В данной главе рассказано, как можно упростить процедуру повторной компиляции и компоновки с помощью команды make. Эта команда поможет вам сэкономить время при работе со своими проектами.
Программа make особенно полезна при создании программ среднего размера. Данная программа не предназначена для решения задач, связанных с поддержкой нескольких версий исходного кода и с описанием больших программ (см. описание команды sccs).
Команда make применяется для обслуживания набора программ, которые обычно относятся к одному проекту. Она предназначена для создания обновленных версий программ.
В любом проекте программы обычно компонуются из объектных файлов и библиотек. Следовательно, после изменения исходного файла вам необходимо заново перекомпилировать часть исходных модулей и заново перекомпоновать программу.
Команда make позволяет упростить процедуру повторной компиляции и компоновки программ. Связи между файлами достаточно определить только один раз. После этого команда make будет автоматически выполнять обновление.
С помощью команды make можно выполнить следующие задачи:
Для работы команде make необходимы файл описания, список имен файлов, а также правила, по которым программа make должна создавать стандартные типы файлов, и временные метки всех системных файлов.
Для создания целевого файла, содержащего весь исполняемый код, программа make использует информацию из пользовательского файла описания (целевого файла). На основе этой информации программа make определяет способ компоновки целевого файла, список файлов для компоновки и их связь с другими файлами. Файл описания содержит следующую информацию:
Программа make проверяет временные метки родительских файлов и на основе этой информации составляет список файлов, которые необходимо заново создать для получения обновленной копии целевого файла. Если какой-либо родительский файл был изменен уже после создания целевого файла, то команда make заново создаст все файлы, связанные с родительским, в том числе целевой файл.
Если файлу описания присвоено имя makefile или Makefile, и этот файл расположен в целевом каталоге, то для обновления целевого файла и его родительских файлов введите следующую команду:
make
Файлы будут обновлены независимо от того, сколько из них было изменено с момента последнего создания целевого файла программой make. В большинстве случаев файл описания имеет простую структуру, и его не требуется часто обновлять.
Если вы собираетесь хранить в одном каталоге несколько файлов описаний, присвойте им разные имена. Команда
make -f файл-описания
присваивает файлу описания имя, указанное в параметре файл-описания.
Ниже приведен общий формат записи:
целевой-файл-1 [целевой-файл-2..]:[:] [родительский-файл-1..][; команда]... [(символ-табуляции) команды]
Элементы в квадратных скобках - необязательные. Имена целевых и родительских файлов - это символьные строки, которые могут содержать буквы, цифры, точки и символы косой черты. Команда make позволяет указывать символы подстановки, такие как * (звездочка) и ? (знак вопроса). Строка файла описания, содержащая имя целевого файла, называется строкой взаимосвязей. Строки, содержащие команды, должны начинаться с символа табуляции.
Примечание: в команде make символ $ (знак доллара) применяется для обозначения макроопределения. Не используйте этот символ в именах целевых или родительских файлов и в командах файла описания, если вы не применяете макроопределение make.
Комментарии в файле описания должны начинаться со знака фунта (#). Программа make игнорирует символ # и все следующие за ним символы. Кроме того, программа make игнорирует пустые строки.
Длина всех строк в файле описания, за исключением строк комментариев, может превышать ширину строки устройства ввода. Для переноса строки укажите в позиции переноса символ \ (обратная косая черта).
Команда - это любая строка символов, кроме строк, начинающихся с символа # (знака фунта) или с символа новой строки. Символ # можно использовать в команде только в кавычках. Команды могут задаваться либо в строке взаимосвязей после двоеточия, либо в строках, начинающихся с символа табуляции, которые следуют непосредственно за строкой взаимосвязей.
В файле описания для целевого файла может быть задана одна последовательность команд, либо несколько последовательностей для различных наборов зависимостей. Оба способа задания команд одновременно использовать нельзя.
Если для создания целевого файла будет применяться одна последовательность команд, укажите одно двоеточие после имени целевого файла в строке взаимосвязей. Например:
test: список-взаимосвязей-1... список-команд... . . . test: список-взаимосвязей-2...
задается имя целевого файла (test), набор родительских файлов и набор команд для создания файла. Для целевого файла test может быть задан и другой список взаимосвязей.
Однако для этого имени нельзя будет указать другой список команд. Если будет изменен один из файлов, от которых зависит файл test, команда make создаст целевой файл test, выполнив команды из заданного списка.
Для задания нескольких последовательностей команд для создания одного и того же файла определите несколько списков взаимосвязей. В каждой строке взаимосвязей должно быть задано имя целевого файла, после которого должны быть указаны два двоеточия (::), список взаимосвязей и список команд, которые нужно выполнить команде make при изменении каких-либо файлов в списке взаимосвязей. Например:
test:: список-взаимосвязей-1... список-команд-1... test:: список-взаимосвязей-2... список-команд-2...
Этот файл определяет два способа создания целевого файла с именем test. При изменении файлов из списка-взаимосвязей-1 команда make выполняет команды из списка-команд-1. При изменении файлов из списка-взаимосвязей-2 команда make выполняет команды из списка-команд-2. Во избежание конфликтов родительский файл не должен присутствовать ни в одном из списков взаимосвязей.
Примечание: команда make передает команды из каждой командной строки в новую оболочку. Будьте внимательны при использовании команд, которые зависят от процесса оболочки, например, команды cd и команд оболочки. Программа make не сохранит результат выполнения этих команд до выполнения команды, указанной в следующей строке файла описания.
Для объединения двух строк файла в одну командную строку, укажите в конце первой строки файла символ \ (обратную косую черту). Команда make объединит две строки в одну и передаст их в одну и ту же оболочку.
Для создания вложенного вызова команды make в файле описания, укажите в командной строке этого файла макроопределение $(MAKE).
Если указан флаг -n и было найдено макроопределение $(MAKE), то новая копия команды make не будет выполнять никаких команд, за исключением другой команды макроопределения $(MAKE). Эту возможность можно использовать для тестирования набора файлов описания программы. Введите команду:
make -n
Эта команда make не выполняет никаких операций с программой. Однако она должна записать в стандартный вывод сведения обо всех этапах компиляции программы, в том числе вывод низкоуровневых вызовов команды make.
Существует несколько способов подавления вывода команды make:
Если какая-либо программа передаст ненулевой код возврата, то программа make обычно завершает работу. Некоторые программы возвращают код возврата, который не сигнализирует об ошибке.
Для того чтобы предотвратить завершение программы make при возникновении ошибки, выполните одно из следующих действий:
Допустим, после компиляции и компоновки трех файлов на языке C (x.c, y.c и z.c) создается программа с именем prog. Общие объявления для файлов x.c и y.c заданы в файле с именем defs. В файле z.c эти объявления не используются. Ниже приведен пример файла описания, который создает программу prog:
# Создание программы prog из трех объектных файлов prog: x.o y.o z.o # Создание prog с помощью cc cc x.o y.o z.o -o prog # Создать x.o из двух других файлов x.o: x.c defs # Создание x.o с помощью cc cc -c x.c # Создание y.o из двух других файлов y.o: y.c defs # Создание y.o с помощью cc cc -c y.c # Создание z.o из z.c z.o: z.c # Создание z.o с помощью cc cc -c z.c
Если присвоить этому файлу имя makefile, то достаточно будет ввести следующую команду:
make
При этом в случае изменения одного из исходных файлов (x.c, y.c, z.c и defs) программа prog будет обновлена.
Для упрощения файла описания можно воспользоваться внутренними правилами программы make. В соответствии с соглашениями о присвоении имен в файловой системе, команда make распознает три файла .c, соответствующие нужным файлам .o. С помощью команды cc -c эта программа может создать объектный файл из исходного.
С учетом этих правил файл описания примет следующий вид:
# Создание программы prog из трех объектных файлов prog: x.o y.o z.o # Создание prog с помощью cc cc x.o y.o z.o -o prog # Использование файлов defs и .c # для создании x.o и y.o x.o y.o: defs
Внутренние правила программы
make хранятся в файле, аналогичном файлам описания. Если
указать флаг -r, программа make не будет использовать
файл внутренних правил. В этом случае необходимо определить правила
создания файлов в файле описания. Файл внутренних правил содержит
список расширений имен файлов (таких как .o или
.a), которые распознаются командой make, и
правила, указывающие команде make способ создания файла с одним
расширением из файла с другим расширением. По умолчанию команда
make распознает следующие расширения имен:
Список расширений имен файлов аналогичен списку взаимосвязей в файле описания и следует за фиктивным именем целевого файла .SUFFIXES. Команда make просматривает список расширений имен файлов слева направо, поэтому последовательность записей существенна.
Программа make будет использовать первую же запись из списка, которая удовлетворяет следующим двум требованиям:
Из двух расширений имен файлов, определяемых правилом, программа make создает имя правила. Например, имя правила для преобразования файла .c в файл .o - .c.o.
Для того чтобы добавить в список другие расширения имен файлов, добавьте в файл описания запись для фиктивного целевого имени .SUFFIXES. Если задать в файле описания строку .SUFFIXES без расширений имен файлов, команда make сотрет текущий список. Для изменения порядка имен в списке, сотрите текущий список, а затем укажите в строке .SUFFIXES новый набор значений.
Ниже приведен фрагмент файла правил, используемых по умолчанию:
# Определение расширений имен файлов, известных команде make. .SUFFIXES: .o .C .C\~ .c .c~ .f .f~ .y .y~ .l .l~ .s .s~ .sh .sh~ .h .h~ .a # Начало списка внутренних # макроопределений YACC=yacc YFLAGS= ASFLAGS= LEX=lex LFLAGS= CC=cc CCC=xlC AS=as CFLAGS= CCFLAGS= # Конец списка внутренних # макроопределений # Создание файла .o из файла .c # с помощью программы cc. c.o: $(CC) $(CFLAGS) -c $<
# Создание файла .o # из файла .s с помощью ассемблера. s.o: $(AS)$(ASFLAGS) -o $@ $<
.y.o: # Создание промежуточного файла с помощью yacc $(YACC) $(YFLAGS) $< # Вызов компилятора cc $(CC) $(CFLAGS) -c y.tab.c # Удаление промежуточного файла rm y.tab.c # Копирование в целевой файл mv y.tab.o $@. .y.c: # Создание промежуточного файла с помощью yacc $(YACC) $(YFLAGS) $< # Копирование в целевой файл mv y.tab.c $@
В программе make
существует набор правил с одним расширением, позволяющий создавать из
исходного файла целевой файл без расширения (например, командный файл).
Существуют также правила, в соответствии с которыми программа make
создает объектные файлы с именами без расширений из следующих исходных
файлов:
Например, если все исходные файлы программы cat находятся в текущем каталоге, то команда
make cat
С помощью команды make
можно создавать библиотеки и библиотечные файлы. Файлы с расширением
.a рассматриваются программой make как
библиотечные файлы. Существуют следующие внутренние правила
преобразования исходных файлов в библиотечные файлы:
Программа make
использует макроопределения из файла правил. Для изменения этих
макроопределений укажите новые определения в командной строке или в
файле. Программа make применяет следующие имена
макроопределений для компиляторов, которые она поддерживает:
AS | Для Ассемблера. |
CC | Для компилятора C. |
CCC | Для компилятора C++. |
YACC | Для команды yacc. |
LEX | Для команды lex. |
Программа make
применяет для поддерживаемых компиляторов следующие макроопределения:
CFLAGS | Для флагов компилятора C. |
CCFLAGS | Для флагов компилятора C++. |
YFLAGS | Для флагов команды yacc. |
LFLAGS | Для флагов команды lex. |
make "CC=NEWCC"
указывает программе make, что вместо обычного компилятора C необходимо вызвать программу NEWCC. Аналогично, команда
make "CFLAGS=-O"
указывает команде make, что объектный код, созданный компилятором C, должен быть оптимизирован.
Внутренние правила команды make хранятся в файле /usr/ccs/lib/make.cfg.
Если при создании целевого файла команда make не может найти в файле описания необходимые команды или внутренние правила, она применяет указанные в файле команды по умолчанию. Команды, которые команда make будет выполнять в этом случае, перечисляются после целевого имени .DEFAULT:
.DEFAULT: команда команда . . .
Поскольку целевой файл .DEFAULT реально не существует, он называется фиктивным. Фиктивный целевой файл .DEFAULT применяется для задания функции исправления ошибок или общей процедуры, которая применяется для создания всех файлов, не определенных во внутренних правилах программы make.
С помощью директивы include в файл описания можно включать другие файлы. Эту директиву можно указывать в любой строке файла. После слова include указывается пробел или символ табуляции, за которым должно следовать имя файла, который будет включен командой make.
Примечание: В директиве include можно задать только одно имя файла.
Например:
include /home/tom/temp
include /home/tom/sample
указывают команде make, что для создания целевого файла необходимо использовать файлы temp, sample и файл описания.
Не следует использовать файлы описания с уровнем вложенности больше 16.
Макроопределение задает имя или метку, которая будет использоваться вместо нескольких других имен. Макроопределения позволяют кратко записывать длинные выражения. Для создания макроопределения:
До и после знака равенства (=) в макроопределении могут стоять пробелы; они ни на что не влияют. Перед знаком равенства не должно стоять двоеточие (:) или символ табуляции.
Ниже приведены примеры макроопределений:
# С константой "2" связывается значение "xyz" 2 = xyz # С константой "abc" связывается значение "-ll -ly" abc = -ll -ly # С константой "LIBES" связывается пустое значение LIBES =
Если задано имя макроопределения, но не указано его значение, то оно считается пустым.
После того как вы зададите макроопределение в файле описания, имя этого макроопределения можно использовать в командах файла описания, указывая перед ним символ $ (знак доллара). Если длина имени больше одного символа, его необходимо заключить в круглые () или фигурные {} скобки. Ниже приведены примеры использования макроопределений:
$(CFLAGS) $2 $(xy) $Z $(Z)
Последние два примера в этом списке эквивалентны.
Ниже приведен пример файла описания, в котором задаются и используются макроопределения:
# OBJECTS - это три файла x.o, y.o и # z.o (откомпилированные ранее) OBJECTS = x.o y.o z.o # LIBES - это библиотека стандартных функций LIBES = -lc # prog зависит от x.o y.o и z.o prog: $(OBJECTS) # Компоновка и загрузка 3 файлов и библиотеки стандартных # функций для создания файла prog cc $(OBJECTS) $(LIBES) -o prog
С помощью этого файла описания программа make компонует и загружает три объектных файла (x.o, y.o и z.o) и библиотеку libc.a.
Макроопределение, которое вводится в командной строке, переопределяет макроопределение с тем же именем, заданное в файле описания. Следовательно, команда
make "LIBES= -ll"
загружает файлы и библиотеку lex(-11).
Примечание: Если внутри макроопределения есть пробелы, его необходимо заключить в двойные кавычки (" "). В противном случае оболочка будет воспринимать эти пробелы не как часть макроопределения, а как разделители параметров.
Команда make поддерживает до 10 уровней вложенности макроопределений. Например, если задать последовательность макроопределений:
macro1=value1
macro2=macro1
то значение выражения $($(macro2)) будет равно value1.
Значение в макроопределении вычисляется в момент его обработки. Оно не вычисляется в момент определения. Если макроопределение было задано, но ни разу не использовалось, то связанное с ним значение не будет ни разу вычислено. Это особенно важно в тех случаях, когда макроопределение создается для значений, интерпретируемых оболочкой, так как они могут изменяться. Результат подстановки макроопределения
OBJS = 'ls *.o'
может быть разным, если оно вызывается в разные моменты времени в процессе создания или удаления объектных файлов. Результат обработки такого макроопределения не совпадает с результатом вызова команды ls во время создания макроопределения OBJS.
В программе make
предусмотрены стандартные макроопределения, которые можно использовать в файле
описания. В частности, они позволяют задавать переменные.
Программа make выполняет следующие макроподстановки:
Если в последовательности команд файла описания задано имя $@, то перед тем, как передать очередную команду оболочке, программа make заменит это имя на имя текущего целевого файла. Программа make выполняет такую подстановку только в том случае, если при создании целевого файла она выполняет команды из файла описания.
Если в строке взаимосвязей файла описания указано имя $$@, то программа make подставляет вместо него имя метки, которое стоит в этой строке слева от двоеточия. Например, строку взаимосвязей
cat: $$@.c
cat: cat.c
после обработки. Это макроопределение можно использовать для создания группы файлов, каждому из которых соответствует только один исходный файл. Например, для обновления каталога системных команд можно создать такой файл описания:
# Макроопределение CMDS # для замены имен команд CMDS = cat dd echo date cc cmp comm ar ld chown # Каждая команда зависит от файла .c $(CMDS): $$@.c # Создание нового набора команд путем компиляции устаревших # файлов ($?) и создания целевого файла с именем ($@) $(CC) -O $? -o $@
При выполнении программы make вместо $$(@F) будет подставлено $@. Это макроопределение можно использовать для обновления каталога usr/include, когда файл описания находится в другом каталоге. Ниже приведен пример такого файла описания:
# Макроопределение для имени каталога INCDIR INCDIR = /usr/include # Замена группы файлов каталога # именем INCLUDES INCLUDES = \ $(INCDIR)/stdio.h \ $(INCDIR)/pwd.h \ $(INCDIR)/dir.h \ $(INCDIR)/a.out.h \ # Все файлы в списке зависят от файла # с тем же именем из текущего каталога $(INCLUDES): $$(@F) # Копирует более свежие файлы из текущего # каталога в /usr/include cp $? $@ # Устанавливает для целевых файлов права только на чтение chmod 0444 $@
Этот файл описания создает файл в каталоге /usr/include, если был изменен соответствующий файл в текущем каталоге.
Если в последовательности команд файла описания есть макроопределение $?, то команда make подставляет вместо него список родительских файлов, которые были изменены уже после создания целевого файла. Программа make выполняет такую подстановку только в том случае, если при создании целевого файла она выполняет команды из файла описания.
Если в последовательности команд файла описания задано макроопределение $<, то команда make подставляет вместо него имя файла, с которого начинается создание целевого файла. Это имя родительского файла, который был изменен после создания целевого файла, что и послужило причиной вызова команды make.
Если указать символ < (знак "меньше") с буквой D или F, то вместо этой конструкции будет подставлено имя каталога или имя первого устаревшего файла, соответственно. Например, если имя первого устаревшего файла
/home/linda/sample.c
то в результате подстановки, выполняемой командой make, он будет заменен на
$(<D) = /home/linda $(<F) = sample.c $< = /home/linda/sample.c
Программа make выполняет эту подстановку только в том случае, если она выполняет команды из своих внутренних правил или из списка .DEFAULT.
Если в последовательности команд файла описания задано макроопределение $*, то команда make подставляет вместо него имя текущего родительского файла (без расширения), который применяется для создания целевого файла. Например, если команда make использует файл
test.c
то вместо $* будет подставлено имя test.
Если после звездочки (*) указать букву D или F, то будет подставляться имя каталога или имя текущего файла, соответственно.
Допустим, что для создания целевого файла программа make использует несколько файлов (заданных в файле описания или во внутренних правилах). В каждый момент времени применяется только один из этих файлов (он называется текущим). Если этот текущий файл
/home/tom/sample.c
то результат подстановки, выполняемой командой make, будет выглядеть так:
$(*D) = /home/tom $(*F) = sample $* = /home/tom/sample
Программа make выполняет эту подстановку только в том случае, если она выполняет команды из своих внутренних правил или из списка .DEFAULT, а не из файла описания.
Если в последовательности команд файла описания задано макроопределение $%, а целевой файл представляет собой компонент архивной библиотеки, то программа make подставляет имя библиотечного компонента. Например, если целевой файл - это
lib(file.o)
то команда make подставляет вместо $% имя компонента, то есть file.o.
Если в командах оболочки файла описания применяются макроопределения, то вы можете изменить текст, который будет подставлен вместо них командой make. Для изменения текста замещения после имени макроопределения нужно поставить двоеточие (:), а затем указать новый текст. Ниже приведен общий вид этой команды:
$(имя:строка1=строка2)
Когда команда make обнаруживает имя макроопределения, вместо строки1 она подставляет строку2. Например, если файл описания содержит макроопределение
FILES=test.o sample.o form.o defs
то с помощью макроопределения в команде файла описания можно заменить файл form.o на input.o:
cc -o $(FILES:form.o=input.o)
Такое изменение макроопределения можно использовать при обновлении архивных библиотек. Дополнительная информация приведена в описании команды ar.
Программа make создает целевой файл поэтапно.
Программа make выполняет следующие действия:
Если целевой файл или один из родительских файлов устарел, программа make создает целевой файл с помощью одного из следующих наборов команд:
Если все файлы уже были обработаны программой make, то она выдаст сообщение о том, что ни один файл не изменен, и завершит свою работу. Если после последнего запуска команды make некоторые файлы были изменены, то команда make обновит только устаревшие файлы. Файлы, которые не были изменены, заново не создаются.
При выполнении команд, предназначенных для создания целевого файла, программа make обрабатывает макроопределения, записывает каждую командную строку и передает команду в новую копию оболочки.
Команды и файлы SCCS применяются для управления доступом к файлу и отслеживания изменений, внесенных в файл. Файл SCCS - это любой текстовый файл, который применяется командами SCCS. При обработке файлов SCCS командами, отличными от SCCS, эти файлы могут быть повреждены. Дополнительная информация об SCCS приведена в разделе Глава 23, Система контроля исходного кода (SCCS).
У всех файлов SCCS есть префикс s., отличающий их от обычных текстовых файлов. Программа make не распознает ссылки на префиксы имен файлов. Из-за этого в файле описания команды make нельзя ссылаться на файлы SCCS напрямую. Для представления файлов SCCS программа make использует расширение ~ (тильду). Следовательно, .c~.o - это имя правила, которое преобразует файл SCCS, содержащий исходный код на языке C, в объектный файл. Ниже приведено внутреннее представление этого правила:
.c~.o: $(GET) $(GFLAGS) -p $< >$*.c $(CC) $(CFLAGS) -c $*.c -rm -f $*.c
Добавление символа ~ (тильды) к расширению имени файла приводит к тому, что вместо обычного файла будет найден файл SCCS с фактическим расширением (включающим все символы, стоящие между точкой (.) и тильдой). С помощью макроопределения GFLAGS в SCCS передаются флаги, задающие версию файла SCCS.
Программа make
распознает следующие расширения имен SCCS:
.C\~ | Исходный файл C++ |
.c~ | Исходный файл c |
.y~ | Исходная грамматика yacc |
.s~ | Исходный файл ассемблера |
.sh~ | Файл команд оболочки |
.h~ | Заголовочный файл |
.f~ | Файл на Фортране |
.l~ | Исходная грамматика lex |
В программе make применяются следующие правила преобразования файлов SCCS:
Если в текущем каталоге хранится файл описания (файл с именем makefile или Makefile), то команда make не будет искать файл описания в SCCS. Если в текущем каталоге нет файла описания, то команда make попытается найти в SCCS файл с именем s.makefile или s.Makefile. Если команда make найдет один из этих файлов, она вызовет команду get для создания файла описания на базе найденного файла с помощью SCCS. После того как SCCS создаст файл описания, он будет обработан командой make как обычный файл описания. Когда команда make завершит свою работу, она удалит из текущего каталога созданный файл описания.
Запустите программу make из каталога, в котором находится файл описания для создаваемого файла. Имя этого файла описания указывается в параметре файл-описания. Введите команду
make -f файл-описания
в командной строке. Если файл описания называется makefile или Makefile, флаг -f указывать не нужно. Введите в командной строке вместе с командой make макроопределения, флаги, имена файлов описания и имена целевых файлов:
make [флаги] [макроопределения] [целевые-файлы]
С помощью параметров, заданных в командной строке, программа make определяет, что ей нужно сделать. Во-первых, она просматривает все макроопределения, указанные в командной строке (т.е. записи, которые заключены в кавычки и содержат знак равенства), и выполняет макроподстановку. Если программа make обнаружит одно и то же макроопределение в командной строке и в файле описания, то она будет применять макроопределение, заданное в командной строке.
После этого программа make просматривает флаги. Для получения дополнительной информации просмотрите список флагов, поддерживаемых командой make.
Все остальные записи в командной строке рассматриваются программой make как имена целевых файлов. Команда make выполняет все команды оболочки, заключенные в обратные кавычки, которые генерируют имена целевых файлов. После этого программа make создает целевые файлы (слева направо). Если имя целевого файла в командной строке не указано, то программа make создает целевой файл с первым же обнаруженным в файле описания именем, которое не начинается с точки. Если задано несколько файлов описания, команда make определяет имя целевого файла из первого файла описания.
При запуске программа make считывает текущие значения переменных среды и добавляет их в свои макроопределения. С помощью макроопределений MAKEFLAGS и MFLAGS пользователь может задать флаги, которые должны быть переданы команде make. Если заданы оба макроопределения, то MAKEFLAGS переопределяет значения MFLAGS. С флагами, заданными с помощью этих переменных, в команду make передаются все опции из командной строки. Если команда make вызывается рекурсивно с помощью макроопределения $(MAKE) в файле описания, то при каждом вызове make передает все флаги.
Программа make выполняет макроподстановку в следующем порядке:
Если переменная среды MAKEFLAGS не задана, команда make проверяет значение переменной среды MFLAGS. Если для одной из этих переменных задано непустое значение, команда make рассматривает каждый символ этого значения как входной флаг. Эти флаги (кроме флагов -f, -p и -d, которые нельзя задать с помощью MAKEFLAGS и MFLAGS), задают среду выполнения команды make.
Ниже приведен файл описания для обновления программы make. Исходный код команды make включает несколько файлов на языке C и грамматику yacc.
# Файл описания для программы make # Макроопределение: вывод на печать P = qprt # Макроопределение: имена исходных файлов FILES = Makefile version.c defs main.c \ doname.c misc.c files.c \ dosy.c gram.y lex.c gcos.c #Макроопределение: имена объектных файлов OBJECTS = version.o main.o doname.o \ misc.o files.o dosys.o \ gram.o # Макроопределение: программа lint и флаги LINT = lint -p # Макроопределение: флаги компилятора C CFLAGS = -O # make зависит от файлов, указанных # в макроопределении OBJECTS make: $(OBJECTS) # Компоновка make с помощью программы cc cc $(CFLAGS) $(OBJECTS) -o make # Выводит размер файлов @size make
# Объектные файлы зависят от файла # с именем defs $(OBJECTS): defs # Файл gram.o зависит от lex.c # Для создания gram.o применяются внутренние правила: gram.o: lex.c # Удаление промежуточных файлов clean: -rm *.o gram.c -du # Копирование вновь созданной программы в каталог # /usr/bin и удаление программы # из текущего каталога install: @size make /usr/bin/make cp make /usr/bin/make ; rm make # Пустой файл "print" зависит от файлов, # включенных в макроопределение FILES print: $(FILES) # Печать измененных файлов pr $? | $P # Изменение даты в пустом файле # print на дату последней # печати touch print
# Сравнение даты старого # файла с датой вновь # созданного файла test: make -dp | grep -v TIME >1zap /usr/bin/make -dp | grep -v TIME >2zap diff 1zap 2zap rm 1zap 2zap # Программа lint зависит # от перечисленных файлов lint: dosys.c doname.c files.c main.c misc.c \ version.c gram.c # Вызов lint с перечисленными файлами # LINT - это внутреннее макроопределение $(LINT) dosys. doname.c files.c main.c \ misc.c version.c gram.c rm gram.c # Архивация файлов, из которых создается make arch: ar uv /sys/source/s2/make.a $(FILES)
Обычно перед выполнением команды программа make отправляет ее на стандартное устройство вывода.
Ниже показан пример вывода, полученного при вызове простой команды make из каталога, содержащего только исходный файл и файл описания:
cc -O -c version.c cc -O -c main.c cc -O -c doname.c cc -O -c misc.c cc -O -c files.c cc -O -c dosys.c yacc gram.y mv y.tab.c gram.c cc -O -c gram.c cc version.o main.o doname.o misc.o files.o dosys.o gram.o -o make make: 63620 + 13124 + 764 + 4951 = 82459
В файле описания не задано ни одного исходного файла или файла грамматики. Для их определения команда make использует свои правила расширения имен, а затем выполняет необходимые команды. Числа в последней строке приведенного примера - это результат выполнения команды size make. Поскольку в файле описания перед командой size стоит символ @, то вывод самой команды подавляется, а выводятся только ее результаты (размеры файлов).
Вывод можно отправить на принтер или в файл, изменив макроопределение P в командной строке. Например:
make print "P = print -sp"
или
make print "P = cat >zap"