MAKE MAKE СОДЕРЖАНИЕ 1. Введение 2. Основные возможности 3. Файлы описаний и подстановки 3.1. Комментарии 3.2. Строки продолжения 3.3. Макроопределения 3.4. Общий вид файла описаний 3.5. Информация о зависимостях 3.6. Исполняемые команды 3.7. Усовершенствования $*, $@, $< 3.8. Выходные преобразования макросов 4. Рекурсивные make-файлы 4.1. Суффиксы и правила трансформации 4.2. Подразумеваемые правила 4.3. Архивные библиотеки 5. Имена SCCS-файлов (тильда) 5.1. Пустой суффикс 5.2. Включаемые файлы 5.3. make-файлы в рамках SCCS 5.4. Динамические параметры зависимостей 6. Запуск утилиты make 6.1. Командная строка 6.2. Переменные окружения 7. Советы и предостережения 8. Встроенные правила 1. ВВЕДЕНИЕ Стремление к увеличению модульности программ может привести к тому, что реализация проекта будет состоять из большого числа файлов. Для формирования из них конечного продукта - программы - могут понадобиться разнообразные порождающие процедуры. Утилита make позволяет поддерживать свежие версии программ, состоящих из нескольких файлов, с возможностью порождения прог- рамм различными способами. Всякий программист запросто может забыть: Зависимости между файлами. Перечень модифицированных файлов и воздействие модифи- каций на другие файлы. Точную последовательность действий, необходимых для по- рождения новой версии программы. Файл описаний позволяет make'у отслеживать зависимости между файлами, составляющими программную систему. Если изменен любой из них, утилита make порождает новую версию программы, переком- пилировав только те ее части, которые прямо или косвенно зат- ронуты изменением. Основные операции утилиты make таковы: Найти в файле описаний целевой файл. Добиться того, чтобы все файлы, от которых зависит це- левой файл, а также файлы, необходимые для его порожде- ния, существовали и не были устаревшими. Файлу описаний, задающему информацию о межфайловых зависимостях и последовательностях команд для порождения файлов, принято да- вать имя makefile, Makefile или s.[mM]akefile. Если следовать этому соглашению, для достижения цели чаще всего оказывается достаточно просто набрать make независимо от того, сколько файлов было изменено. В большинстве случаев файл описаний написать нетрудно, а изменяется он нечас- то. Даже если отредактирован единственный файл, вызов утилиты make надежнее, чем ввод всех команд перегенерации целевого фай- ла. Имеется одно применение утилиты make, с которым приходится сталкиваться всем системным программистам - это перегенерация ОС UNIX. В каталоге /usr/src/uts находится файл описаний с име- нем Makefile, управляющий процессом перегенерации. Изучение по- добного реального примера должно способствовать лучшему понима- нию данного описания. 2. ОСНОВНЫЕ ВОЗМОЖНОСТИ Основное действие утилиты make - обновление целевого файла при условии, что все файлы, от которых зависит целевой, существуют и не являются устаревшими. Целевой файл порождается заново, ес- ли названные файлы модифицированы, а целевой - нет. Утилита ma- ke исследует граф зависимостей. Функционирование 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- файлам, и применяет встроенные правила порождения об'ектного файла из исходного С-файла (то есть выполняет команду 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 Печать самой командной строки подавляется знаком @ в файле опи- саний. 3. ФАЙЛЫ ОПИСАНИЙ И ПОДСТАНОВКИ В данном разделе описываются основные компоненты файла описа- ний. 3.1. Комментарии Признаком комментария, по соглашению, является символ #; все символы за ним до конца строки игнорируются. Пустые строки и строки, начинающиеся с #, игнорируются полностью. 3.2. Строки продолжения Слишком длинную строку, не являющуюся комментарием, можно про- должить, используя знак \. Если последним символом строки явля- ется символ \, то он, а также перевод строки и все следующие за ним пробелы и табуляции заменяются на одиночный пробел. 3.3. Макроопределения Макроопределение - это идентификатор, за которым следует знак равенства. Перед идентификатором не должно стоять двоеточия или табуляции. Имя (цепочка букв и/или цифр) слева от знака ра- венства (завершающие пробелы и табуляции отбрасываются) сопос- тавляется цепочке символов, следующей за знаком равенства (на- чальные пробелы и табуляции отбрасываются). Ниже приведены кор- ректные макроопределения: 2 = xyz abc = -ll -ly -lm LIBES = Последнее определение сопоставляет LIBES с пустой цепочкой. Макрос, нигде не определенный явным образом, имеет в качестве значения пустую цепочку. Напомним, однако, что некоторые макро- сы явно определяются во встроенных правилах утилиты make. (См. раздел ВСТРОЕННЫЕ ПРАВИЛА.) 3.4. Общий вид файла описаний Общий вид точки входа в файле описаний таков: цель1 [цель2 ...] :[:] [зависимость1 ...] [; команды] [# ...] [\t команды ] [# ...] Указанные в скобках компоненты могут быть опущены, цели и зави- симости являются цепочками из букв, цифр, символов . и /. При обработке строки интерпретируются метасимволы shell'а, такие как * и ?. Команды могут быть указаны после точки с запятой в строке зависимостей, или в строках, начинающихся с табуляции, которые следуют сразу за строкой зависимостей. Команда - это произвольная цепочка символов, не содержащая знак #, за исклю- чением тех случаев, когда # заключен в кавычки. 3.5. Информация о зависимостях В строке зависимостей может быть указан одинарный либо сдвоен- ный знак двоеточия. Целевое имя может встречаться более чем в одной строке зависимостей, однако все эти строки должны быть одного (либо с одинарным, либо со сдвоенным двоеточием) типа. В более распространенном случае (одинарное двоеточие) последова- тельность команд может быть сопоставлена не более чем одной строке зависимостей. Если целевой файл устарел по сравнению с какой-либо зависимостью в любой из этих строк и специфицирована последовательность команд (даже если после точки с запятой или табуляции идет пустая цепочка), данная последовательность ко- манд выполняется; иначе может быть вызвано встроенное правило. В случае со сдвоенным двоеточием последовательность команд мо- жет быть сопоставлена более чем одной строке зависимостей. Если целевой файл устарел по сравнению с какой-либо зависимостью из одной из этих строк, выполняются соответствующие команды. Также может быть выполнено встроенное правило. Форма со сдвоенным двоеточием особенно полезна для обновления архивных файлов, где целевой файл - это сама архивная библиотека. (Соответствующий пример содержится в пункте Архивные библиотеки.) 3.6. Исполняемые команды Если целевой файл должен быть создан, выполняется последова- тельность команд. Обычно каждая командная строка распечатывает- ся и затем, после подстановки макросов, для ее выполнения за- пускается очередной экземпляр shell'а. Печать может быть подав- лена в режиме "молчания" (опция -s утилиты make) или в том слу- чае, если командная строка в файле описаний начинается со знака @. make обычно прекращает работу, если какая-либо команда сиг- нализирует об ошибке, возвращая ненулевой код завершения. Ошиб- ки игнорируются, если в командной строке make'а указана опция -i, или если в файле описаний указано фиктивное целевое имя .IGNORE, или если командная строка в файле описаний начинается со знака минус. Если известно, что программа возвращает бессо- держательное значение, полезно указывать минус перед строкой, ее запускающей. Поскольку каждая командная строка передается отдельному экземпляру shell'а, при использовании собственных команд shell'а [например, cd(1)] надо проявлять осторожность, потому что они имеют смысл только в пределах одного shell-про- цесса. Перед выполнением следующей строки результаты выполнения этих команд утрачиваются. Перед вызовом любой команды устанавливаются некоторые встроен- ные макросы. Макрос $@ устанавливается равным полному имени те- кущего целевого файла. Он вычисляется только для явно указанных зависимостей. Макрос $? устанавливается равным цепочке имен файлов, которые оказались более свежими, чем целевой; он также вычисляется только при обработке явных правил make-файла. Если команда порождена неявным правилом, макрос $< равен имени фай- ла, вызвавшего действие; макрос $* - префикс имени, общий для текущего файла и файла из строки зависимостей. Если файл должен быть получен, но нет явных команд или встроенных правил, ис- пользуются команды, сопоставленные фиктивному целевому имени .DEFAULT. Если такого имени нет, make выдает сообщение и прек- ращает работу. Кроме того, в файле описаний можно использовать следующие свя- занные с упомянутыми выше макросы: $(@D), $(@F), $(*D), $(*F), $(