qmake: переменные для настройки сборки

DEFINES

Список макросов. Передается не только компилятору С/C++, но и компилятору ресурсов Windows (который обрабатывает .rc файл). Можно задать макросы со значениями:

Самое печальное с DEFINES — это то, что их изменение не вызывает перекомпиляции файлов, в которых они используются. Так что в таком случае нужно обязательно делать полный ребилд.

INCLUDEPATH

Список каталогов для включаемых (заголовочных) файлов.

Каталог проекта (где расположен .pro файл) по умолчанию включается в INCLUDEPATH. Если вдруг нужно, то эту фичу можно отключить с помощью CONFIG += no_include_pwd.

В Qt 5 заголовочные файлы, найденные в INCLUDEPATH, создают зависимости для файлов, в которые они включаются, а в Qt 4 — нет. Читайте ниже сагу о DEPENDPATH.

DEPENDPATH

Документация: «Эта переменная содержит список всех директорий для поиска в них зависимостей. Она используется при прохождении по включенным (include) файлам». Хрен поймешь, что это такое и нафик оно нужно. Как я выяснил, это еще и не совсем верная и изрядно устаревшая информация.

Задумка этой переменной в следующем: быть подмножеством INCLUDEPATH. Только включенные файлы из каталогов этого подмножества создают зависимости (т.е. прописываются как предпосылки к файлам, их включающим прямо или косвенно). Таким образом можно было избежать включения в список зависимостей стабильных файлов (заголовочные файлы стандартной библиотеки C++ и Qt, к примеру). Такая оптимизация значительно сокращает работу для make, т.к. гораздо меньше файлов нужно проверять на «свежесть».

Но практика показала, что от такой оптимизации больше вреда, чем пользы. Люди должны были руками за этой переменной следить, чтобы не напороться на трудноотслеживаемые глюки. Учитывая, что любую документацию никто не читает, а в доке по qmake к тому же ничего толком и не написано, то именно после такого столкновения с глюками люди об этой переменной и узнавали. Полнейшее безобразие. Так что, в конце концов, разработчики решили убрать этот механизм под ковер. В Qt 4 этого сделать было нельзя, не поломав старый код, поэтому ограничились введением способа сделать так, чтобы DEPENDPATH всегда был равен INCLUDEPATH. Делается это с помощью CONFIG += depend_includepath. В Qt 5 эта настройка включена по умолчанию. Мазохисты могут ее отключить (CONFIG -= depend_includepath), но я не советую. Жизнь слишком коротка, чтобы тратить ее на всякие глупости. Из глупостей: до 5 версии Qt DEPENDPATH по неведомым причинам включался в VPATH, что приводило к хитрым глюкам.

Резюме: если включена опция depend_includepath, то все включенные файлы будут создавать зависимости, причем рекурсивно. Таким образом, автоматически обеспечивается, что изменение любого заголовочного файла, включенного откуда угодно каким угодно путем, приведет к правильной перекомпиляции при вызове make. Аминь.

LIBS

Список статических библиотек, которые будут прилинкованы к результирующему файлу.

Включение библиотеки в этот список не сделает результирующий файл от нее зависимым, т.е. изменение библиотеки само по себе не приведет к перелинковке при вызове make. Для того, чтобы библиотека стала зависимостью, добавьте путь к ней в переменную PRE_TARGETDEPS или POST_TARGETDEPS. О них я еще расскажу подробнее в одном из следующих постов.

Библиотеки можно задать с помощью двух различных синтаксисов: как принято в Unix (флаги -L для путей и -l для имен библиотек) и как принято в Windows (просто путь к библиотеке без дополнительных извращений).

Большое неудобство синтаксиса Windows заключается в том, что нужно знать расширение в имени файла библиотеки, а оно зависит от тулчейна (в MSVC это .lib, в MinGW .a; в MinGW еще и префикс lib добавляется к имени библиотеки). Но, тем не менее, под Windows надежнее использовать виндовый синтаксис, поскольку юниксовый преобразуется в виндовый для виндовых линкеров, и это преобразование происходит не без нюансов:

  • На момент вызова qmake библиотека должна существовать, иначе qmake не сможет определить, в каком каталоге из указанных она находится, а значит, не сможет выполнить преобразование.
  • В рамках вышеуказанного примера: если в указанных в LIBS каталогах будут найдены библиотеки, скажем, mylib.lib и mylib2.lib, то вместо mylib в проект будет прилинкована mylib2! Число в конце имени библиотеки интерпретируется как ее версия, и выбирается библиотека с максимальной версией… вот нахрена такое счастье на Windows-то? Проблему можно обойти, добавив расширение явно, но тогда теряется вся идея кроссплатформенности синтаксиса.

Еще предостережение: в случае использования синтаксиcа Windows, т.е. указания пути к файлу библиотеки, лучше используйте полные пути, не относительные. Это связано с тем, что относительный путь будет относительным относительно каталога, в котором запущен линкер, а не каталога .pro файла, и теоретически он может быть совсем другим. Для преобразования относительных путей в абсолютные можно использовать переменную PWD, о которой я еще расскажу.

В результате всего перечисленного, добавить статическую библиотеку в проект на qmake есть задача не самая тривиальная, если не сказать резче. В одном из следующих постов я расскажу, как лично я выхожу из положения.

TEMPLATE

Значение переменной задает тип проекта:

  • app: исполняемый файл. Значение по умолчанию.
  • lib: статическая или динамическая библиотека.
  • subdirs: специальный вариант .pro файла для разбиения проекта на несколько отдельных частей (обычно в подкаталогах), каждая со своим отдельным .pro файлом. Подробности — в одном из дальнейших постов.

В случае библиотеки ее тип (статическая или динамическая) задается CONFIG (CONFIG += staticlib или CONFIG += dll). Также есть специфический конфиг для плагинов (CONFIG += plugin), который влючает в себя dll.

Для приложений под Windows можно указать, какое оно будет: GUI (CONFIG += windows, по умолчанию) или консольное (CONFIG += console). Эти два флага работают как переключатели, поэтому если нужно проверять на тип приложения, то нужно использовать функцию CONFIG:

TARGET

Имя проекта. По умолчанию равно имени .pro файла (без расширения .pro). Имя результирующего файла получается на основании значения переменных TARGET, TEMPLATE, VERSION, некоторых других переменных, а также платформы и тулчейна, и может обрасти разными префиксами и суффиксами. Поскольку генерация имени происходит в фичах, надежного способа узнать это имя в .pro файле нет. Хотя в Makefile можно; подробности позже.

CONFIG

Некоторые настройки компилятора задаются в CONFIG, кроссплатформенным и высокоуровневым образом.

QT

Переменная для указания модулей Qt, которые подключаются к проекту. Список всех доступных модулей можно посмотреть в подкаталоге modules каталога mkspecs. Каждый файл в нем описывает свой модуль, и в нем без труда обнаруживается имя модуля (например, QtQmlDevTools) и имя, которое нужно добавить в переменную Qt (qmldevtools) для его подключения в проект.

По умолчанию добавляются два модуля, core и gui. Если пишется консольное Qt приложение, то нужно выключить GUI. А если выключить все модули, то проект не будет использовать Qt вообще. Так что с помощью Qt Creator + qmake можно разрабатывать C/C++ программы, Qt не использующие.

В Qt 5 из модуля gui виджеты были вынесены в отдельный модуль widgets. Теперь, если интерфейс реализован сугубо на QtQuick, то тащить за собой виджеты не нужно. Но, как следствие, если программа использует виджеты, то теперь их надо явно включать. Для совместимости с Qt 4 можно сделать это следующим образом:

Кстати, о переменных версии Qt. Они существуют как раз для такого рода задач, так что полезно о них знать.

VERSION

Информация о версии в Explorer

Информация о версии в Explorer

Версия результирующего файла.

Задумка была хорошая, но реализация капитально подкачала. Настолько, что я не могу рекомендовать этой переменной пользоваться. Проблема в том, что эта версия лезет куда только можно, и совершенно ненастраиваемым образом. И при этом — глюкавит.

Самая приятная фича VERSION заключается в том, что под Windows указание версии приводит к генерации .rc файла с информацией о версии. Причем можно указать дополнительную информацию, не только номер:

Результат на картинке. В чем подвох? В том, что все это не работает, если указано значение переменной RC_FILE, а создание своего .rc (и указание его в этой переменной) было единственным способом указать иконку для приложения Windows. В версии Qt 5.0.2 добавили переменную RC_ICONS, которая содержит список иконок, добавляемых в этот же генеримый файл. Так что до совсем недавнего времени эта фича представляла собой сугубо академический интерес. В последней версии вроде как можно пользоваться…. но VERSION не дает.

Не столь приятная фича — старший номер версии стремится прибавиться к имени результирующего файла. Если вы билдите dll и определили, например, VERSION = 2.1.3, то результирующий файл будет не mylib.dll, а mylib2.dll. Может, кому-то это и полезно. Но явно не мне. Можно полечить с помощью TARGET_EXT = .dll, но чем лечить — лучше не болеть, имхо.

Совсем неприятная фича, которую я не знаю как лечить, проявляет себя под MSVC. Если определена переменная VERSION, то для линкера будет сгенерирован параметр /VERSION. Проблема в том, что формат для параметра имеет вид MAJOR.MINOR, где MINOR < 65K. qmake в припадке мудрости MINOR получает конкатенацией всего, что идет после первой точки в значении VERSION. Если, например, прописать VERSION = 1.71.238, то поимеем следующую радость:

После этого известия я поставил крест на переменной VERSION.

RC_INCLUDEPATH

В тему о ресурсах. Под Windows компилятор виндовых ресурсов запускается для файла .rc, если он есть у проекта (указан в переменной RC_FILE или сгенерирован автоматически). При этом компилятору передаются макросы проекта (DEFINES) и пути из RC_INCLUDEPATH. Эти пути служат для нахождения включенных файлов, а также для файлов, включаемых в ресурс.

Низкоуровневые переменные

Если припечет нужда, то можно полезть руками ковырять настройки конкретных утилит тулчейна. Желающие могут покопаться с переменными с именами, начинающимися на QMAKE_*.

Наибольший интерес представляют собой переменные с опциями для компиляторов C и C++ и линкера. Например, QMAKE_CXXFLAGS — это базовые опции компилятора C++, а QMAKE_CXXFLAGS_DEBUG — это опции, которые будут добавлены к ним, если выбран debug; аналогично есть переменная QMAKE_CXXFLAGS_RELEASE и переменные для других выбров, например QMAKE_CXXFLAGS_WARN_OFF и QMAKE_CXXFLAGS_WARN_ON. Для линкера существует устроенный по аналогичному принципу набор переменных QMAKE_LFLAGS*.

Игры с этими переменными позволяют реализовать вещи, которые другими путями в qmake сделать нельзя. Пара примеров:

Цикл: qmake

  6 comments for “qmake: переменные для настройки сборки

  1. 17.12.2013 at 02:48

    Спасибо, очень полезно, особенно про VERSION

  2. Сергей Никонов
    09.04.2014 at 17:27

    В разделе про переменную INCLUDEPATH небольшая опечатка: вместо
    CONFIG -= no_include_pwd
    нужно писать
    CONFIG += no_include_pwd

  3. Alex
    03.06.2015 at 15:03

    # В Qt 5 поддержка C++ 11 включается без лишних телодвижений
    COMFIG += c++11

    исправить бы.

  4. Alex
    03.06.2015 at 15:15

    ==begin
    А если выключить все модули, то проект не будет использовать Qt вообще. Так что с помощью Qt Creator + qmake можно разрабатывать C/C++ программы, Qt не использующие.
    # консольное приложение
    QT -= gui
    # Приложение без Qt
    QT =
    ==end

    Посмотрел, что делает QtCreator (3.4.0) Qt(5.4.1) когда создаёт консольное приложение:
    TEMPLATE = app
    CONFIG += console // Я так понял это это аналогично QT -= gui
    CONFIG += c++11
    CONFIG -= app_bundle
    CONFIG -= qt // Здесь явно отключается qt может «QT =» недостаточно для отключения

    SOURCES += main.cpp

    Если я не прав, в замечаниях, то пожалуйста поправьте.

    • mgsxx
      03.06.2015 at 15:48

      CONFIG += console ни в коем случае не аналогичен QT -= gui. Ничто не мешает GUI приложению иметь консоль. По крайней мере, теоретически. Вообще, переменные QT и CONFIG — весьма разные вещи.

      На счет CONFIG -= qt ничего не скажу. В свое время не встречал. За деталями происходящего нужно лезть в исходник фичи qt и смотреть, какие там переменные и на что меняются.

Добавить комментарий