При использовании условной конструкции, часть make-файла обрабатывется или игнорируется, в зависимости от значений переменных. Условные конструкции могут сравнивать значение одной переменной со значением другой переменной или значение переменной с постоянной строкой. Условные конструкции управляют тем, что программа make на самом деле "видит" в make-файле, поэтому они не могут быть использованы для управления командами командной оболочки во время их исполнения.
Приведенный ниже пример условной конструкции указывает программе make использовать один набор библиотек, если значением переменной CC является 'gcc', и другой набор библиотек - в противном случае. Его работа основывается на управлении тем, какая из двух командных строк будет использована в правиле в качестве команды. В результате 'CC=gcc' в качестве аргумента программы make изменяет не только используемый компилятор, но также и компонуемые библиотеки.
libs_for_gcc = -lgnu
normal_libs =
foo: $(objects)
ifeq ($(CC),gcc)
p $(CC) -o foo $(objects) $(libs_for_gcc)
else
p $(CC) -o foo $(objects) $(normal_libs)
endif
Эта условная конструкция использует три директивы: одну директиву
ifeq, одну директиву else и одну директиву endif.
Директива ifeq начинает условную конструкцию и определяет условие. Она содержит два аргумента, разделенных запятой и окруженных круглыми скобками. Для обоих частей производится подстановка значения переменной, после чего они сравниваются. Строки make-файла, следующие за директивой ifeq обрабатываются, если два аргумента идентичны, в противном случае они игнорируются.
При использовании директтивы else, следующие за ней строки должны быть обработаны, если предыдущее условие не выполнилось. В вышеприведенном примере это означает, что вторая альтернатива команды компоновки изпользуется всегда, когда не используется первая альтернатива. Наличие директивы else в условной конструкции не является обязательным.
Директива endif заканчивает условную конструкцию. Каждая условная конструкция должна заканчиваться директивой endif. За ней следует безусловный фрагмент make-файла.
Как показывает этот пример, условная конструкция работает на текстуальном уровне: строки условной конструкции обрабатываются или игнорируются, в соответствии с условиями, как часть make-файла. Именно поэтому более крупные синтаксические элементы make-файла, такие как правила, могут пересекаться с началом или концом условной конструкции.
Когда значением переменной CC является 'gcc', из фрагмента make-файла, приведенного в предыдущем примере, получается такой фрагмент:
foo: $(objects)
$(CC) -o foo $(objects) $(libs_for_gcc)
Когда значением переменной CC является что-либо, отличное от 'gcc',
получается такой фрагмент:
foo: $(objects)
$(CC) -o foo $(objects) $(normal_libs)
Эквивалентный результат может быть достигнут еще одним способом, с помощью условной обработки присваивания значения переменной и последующего безусловного ее использования.
libs_for_gcc = -lgnu
normal_libs =
ifeq ($(CC),gcc)
libs=$(libs_for_gcc)
else
libs=$(normal_libs)
endif
foo: $(objects)
$(CC) -o foo $(objects) $(libs)
Синтаксис простой условной конструкции без использования else следующий:
УСЛОВНАЯ-ДИРЕКТИВА
ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ
endif
ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ может представлять собой любые строки
текста, которые будут считаться частью make-файла, если условие истинно.
Если условие ложно, никакой другой фрагмент взамен не используется.
Синтаксис сложной условной конструкции следующий:
УСЛОВНАЯ-ДИРЕКТИВА
ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ
else
ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ
endif
Если условие истинно, используется ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в
противном случае используется ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ.
ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ может занимать любое количество
строк текста.
Синтаксис УСЛОВНОЙ-ДИРЕКТИВЫ в простой и в сложной условной конструкции один и тот же. Есть четыре различных директивы, которые проверяют различные условия. Вот их список:
Подставляет значения для всех ссылок на переменные в переменных arg1 и arg2 и сравнивает их. Если они идентичны, обрабатывается ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае - обрабатывается ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ, если он есть
Часто вы хотите проверить, имеет ли переменная непустое значение. Когда переменная получается в результате сложных вычислений переменных и функций, те подставляемые значения, которые вы рассматриваете как простые, могут, на самом деле, содержать пробельные символы и, таким образом, не считаться пустыми. Однако, вы можете использовать функцию strip (смотрите раздел 8.2 [Функции для работы с текстом]), чтобы избежать интерпретации пробелов как непустых значений. Например, в результате вычисления данной условной директивы:
ifeq ($(strip $(foo)),)
ФРАГМЕНТ-ДЛЯ-ПУСТОГО-ЗНАЧЕНИЯ
endif
будет обрабатываться ФРАГМЕНТ-ДЛЯ-ПУСТОГО-ЗНАЧЕНИЯ, даже если
результат вычисления $(foo) содержит пробельные символы.
Подставляет значения для всех ссылок на переменные в переменных arg1 и arg2 и сравнивает их. Если они различаются, обрабатывается ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае - обрабатывается ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ, если он есть
Если переменная с указанным именем имеет непустое значение, обрабатывается ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае - обрабатывается ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ, если он есть. Переменные, которые нигде не были определены, имеют пустое значение.
Обратите внимание, что директива ifdef проверяет, имеет ли переменная значение. Она не вычисляет переменную, чтобы увидеть, является ли ее значение непустым. Следовательно, проверка с использование директивы ifdef определит выполнение условия для всех переменных, чьи определения имеют вид, отличный от foo =. Чтобы проверить на пустое значение, используйте директиву ifeq ($(foo),). Например, следующий фрагмент make-файла:
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif
устанавливает 'yes' в качестве значения переменной frobozz, в то
время как такой фрагмент:
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif
устанавливает 'no' в качестве значения переменной frobozz.
Если переменная с указанным именем имеет пустое значение, обрабатывается ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае - обрабатывается ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ, если он есть.
В начале строки с условной директивой разрешается добавлять пробелы, но символ табуляции не разрешен. (Если строка начинается с символа табуляции, она будет рассматриваться как команда для правила.) Кроме этого, дополнительные пробелы или символы табуляции без последствий могут вставляться в любом месте, только не внутри имени директивы и не внутри аргумента. В конце строки может появиться символ начала комментария '#'.
Двумя другими директивами, играющими роль в условной конструкции являются директивы else и endif. Каждая из этих директив записывается в одно слово, без аргументов. В начале строки допускаются и игнорируются добаленные пробелы, а вконце строки - добавленые пробелы и символы табуляции. В конце строки может появиться комментарий, начинающийся с символа '#'.
Условные конструкции воздействуют на то, какие строки make-файла использует программа make. Если условие истинно, make считывает строки ФРАГМЕНТА-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ как часть make-файла, если же условие ложно, make полностью игнорирует эти строки. Из этого следует, что синтаксические единицы make-файла, такие как правила, могут быть безопасно разбиты на части началом или окончанием условной конструкции.
make обрабатывает условные конструкции в момент чтения make-файла. Слкдовательно, вы не можете использовать автоматические переменные в условиях условных конструкций, поскольку они не определены до момента выполнения команд (смотрите раздел 10.5.3 [Автоматические переменные]).
Чтобы избежать ужасного беспорядка, не разрешается начинать условную конструкцию в одном make-файле и заканчивать ее в другом. Однако, внутри условной конструкции вы можете написать директиву include, гарантирующую, что вы не пытаетесь закончить условную конструкцию во включаемом файле.
Вы можете написать условную конструкцию, которая проверяет опцию командной строки программы make, такую как '-t', используя переменную MAKEFLAGS вместе с функцией findstring (смотрите раздел 8.2 [Функции подстановки и анализа строк]). Это полезно в тех случаях, когда программы touch недостаточно для того, чтобы файл выглядел обновленным.
Функция findstring определяет, появляется ли одна строка внутри другой в качестве подстроки. Если вы хотите проверить опцию '-t', используйте 't' в качестве первой строки и значение переменной MAKEFLAGS в качестве второй.
Здесь приведен пример того, как ввести соглашение об использовании 'ranlib -t' при окончании отметки архивного файла как обновленного:
archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
+touch archive.a
+ranlib -t archive.a
else
ranlib archive.a
endif
Префикс '+' помечает соответствующие командные строки как "рекурсивные"
для того, чтобы они были исполнены, несмотря на использование опции -t.
Смотрите раздел 5.6 [Рекурсивное использование make].