Методы отладки
Здесь представлены некоторые полезные советы, которые помогут вам отладить ваше программное обеспечение на основе Qt.
Настройка Qt для отладки
При настройке Qt для установки, можно убедиться, что он скомпилирован с включением символов отладки, что облегчит отслеживание ошибок в приложениях и библиотеках. Однако на некоторых платформах компиляция Qt в отладочном режиме приведет к увеличению размера приложений.
Отладка в macOS и Xcode
Отладка с/без фреймворков
Основные сведения об отладочных библиотеках и фреймворках можно найти на сайте developer.apple.com в: Технической заметке Apple TN2124.
При компиляции Qt фреймворки создаются по умолчанию, и внутри фреймворка вы найдете как релизную, так и отладочную версии (например, QtCore и QtCore_debug). Если вы передаете флаг -no-framework при компиляции Qt, для каждой библиотеки Qt будут созданы две dylib (например, libQtCore.4.dylib и libQtCore_debug.4.dylib).
То, что происходит при линковке, зависит от того, используете ли вы фреймворки или нет. У нас нет убедительных причин рекомендовать один вариант вместо другого.
С фреймворками:
Поскольку релизные и отладочные библиотеки находятся внутри фреймворка, приложение просто подключается к фреймворку. Затем, при запуске в отладчике, вы получите либо релизную, либо отладочную версию в зависимости от того, установили ли вы DYLD_IMAGE_SUFFIX. Если вы не устанавливаете его, вы по умолчанию получаете релизную версию (т.е. без _debug). Если вы установите DYLD_IMAGE_SUFFIX=_debug, вы получите отладочную версию.
Без фреймворков:
Если вы укажете qmake сгенерировать Makefile с конфигурацией отладки, он будет ссылаться на _debug-версию библиотек и сгенерирует символы отладки для приложения. Запуск этой программы в GDB будет работать так же, как и запуск 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— сообщение, записывает предупреждение: "Ошибка проверки в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.13/debug.html