Методы отладки
Здесь представлены полезные советы, которые помогут вам при отладке вашего программного обеспечения на базе 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 будет работать так же, как запуск 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 или подобных, скорее всего, связана с этой проблемой.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.15/debug.html