qmake позволяет писать навороченные скрипты, средства для этого есть.
Ветвление
В самом простом случае проверка выполнения некоторого условия (в документации именуется scopes) выглядит следующим образом:
1 2 3 4 5 |
scope { # скобка обязательно в этой же строке! ... } |
То, что внутри, отработает только в том случае, если scope истинно. В качестве scope может выступать:
- mkspecs: названия доступных конфигураций qmake по сочетаниям платформа-компилятор, выглядят как
win32-msvc2008
,macx-g++42
илиwince60standard-armv4i-msvc2005
. Могут указываться в виде grep масок (? и *). Подробнее о mkspecs я еще расскажу. - Платформа:
win32
,unix
,macx
. Она косвенно определяется через mkspecs. - Значения из специальной переменной CONFIG (которые являются именами фич, они же features). Об этом я тоже потом подробно расскажу. Для них тоже можно использовать маски, хотя практической пользы от этого немного.
- Встроенные условные функции.
- Пользовательские условные функции.
build_pass
. Об этой затычке я расскажу позже, когда буду ругать режимdebug_and_release
.
Примеры:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
win32-msvc* { # что-то специфическое для Visual C++ 2005-2012 под win32 LIBS += advapi32.lib shell32.lib win32-msvc2012 { # в добавок что-то сугубо для 2012 } } *msvc2010 { # что-то для Visual C++ 2010 под любые платформы # вряд ли практический смысл в этом есть } macx { # что-то OSX специфическое } CONFIG += console console { # что-то только для консольных приложений DEFINES += _CONSOLE_ } exists(version.h) { # встроенная функция проверки # существования файла HEADERS += version.h } |
Если условие нужно только на одну строку, то можно записать scope в сокращенном варианте, через двоеточие. Например:
1 2 3 |
console: DEFINES += _CONSOLE_ |
Вложенные условия тоже можно сокращать:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
win32 { console { DEFINES += _CONSOLE_ } } # можно записать как win32:console { DEFINES += _CONSOLE_ } # и даже как win32:console: DEFINES += _CONSOLE_ |
Фактически, двоеточие работает как логическое И. Логическое ИЛИ тоже присутствует и в более привычном для сишников виде, равно как и отрицание:
1 2 3 4 5 6 7 8 9 |
win32-msvc2005|win32-msvc2008 { # что-то только для Visual C++ 2005 или 2008 } !exists(version.h) { error(version.h is not found) # qmake завершиться с ошибкой } |
Чтобы в одном условии объединить И и ИЛИ, нужны скобки. Их предоставляет конструкция if. Вот пример, взятый из документации:
1 2 3 4 5 6 |
# debug режим на linux или OSX if(linux-g++*|macx-g++*):CONFIG(debug, debug|release) { message("We are on Linux or Mac OS, and we are in debug mode.") } |
Также в синтаксисе ветвления присутствует else, причем даже в виде, напоминающем else-if:
1 2 3 4 5 6 7 8 9 10 11 12 |
win32:xml { # xml под win32 SOURCES += xmlhandler_win.cpp } else:xml { # xml под юниксы SOURCES += xmlhandler.cpp } else { # а без xml низзя error("Unknown configuration") } |
Цикл for
Цикл выполняется для каждого значения в переменной:
1 2 3 4 5 6 7 |
# Цикл выполняется для каждого значения из listVar for(valueVar, listVar) { # скобка обязательно в этой же строке! ... } |
Пример: директории из списка EXTRAS добавляются в SUBDIRS, если они существуют.
1 2 3 4 5 6 7 8 |
EXTRAS = handlers tests docs for(dir, EXTRAS) { exists($$dir) { SUBDIRS += $$dir } } |
Обратите внимание: вторым параметром в цикле for может быть только имя переменной.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
EXTRAS = handlers tests docs # $$unique убирает дубликаты for(dir, $$unique(EXTRAS)) { # бананас exists($$dir) { SUBDIRS += $$dir } } # Это досадное ограничение можно обойти с помощью # встроенной функции list. Она принимает одно значение и # создает переменную с уникальным именем, содержащим это значение. EXTRAS = handlers tests docs # $$unique убирает дубликаты for(dir, $$list($$unique(EXTRAS))) { # работает! exists($$dir) { SUBDIRS += $$dir } } |
Существуют аналоги сишных операторов continue
и break
, это функции next()
и break()
:
1 2 3 4 5 6 7 8 9 10 |
LIST = 1 2 3 for(a, LIST) { equals(a, 1): next(); equals(a, 3): break(); message($$a) } # вывод цикла будет следующим: # Project MESSAGE: 2 |
Поддерживается забавное сокращение: использование цикла for в виде условной функции. Следующий фрагмент выведет на консоль то же, что и предыдущий:
1 2 3 4 |
LIST = 1 2 3 for(a, LIST):equals(a, 2):message($$a) |
Хочу добавить, что для использования самодельных условий создавать «фичи» не обязательно, достаточно написать
CONFIG *= my_condition
my_condition : DEFINES *= BLA_BLA_BLA
и условие отработает.