qmake: механизм features для финальной обработки переменных

Помимо описанных ранее механизмов задать начальные значения переменных qmake предоставляет механизм для изменения переменных после обработки собственно .pro файла. Это механизм фич (features), и он является главным средством для расширения и настройки qmake под свои нужды.

Вкратце, работает он следующим образом:

  • имена фич (только маленькие буквы в имени!), которые будут использованы, указываются в специальной переменной CONFIG;
  • файл фичи ищется в наборе специальных каталогов, имя файла есть имя фичи с расширением .prf;
  • файл фичи неявно добавляется в конец .pro файла, подобно include

Рассмотрим подробнее некоторые моменты.

Поиск фич

Цитируя документацию, при поиске фич просматриваются следующие каталоги, в порядке очередности:

  • Из списка каталогов в переменной окружения QMAKEFEATURES (разделяются двоеточием)
  • Из списка каталогов в переменной в qmake QMAKEFEATURES (также разделяются двоеточием)
  • Каталог features в каталоге mkspecs
  • И в кучке других мест в установочном каталоге Qt, которые мне влом перечислять.

Поскольку ковыряться в установочном каталоге Qt есть идея по многим причинам не очень хорошая, из всех этих способов подсунуть фичу qmake годится только переменная окружения или переменная qmake. Первый способ у меня не заработал почему-то, я особо не разбирался почему. Не люблю переменные окружения. А второй способ работает отлично. Я создал файл .qmake.cache в корне дерева своих исходников и в нем прописал значение для переменной:

Взаимоисключающие фичи

Иногда может быть удобно сделать пару взаимоисключающих фич. Самый заметный случай — это стандартные фичи debug и release. Выполнена может быть только одна из них. Можно потребовать от программиста, чтобы он следил за тем, чтобы эти фичи не были указаны одновременно, но авторы qmake решили этот вопрос по-другому, более гибким образом.

Взаимоисключающие фичи можно указывать в переменной CONFIG одновременно и сколько угодно раз; эффект должна иметь последняя указанная. За тем, какая из фич имеет эффект, должны следить сами фичи, вызываются они в любом случае. Фича при вызове должна проверить, активна ли она, и действовать соответственно. Для проверки активности фичи предназначается встроенная функция CONFIG.

Обратной стороной описанного подхода к реализации взаимоисключающих фич является неочевидность проверки взаимоисключающих условий. Интернет пестрит вопросами в духе «я проверяю на debug/release, и как-то ничего не работает, что делать».

Чтобы жизнь была хороша и сияло солнце, нужно делать так:

Порядок выполнения фич не определен

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

Соответственно, нет удобного способа что-то сделать до того, как начнут выполняться фичи, или после того, как все фичи отработают. Если первое ограничение еще можно обойти с помощью include в конце файла, то последнее никак нельзя.

Функция load

Иногда может быть нужно выполнить фичу не в конце файла, а в определенном месте. В самом начале файла, например, вместо include. Для этого можно воспользоваться недокументированной функцией load, которая ведет себя во многом подобно include.

Вместо имени фичи можно указать путь к файлу фичи. Также прошу заметить такой момент: фича может быть выполнена только один раз. Все последующие вызовы load не будут иметь эффекта.

Фичи и Makefile

Все использованные фичи будут перечилены как зависимости в Makefile на вызов qmake. Соответственно, изменение файла фичи приведет к повтороной обработке .pro файла.

Хорошо, что разработчики продумали этот момент, а то нужно было бы при изменении своих самописных фич каждый раз руками перекомпилировать все свои проекты.

Фичи и Qt Creator

Фичи предназначены для «закулисной» работы, результаты их деятельности, по задумке создателей, должны сказываться на проекте неявным образом. Например, если фича реализует вызов IDL компилятора, то результат ее работы (промежуточные файлы, которые добавляются в переменную исходных файлов для дальнейшей обработки) не должен мозолить глаза программисту. По этой причине Qt Creator не отображает в интерфейсе проекта изменения, сделанные фичами.

В целом это правильное решение, но иногда оно мешает. Приходится выкручиваться через include в конце .pro файла.

Пример: MIN_QT_VERSION

Расширим qmake проверкой минимальной версии Qt: если версия меньше, чем указанная программистом в переменной MIN_QT_VERSION, то qmake завершится с ошибкой.

Для реализации этой фичи создадим в одном из специальных мест файл minqtversion.prf следующего содержания:

Пользоваться этой фичей предполагается следующим образом:

Цикл: qmake

  2 comments for “qmake: механизм features для финальной обработки переменных

  1. Lesav
    13.12.2014 at 21:53

    Могу добавить, что механизм с .qmake.cache не работает в Qt 4.8.6
    Есть только один вариант как оповестить qmake где искать features,
    это создать переменную окружения QMAKEFEATURES=D:/sources/sys/qmake/features

    В Qt 5.x.x это работает. Я использовал вот такой код .pro

    #———————————————————————————————————-
    # Создать спецфайл, в котором указать qmake где искать features
    MY_QMAKE_CACHE=$${OUT_PWD}/.qmake.cache
    !exists($$MY_QMAKE_CACHE) : {
    system(echo QMAKEFEATURES=$$PWD/features> $$MY_QMAKE_CACHE)
    error(Please start again qmake)
    }
    unset(MY_QMAKE_CACHE)
    #———————————————————————————————————-

  2. Lesav
    14.12.2014 at 00:00

    Найдено решение, которое работает в Qt4 и Qt5

    #———————————————————————————————————-
    # создать директиву features для qmake
    !exists($${OUT_PWD}/.qmake.cache) : {
    system(echo QMAKEFEATURES=$$PWD/features>$${OUT_PWD}/.qmake.cache)
    error(Please start again qmake)
    }
    !build_pass:message($$basename(_FILE_):$$_LINE_ _QMAKE_CACHE_=$$_QMAKE_CACHE_)

    # Теперь можно использовать конструкцию вида:
    # первый load для Qt5 А этот для Qt4
    !load(_check_toolchane, 1): load(features/_check_toolchane.prf)
    #———————————————————————————————————-

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