Техники отладки
Здесь представлены некоторые полезные подсказки, которые помогут вам в отладке вашего программного обеспечения на основе 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 с конфигурацией отладки, он будет линковаться с отладочной версией библиотек и генерировать символы отладки для приложения. Запуск этой программы в 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-6.1/debug.html