Методы отладки
Здесь представлены некоторые полезные советы, которые помогут вам при отладке программного обеспечения на основе Qt.
Настройка Qt для отладки
При настройке Qt для установки можно убедиться, что он скомпилирован с включенными отладочными символами, что может облегчить отслеживание ошибок в приложениях и библиотеках. Однако на некоторых платформах компиляция Qt в отладочном режиме приведет к увеличению размера приложений.
Отладка в macOS и Xcode
Отладка с/без фреймворков
Основные сведения об отладочных библиотеках и фреймворках можно найти на developer.apple.com в: Технической заметке Apple TN2124.
При компиляции Qt фреймворки создаются по умолчанию, и внутри фреймворка вы найдете как релизную, так и отладочную версии (например, QtCore и QtCore_debug). Если вы передадите флаг -no-framework при компиляции Qt, для каждой библиотеки Qt будут скомпилированы две библиотеки (например, libQtCore.4.dylib и libQtCore_debug.4.dylib).
То, что произойдет при линковке, зависит от того, используете ли вы фреймворки или нет. Мы не видим убедительной причины рекомендовать один вариант вместо другого.
С фреймворками:
Поскольку релизные и отладочные библиотеки находятся внутри фреймворка, приложение просто подключается к фреймворку. Затем при запуске в отладчике вы получите либо релизную, либо отладочную версию в зависимости от того, установили ли вы DYLD_IMAGE_SUFFIX. Если вы не установите его, по умолчанию используется релизная версия (т.е. без _debug). Если вы установите DYLD_IMAGE_SUFFIX=_debug, вы получите отладочную версию.
Без фреймворков:
Когда вы укажете qmake сгенерировать Makefile с отладочной конфигурацией, он будет подключаться к версии библиотек с _debug и генерировать отладочные символы для приложения. Запуск этой программы в GDB затем будет работать так же, как и на других платформах, и вы сможете отслеживать внутри Qt.
Командные строки, распознаваемые Qt
При запуске приложения Qt вы можете указать несколько командных строк, которые могут помочь при отладке. Они распознаются QApplication.
| Вариант | Описание |
|---|---|
-nograb |
Приложение не должно никогда захватывать мышь или клавиатуру. Этот параметр установлен по умолчанию, когда программа выполняется в отладчике gdb под Linux. |
-dograb |
Игнорировать все неявные или явные -nograb. -dograb имеет приоритет над -nograb, даже если -nograb указан последним в командной строке. |
Переменные среды, распознаваемые Qt
При запуске приложение Qt распознает множество переменных среды, некоторые из которых могут быть полезны при отладке:
| Переменная | Описание |
|---|---|
QT_DEBUG_PLUGINS |
Установите значение, отличное от нуля, чтобы Qt печатал диагностическую информацию о каждом (C++) плагине, который он пытается загрузить. |
QML_IMPORT_TRACE |
Установите значение, отличное от нуля, чтобы QML печатал диагностическую информацию из механизма загрузки импорта. |
QT_HASH_SEED |
Установите целое значение, чтобы отключить использование QHash и QSet с новой случайной сортировкой для каждого запуска приложения, что в некоторых случаях может затруднить тестирование и отладку. |
Предупреждения и сообщения об ошибках
Qt включает глобальные макросы для вывода предупреждений и отладочных сообщений. Вы можете использовать их для следующих целей:
- qDebug() используется для вывода пользовательского отладочного вывода.
- qInfo() используется для информационных сообщений.
- qWarning() используется для вывода предупреждений и исправимых ошибок в вашем приложении.
- qCritical() используется для вывода критических сообщений об ошибках и сообщений об ошибках системы.
- qFatal() используется для вывода сообщений о фатальных ошибках незадолго до выхода.
Если вы включите заголовочный файл <QtDebug>, макрос qDebug() также может быть использован как поток вывода. Например:
qDebug() << "Widget" << widget << "at position" << widget->pos();
Реализация Qt этих макросов выводит в поток stderr под Unix/X11 и macOS. В Windows, если это консольное приложение, текст отправляется в консоль; в противном случае он отправляется в отладчик.
По умолчанию печатается только сообщение. Вы можете включить дополнительную информацию, установив переменную среды QT_MESSAGE_PATTERN. Например:
QT_MESSAGE_PATTERN="[%{type}] %{appname} (%{file}:%{line}) - %{message}" Формат документирован в qSetMessagePattern(). Вы также можете установить свой собственный обработчик сообщений с помощью qInstallMessageHandler().
Если переменная среды QT_FATAL_WARNINGS установлена, qWarning() завершается после вывода сообщения о предупреждении. Это упрощает получение стека вызовов в отладчике.
qDebug(), qInfo() и qWarning() являются средствами отладки. Они могут быть исключены из компиляции, если во время компиляции определены QT_NO_DEBUG_OUTPUT, QT_NO_INFO_OUTPUT, или QT_NO_WARNING_OUTPUT.
Функции отладки QObject::dumpObjectTree() и QObject::dumpObjectInfo() часто полезны, когда приложение выглядит или ведет себя странно. Более полезны, если вы используете имена объектов, но часто полезны даже без имен.
Предоставление поддержки оператора потока qDebug()
Вы можете реализовать оператор потока, используемый qDebug(), для предоставления поддержки отладки для ваших классов. Класс, реализующий поток, QDebug. Используйте QDebugStateSaver для временного сохранения параметров форматирования потока. Используйте nospace() и манипуляторы QTextStream для дальнейшей настройки форматирования.
Вот пример класса, представляющего 2D координаты.
QDebug operator<<(QDebug dbg, const Coordinate &c)
{
QDebugStateSaver saver(dbg);
dbg.nospace() << "(" << c.x() << ", " << c.y() << ")";
return dbg;
} Интеграция пользовательских типов с метаобъектной системой Qt более подробно описана в документе Создание пользовательских типов Qt.
Макросы отладки
Заголовочный файл <QtGlobal> содержит некоторые макросы отладки и #define.
Три важных макроса:
-
Q_ASSERT(cond), где
cond— это булево выражение, выводит предупреждение "ASSERT: 'cond' в файле xyz.cpp, строка 234" и завершается, еслиcondложно. -
Q_ASSERT_X(cond, где, что), где
cond— это булево выражение,where— местоположение, аwhat— сообщение, выводит предупреждение: "Ошибка ASSERT вwhere: 'what', файл xyz.cpp, строка 234" и завершается, еслиcondложно. -
Q_CHECK_PTR(ptr), где
ptr— указатель. Выводит предупреждение "В файле xyz.cpp, строка 234: Нет памяти" и завершается, еслиptrравно 0.
Эти макросы полезны для обнаружения ошибок программы, например, так:
char *alloc(int size)
{
Q_ASSERT(size > 0);
char *ptr = new char[size];
Q_CHECK_PTR(ptr);
return ptr;
} Q_ASSERT(), Q_ASSERT_X() и Q_CHECK_PTR() не расширяются ни до чего, если QT_NO_DEBUG определено во время компиляции. По этой причине аргументы этих макросов не должны иметь побочных эффектов. Вот неправильное использование Q_CHECK_PTR():
char *alloc(int size)
{
char *ptr;
Q_CHECK_PTR(ptr = new char[size]); // WRONG
return ptr;
} Если этот код скомпилирован с QT_NO_DEBUG определённым, код в выражении Q_CHECK_PTR() не выполняется, а alloc возвращает неинициализированный указатель.
Библиотека Qt содержит сотни внутренних проверок, которые будут выводить сообщения о предупреждениях, когда будет обнаружена ошибка программирования. Поэтому мы рекомендуем использовать отладочную версию Qt при разработке программного обеспечения на основе Qt.
Распространённые ошибки
Существует одна ошибка, которая настолько распространена, что заслуживает упоминания здесь: если вы включаете макрос Q_OBJECT в объявлении класса и запускаете компилятор метаобъектов (moc), но забываете подключить сгенерированный moc код объекта в свой исполняемый файл, вы получите очень запутанные сообщения об ошибках. Любая ошибка линковки, жалующаяся на недостаток vtbl, _vtbl, __vtbl или аналогичные, скорее всего, является результатом этой проблемы.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.9/debug.html