Методы отладки
Здесь представлены некоторые полезные подсказки, которые помогут вам в отладке вашего программного обеспечения на базе 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 для дальнейшей настройки форматирования.
Вот пример класса, представляющего двумерную координату.
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.0/debug.html