ОСНОВНЫЕ ВОЗМОЖНОСТИ
Основное действие утилиты make - обновление целевого файла при условии, что все файлы, от которых зависит целевой, существуют и не являются устаревшими. Целевой файл порождается заново, если названные файлы модифицированы, а целевой - нет. Утилита make исследует граф зависимостей. Функционирование make'а основывается на анализе времени последней модификации файлов.
Утилита make действует, опираясь на три источника информации:
- Заданный пользователем файл описаний.
- Имена файлов и времена последней модификации, получае- мые от файловой системы.
- Встроенные правила, позволяющие разрешить некоторые не- домолвки в файле описаний.
В качестве иллюстрации рассмотрим следующий простой пример. Программа prog получается из трех исходных файлов x.c, y.c и z.c путем их компиляции и редактированием связей совместно с библиотекой math. В соответствии с принятыми соглашениями результат работы C-компилятора будет помещен в файлы с именами x.o, y.o и z.o. Предположим также, что файлы x.c и y.c используют общие описания из включаемого файла defs.h, а z.c - не использует. Пусть x.c и y.c содержат строку
#include "defs.h"
Следующая спецификация описывает взаимосвязи и операции:
prog : x.o y.o z.o cc x.o y.o z.o -lm -o prog x.o y.o : defs.h
Если эту информацию поместить в файл с именем makefile, команда
make
будет выполнять операции, необходимые для перегенерации prog
после любых изменений, сделанных в каком-либо из четырех исходных файлов x.c, y.c, z.c или defs.h. В приведенном выше примере в первой строке утверждается, что prog зависит от трех .o-файлов. Если эти файлы имеются в наличии, рассматривается вторая строка, которая описывает, как отредактировать связи между ними, чтобы создать prog. Третья строка гласит, что x.o и y.o зависят от defs.h. Обратившись к файловой системе, make обнаруживает, что имеются три .c-файла, соответствующие требуемым .o- файлам, и применяет встроенные правила порождения объектного файла из исходного C-файла (то есть выполняет команду cc -c).
Если make не может автоматически определить действия, которые требуется выполнить, необходим следующий, более длинный файл описаний:
prog : x.o y.o z.o cc x.o y.o z.o -lm -o prog x.o : x.c defs.h cc -c x.c y.o : y.c defs.h cc -c y.c z.o : z.c cc -c z.c
Если ни один из исходных или объектных файлов не был изменен с момента последнего порождения prog и все файлы в наличии, утилита make известит об этом и прекратит работу. Если, однако, файл defs.h отредактировать, x.c и y.c (но не z.c) будут перекомпилированы; затем из новых файлов x.o и y.o и уже существую- щего файла z.o будет заново собрана программа prog. Если изменен лишь файл y.c, только он и перекомпилируется, после чего последует пересборка prog. Если в командной строке make не за- дано имя цели, создается первый упомянутый в описании целевой файл; в противном случае создаются специфицированные целевые файлы. Команда
make x.o
будет перегенерировать x.o, если изменен x.c или defs.h.
Часто в файл описаний включают правила с мнемоническими именами и командами, которые в действительности не порождают файлов с соответствующими именами. Смысл в том, чтобы воспользоваться средствами make'а по генерации файлов и подстановке макросов (информацию о макросах см. в разделе ФАЙЛЫ ОПИСАНИЙ И ПОДСТАНОВКИ). Мнемонические имена играют роль точек входа, при обращении к которым выполняются определенные действия. Так, точка входа save может служить для копирования определенной совокупности файлов, а точка входа clean - для удаления ненужных промежуточных файлов.
Если после выполнения таких команд файл существует, то для того, чтобы принимать последующие решения, используется время его последней модификации; если же он не существует, используется текущее время.
Еще один полезный прием состоит в том, что при необходимости отслеживать только время выполнения определенных действий целесообразно завести пустой файл, который будет использоваться только как носитель времени последней модификации.
Утилита make использует простой механизм макросов для выполнения подстановок в строках зависимостей и цепочках команд. Макрос можно либо задать аргументами командной строки, либо включить в файл описаний. В обоих случаях макроопределение состоит из имени, за которым следует знак равенства (=), а затем то, что макрос обозначает. При обращении к макросу перед его именем указывается знак $. Имена макросов, состоящие более чем из одного символа, должны заключаться в скобки. Ниже приводятся примеры корректных обращений к макросам:
$(CFLAGS) $2 $(xy) $Z $(Z)
Две последние строки эквивалентны.
$*, $@, $?, $< - это четыре специальных макроса, значения которых изменяются во время выполнения команды. Они описываются в разделе ФАЙЛЫ ОПИСАНИЙ И ПОДСТАНОВКИ. В следующем фрагменте показаны определения и использования некоторых макросов:
OBJECTS = x.o y.o z.o LIBES = -lm prog: $(OBJECTS) cc $(OBJECTS) $(LIBES) -o prog . . .
Команда
make LIBES="-ll -lm"
загружает три объектных файла вместе с библиотекой lex'а (-ll) и математической библиотекой (-lm), потому что в первую очередь используются макроопределения из командной строки, а не одноименные определения в файле описаний. (В командах ОС UNIX аргументы, содержащие пробелы, должны заключаться в кавычки).
В качестве примера использования make'а приведем файл описаний, который может применяться при сопровождении самой утилиты make. Исходный текст утилиты содержится в нескольких C-файлах, а также включает yacc-спецификацию грамматики.
# Файл описаний для утилиты make
FILES = Makefile defs.h main.h doname.c misc.c files.c dosys.c gram.y OBJECTS = main.o doname.o misc.o files.o dosys.o gram.o LIBES = -lld LINTS = lint -p CFLAGS = -O LP = /usr/bin/lp
make: $(OBJECTS) $(CC) $(CFLAGS) $(OBJECTS) $(LIBES) -o make
$(OBJECTS): defs.h
cleanup: -rm *.o gram.c -du install: @size make /bin/make mv make /bin
lint : dosys.c doname.c files.c main.c misc.c gram.c $(LINT) dosys.c doname.c files.c main.c misc.c \ gram.c
# Распечатать файлы, состояние которых не # согласуется с "целевым файлом" print
print: $(FILES) pr $? | $(LP) touch print
Перед выполнением всякой команды утилита make распечатывает ее.
Вызов утилиты make в каталоге, содержащем только указанные исходные файлы и файл описаний, будет иметь следующий результат:
cc -o -c main.c cc -o -c doname.c cc -o -c misc.c cc -o -c flies.c cc -o -c dosys.c yacc gram.y mv y.tab.c gram.c cc -o -c gram.c cc main.o doname.o misc.o files.o dosys.o gram.o -lld \ -o make make: 24700 + 7100 + 18344 = 50144 /bin/make: 25200 + 6900 + 18108 = 50208
Две последние строки являются результатом выполнения команды
size make /bin/make
Печать самой командной строки подавляется знаком @ в файле описаний.