next up previous contents index
Next: Шаблонные правила Up: Средство управления проектом make Previous: Алгоритм работы make   Contents   Index

Переменные в make-файлах

GNU Make поддерживает два способа задания переменных, которые несколько различаются по смыслу. Первый способ - традиционный, с помощью оператора '=':

compile_flags = -O3 -funroll-loops -fomit-frame-pointer

Такой способ поддерживают все варианты утилиты make. Его можно сравнить, например, с заданием макроса в языке Си.

#define compile_flags "-O3 -funroll-loops -fomit-frame-pointer"

Значение переменной, заданной с помощью оператора '=', будет вычислено в момент ее использования. Например, при обработке make-файла: var1 = one var2 = $(var1) two var1 = three all: @echo $(var2)

на экран будет выдана строка ``three two''. Значение переменной var2 будет вычислено непосредственно в момент выполнения команды echo, и будет представлять собой текущее значение переменной var1, к которому добавлена строка ``two''. Как следствие - одна и та же переменная не может одновременно фигурировать в левой и правой части выражения, так как это может привести к бесконечной рекурсии. GNU Make распознает подобные ситуации и прерывает обработку make-файла. Следующий пример вызовет ошибку:

compile_flags = -pipe $(compile_flags)

GNU Make поддерживает также и второй, новый способ задания переменной - с помощью оператора ':=':

compile_flags := -O3 -funroll-loops -fomit-frame-pointer

В этом случае переменная работает подобно ``обычным'' текстовым переменным в каком-нибудь из языков программирования. Вот приблизительный аналог этого выражения на языке C++:

string compile_flags = "-O3 -funroll-loops -fomit-frame-pointer";

Значение переменной вычисляется в момент обработки оператора присваивания. Если, например, записать var1 := one var2 := $(var1) two var1 := three all: @echo $(var2)

то при обработке такого make-файла на экран будет выдана строка ``one two''.

Переменная может ``менять'' свое поведение в зависимости от того, какой из операторов присваивания был к ней применен последним. Одна и та же переменная на протяжении своей жизни вполне может вести себя и как ``макрос'' и как ``текстовая переменная''.

Зависимости цели edit в примерах выше являлись аргументами для команд компоновки. Можно избежать их повторения, определив переменную, которая будет содержать имена всех объектных файлов. # Makefile for simple editor

OBJS = edit.o kbd.o commands.o display.o $ \backslash$
insert.o search.o files.o utils.o
edit : $(OBJS)
gcc -g -o edit $(OBJS)
Строка, начинающаяся с ``OBJS ='' определяет переменную OBJS, на которую можно в дальнейшем сослаться через ``$(OBJS)'' или ``$OBJS''. Эти более поздние ссылки приводят к тому, что обозначение OBJ будет дословно заменяться, прежде чем правило будет обработано. Иногда неудобно, что и gmake и shell используют `$' как префикс для ссылок на переменные; gmake определяет `$$', такое же, как `$', позволяя Вам передавать `$' в shell, если это необходимо.

Иногда Вам может понадобиться величина, выглядящая как обычная переменная, но с некоторыми уточнениями. Например, задавая переменную со списком имен всех исходных файлов, Вы можете захотеть задать имена всех получающихся объектных файлов. Можно переопределить OBJS следующим образом. SRCS = edit.cc kbd.cc commands.cc display.cc $ \backslash$
insert.cc search.cc files.cc utils.cc
OBJS = $(SRCS:.cc=.o)
Суффикс уточнения `:.cc=.o' определяет необходимые уточнения. Теперь у нас есть переменные для имен всех исходных и объектных файлов, при этом не пришлось повторять в определениях множество имен.

Переменные могут быть упомянуты и в командной строке при вызове gmake. Например, если make-файл содержит edit.o: edit.cc
gcc $(DEBUG) -c -Wall edit.cc
то команда типа gmake DEBUG=-g ... приведет к использованию ключа -g (добавить символическую информацию отладчика) при компиляции, а отсутствие DEBUG=-g исключит использование этого ключа. Определения переменных в командной строке имеют преимущество перед определениями внутри make-файла, что позволяет задать в make-файле значения по умолчанию.

Переменные, не установленные любым из перечисленных методов, могут быть установлены как переменные среды. Поэтому, последовательность команд

setenv DEBUG -g gmake ...

для последнего примера также приведет к использованию ключа -g во время компиляции.



Alex Otwagin 2002-12-16