MAKE MAKE СОДЕРЖАНИЕ 1. Введение 2 2. Основные возможности 4 3. Файлы описаний и подстановки 9 3.1. Комментарии 9 3.2. Строки продолжения 9 3.3. Макроопределения 9 3.4. Общий вид файла описаний 9 3.5. Информация о зависимостях 10 3.6. Исполняемые команды 10 3.7. Усовершенствования $*, $@, $< 11 3.8. Выходные преобразования макросов 11 4. Рекурсивные make-файлы 13 4.1. Суффиксы и правила трансформации 13 4.2. Подразумеваемые правила 13 4.3. Архивные библиотеки 15 5. Имена SCCS-файлов (тильда) 18 5.1. Пустой суффикс 19 5.2. Включаемые файлы 20 5.3. make-файлы в рамках SCCS 20 5.4. Динамические параметры зависимостей 20 6. Запуск утилиты make 22 6.1. Командная строка 22 6.2. Переменные окружения 23 7. Советы и предостережения 25 8. Встроенные правила 26 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 файлам, и применяет встроенные правила порождения объектного файла из исходного C-файла (то есть выполняет команду cc -c). Если make не может автоматически определить действия, которые требуется выполнить, необходим следующий, более длинный файл описаний: |x.o : x.c | 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), $(