Интерпретатор make Производственно-внедренческий кооператив "И Н Т Е Р Ф Е Й С" Диалоговая Единая Мобильная Операционная Система Демос/P 2.1 Интерпретатор make Москва 1988 АННОТАЦИЯ Описан интерпретатор make, используемый для сборки пакетов программ, минимизирующий число вызовов транслятора. 1. Введение Интерпретатор make [1], наиболее часто используемый программистами ДЕМОС, предоставляет уникальные возможности по управлению любыми видами работ в операционной системе. Всюду, где имеется необходимость учитывать зависимости фай- лов и времена их создания (модификации), make оказывается незаменимым инструментом. Интерпретатор реализует непроце- дурный язык, который позволяет управлять группами командных строк системы. В основу такого управления положены зависи- мости между файлами с исходными данными и файлами, в которых содержатся результаты. При этом предполагается любой возмож- ный список действий над исходными файлами: компиляция, мак- рообработка, редактирование, печать, упаковка или шифрование и т.д. Исходной информацией для интерпретатора является Make-программа, представлящая список определений макропере- менных и список правил. Каждое правило включает формулировку цели и список действий для интерпретатора shell. При выпол- нении Make-программы интерпретатор make использует информа- цию о связях между целями и результатами и передает на выполнение shell списки действий, которые в данный момент необходимо выполнить для получения заданного результата. Таким образом, интерпретатор make позволяет записывать любой набор действий над исходными данными, благодаря чему он широко используется при решении прикладных и общесистемных задач. Очень важно и то, что Make-программа становится общесистемным стандартным описанием структуры задачи, алго- ритма сборки и установки программного комплекса. Програм- мист, владеющий средствами интерпретатора make, использует следующую технологию разработки программного комплекса, независимо от его сложности: редактор -> make -> проверка -> редактор При такой технологии существенно повышается производитель- ность труда программиста,так как он освобождается от ручной сборки программ, сокращается загрузка ЭВМ - make "следит" за тем, чтобы при многократных компиляциях и отладках программ "не делалолсь то, что можно не делать". Важно отметить, что make является средством автоматиза- ции процедур установки компонент ДЕМОС. Например, компонента системы cat может включать следующие файлы: выполняемый код - файл /bin/cat текст программы - файл ./src/cmd/cat/cat.c документацию - файл ./man/man1/cat.1 программу сборки - файл ./src/cmd/cat/Makefile Файл ./src/cmd/cat/Makefile содержит всю необходимую для правильной компиляции и установки в ОС компоненты cat инфор- мацию. Особенно эффективен make для выполнения работ в программных проектах малой и средней (до 200 файлов) - 3 - величин. 2. Принципы выполнения Make-программы Интерпретатор make выполняет программу, которую будем называть Make-программой. Make-программа содержит структуру зависимостей файлов и действий над ними, оформленных в виде списка правил. Выполнение действий приводит к созданию тре- буемых файлов. Допустим, имеются файлы a b c d e f из которых определенным образом необходимо получить файл E. Пусть далее известно, что над различными комбинациями исход- ных файлов выполняются некоторые действия, а результаты будут размещены в промежуточных файлах A, B, C и D. Расс- мотрим граф, узлы которого - имена файлов. Дуги графа отра- жают зависимости файлов, стрелка указывает направление пре- образований от исходных файлов к файлам, которые необходимо получить. В Make-программе каждой паре (x,y) инцидентных узлов этого графа ставится в соответствие список действий, выпол- нение которых приведет к созданию x. Когда файл x сущест- вует, список действий не выполняется, но только в том слу- чае, если файл y создан (модифицирован) раньше по времени, чем файл x. Каждой дуге графа можно поставить в соответсвие значение функции t(x,y). Функция t(x,y) возвращает результат в виде /\ цель E / \ | /----\ | || t(E,D ) | t(E,C) || ----------------------- || | | || цель D цель C || t(D,A) | t(D,B) | || ---------------- | || | | | || цель A цель B | || | | t(C,e)| || t(A,a)| t(A,b) t(B,c)| t(B,d) t(C,d)| || ------------ ------------ ------- || | | | | | | || | | | | | | || a b c d e f || - 4 - x МОЛОЖЕ y - список действий не выполняется; x СТАРЕЕ y - список действий выполняется. Множество значений функции t(x,y) образует структуру динами- ческих (зависящих от времени) связей между файлами. На этой основе интерпретатор make выделяет те разделы Make- программы, которые можно не выполнять. Выше предполагалось, что каждый узел графа - это файл. Существует возможность записать в Make-программe список действий, выполнение которых не связано с созданием файла. Поэтому в общем случае узел графа правильнее называть целью. Пара инцидентных узлов графа образует цель и подцель. В при- мере узел E - цель, узлы D и C - подцели цели E. Аналогично узел D - цель, узлы A и B - подцели цели D. Наконец, узел A - цель, узлы a и b - подцели узла A. Перечисление вида ЦЕЛЬ - ПОДЦЕЛИ отражает обобщенную структуру алгоритма достижения целей. Введем понятие реконструкция файла-цели. Если файл-цель существует и "МОЛОЖЕ" всех файлов, от которых зависит, то он остается без изменений, иначе, если файл-цель существует и "СТАРЕЕ" какого-либо файла, от которого зависит, он реконст- руируется (изготавливается заново). Приведем пример Make-программы, соответствующей приве- денному выше графу. Программа выглядит как его линейная запись: E : D C # E зависит от D и C cat D C > E # действие правила 1 D : A B # D зависит от A и B cat A B > D # действие правила 2 A : a b # A зависит от a, b cat a b > A # действие правила 3 B : c d # B зависит от c, d cat c d > B # действие правила 4 C : e f # C зависит от e, f cat e f > C # действие правила 5 clean clear: -rm -f A B C D E Здесь содержится 6 правил. Каждое правило включает строку зависимостей файлов и командную строку системы. Правило описывается просто: сначала указывается имя файла, который - 5 - необходимо создать (цель), затем двоеточие, затем имена фай- лов, от которых зависит создаваемый файл (подцели), затем строки действий. Первую строку правила назовем строкой зависимостей. Следует обратить внимание на шестое правило: в нем пустой список подцелей в строке зависимостей. Синтак- сис строк действий соответствует синтаксису командных строк shell. Первым символом строки действия в Make-программе дол- жен быть символ табуляции (или 8 пробелов) - это обязатель- ное условие. Все последовательности символов, начиная от символа # и до конца строки, являются комментарием. Пустые строки и лиш- ние пробелы игнорируются. Если Make-программа размещена в файле Makefile, то имя файла с Make-программой в командной строке можно не указывать. Допустим, файл с Make-программой называется Makefile, в рабочем каталоге имеются файлы a, b, c и d. Файлы A, B, C и D отсутствуют, тогда по команде make мы получим результат - файл Е и файлы A, B, C и D. Рассмот- рим порядок выполнения Make-программы, когда эти файлы уже существуют, т.е. при повторном выполнении команды make. Первый шаг выполнения Make-программы: E : D C cat D C > E Если файлы D и C существуют и не требуется их реконструкция, а файл E "МОЛОЖЕ", чем файлы D и C, то make прекратит выпол- нение программы - файл Е готов. Если требуется реконструк- ция файлов D и/или C, то осуществляется переход к выполнению подцелей D и/или C, затем возврат к этому правилу. Иначе, если требуется реконструкция файла E, то выполняется дейст- вие этого правила и make прекращает выполнение программы - готов реконструированный файл E. Иначе, если отсутствуют файлы D и/или C, будут выполнены подцели D и/или C в том порядке, в котором они указаны в списке зависимостей, затем выполняется действие этого правила и make прекратит выполне- ние программы - готов файл E. Второй шаг выполнения Make-программы: D : A B cat A B > D Если файлы A, B и D существуют и не требуется их реконст- рукция, то выполняется переход к следующему шагу Make- программы (файл D уже готов). Если требуется реконструкция файлов A и/или B, происходит переход к выполнению подцелей A и/или C, затем возврат к этому правилу. Иначе, если требу- ется реконструкция файла D, выполняется действие этого пра- вила и переход к следующему шагу выполнения Make-программы. Иначе, если отсутствуют файлы A и/или B, будут выполнены подцели A и/или B в том порядке, в котором они указаны в - 6 - списке зависимостей, затем действие этого правила и переход к выполнению первого правила Make-программы. Третий шаг выполнения Make-программы: A : a b cat a b > A Проверяется наличие файлов a и b в рабочем каталоге. При отсутствии хотя бы одного из них выполнение программы прек- ращается. Затем проверяется наличие файла A, если его нет или требуется его реконструкция, выполняется действие этого правила. Иначе осуществляется переход к выполнению второго правила. Четвертый шаг выполнения Make-программы: B : c d cat c d > B Действия аналогичны описанным в третьем шаге, переход осу- ществляется к выполнению второго правила. Пятый шаг выполнения Make-программ: C : e f cat e f > C Проверяется наличие файлов e и f в рабочем каталоге. При отсутствии хотя бы одного из них выполнение программы прек- ращается. Затем проверяется наличие файла C, если его нет или требуется его реконструкция, выполняется действие этого правила. Иначе осуществляется переход к выполнению первого правила. При вызове интерпретатора make в командной строке можно указать имя цели. Если, например, необходимо получить файл D, то командная строка выглядела бы так % make D или если необходимо получить файлы C и D, то командная строка выглядела бы % make C D Таким образом, имя файла-цели в командной строке определяет вход в Make-программу. Если задано несколько входов, то make выполнит в указанном порядке все необходимые разделы Make- программы. Если же вход не указан, выполняется первое пра- вило Make-программы. - 7 - В шестом правиле примера цель не является файлом, это важная особенность make. Программисту предоставляется воз- можность записать правило, цель и/или подцели которого не являются файлами. В таком случае цель - это имя входа в Make-программу (или метка правила). Шестое правило исполь- зуется в программе для удаления файлов. Следует обратить внимание на то, что в этом правиле два имени цели (clean и clear), поэтому в командной строке можно указывать любое имя входа, например: % make clean или % make clear В результате выполнения будут удалены файлы A, B, C, D и E. Все строки действий в правилах передаются на выполнение shell следующим образом: sh -c строка_действия и должны нормально выполняться интерпретатором sh (код возв- рата 0), иначе (по получении другого кода завершения командной строки) make прекратит выполнение программы. Существует способ обойти это условие. Обратите внимание на действие в 6-м правиле: строка действий начинается с символа "-", что означает не прекращать работу при неудачном выпол- нении команды rm. В Make-программе можно использовать макропеременные. Механизм макроопределений и подстановок макропеременных в Make-программе по смыслу аналогичен механизму подстановок в shell, хотя по синтаксису несколько отличается. Рассмотрим приведенный выше пример с использованием макропеременных. Теперь Makefile будет выглядеть так: - 8 - SRC1 = a b # макроопределения SRC2 = c d SRC3 = e f SRC4 = A B C D E : D C cat D C > E D : A B cat A B > D A : $(SRC1) # A зависит от SRC1 cat $(SRC1) > A B : $(SRC2) # B зависит от SRC2 cat $(SRC2) > B C : $(SRC3) # C зависит от SRC3 cat $(SRC3) > C clean clear: -rm -f $(SRC4) Первые строки Make-программы - строки с макроопределениями, где каждой переменной SRC присваиваются значения. В правилах выполняется операция подстановки значения макропеременной, например $(SRC1). Макропеременные позволяют манипулировать списками имен файлов при минимальных изменениях в тексте Make-программы. Интерпретатор make реализует механизм обработки умолча- ний зависимостей файлов со стандартными суффиксами имен. Например, файл с суффиксом имени .o можно получить из файлов с суффиксами имен .c (язык программирования Си) и .s (язык ассемблер). Рассмотрим пример. Допустим, имеются файлы a.c, b.c, c.c и d.s, образующие программу, которую назовем pro- gram. Файлы a.c, b.c и c.c содержат строку # include program.h т.е. зависят от файла program.h. Make-программа для работы с этими файлами будет содержать 3 строки program: a.o b.o c.o d.o cc a.o b.o c.o d.o -o program a.o b.o c.o: program.h По команде make будет создан файл program. При первом выполнении получим на экране дисплея: - 9 - cc -c a.c cc -c b.c cc -c c.c as - -o d.o d.s cc a.o b.o c.o d.o -o program Обратите внимание на то, что интерпретатор определил необхо- димые действия над исходными файлами с суффиксами имен .c и .s, хотя имена этих файлов в Make-программе не указаны, и правильно осуществил сборку программы. Теперь, допустим, мы вызываем make на выполнениe второй раз после редактирования файла program.h, при этом получим: cc -c a.c cc -c b.c cc -c c.c cc a.o b.o c.o d.o -o program Если выполнить Make-программу после редактирования файла b.c, то получим: cc -c b.c cc a.o b.o c.o d.o -o program Наконец, если, допустим, необходимо получить файл c.o, то можно выполнить команду make c.o Механизм умолчаний и обработки суффиксов спроектирован для автоматизации программирования Make-программ; он существенно сокращает размеры программ и количество ошибок в них. 3. Соглашения языка Make Ниже в компактной форме приводятся основные синтакси- ческие конструкции языка Make. В следующих параграфах по каждой конструкции будут даны описания и примеры. идентификатор последовательность букв, цифр и символа "_", содержащая шаблоны имен файлов ([...], ?, *), символы / и "." идентификатор = значение определение макропеременной. В правой части могут быть макроподстановки, а также вся правая часть может быть пустой строкой. $(идентификатор) ${идентификатор} $символ - 10 - подстановка значения макропеременной. Специальное зна- чение символа $ можно отменить, указывая $$. комментарий текст, следующий за символом # и до конца строки. Спе- циальное значение символа # отменяется, если он указан в кавычках. обратная наклонная черта символ продолжения строки. Специальное значение сим- вола \ отменяется, если он указан дважды. пустая строка, пробелы пробелы служат разделителями слов в командной строке, лишние пробелы и табуляции игнорируются. Пустая строка всюду игнорируется. список_зависимостей список_действий правило в общем виде. Список_действий может быть пус- тым. .первый_суффикс.второй_суффикс: список_действий правило с указанием зависимостей суффиксов. Если в Make-программе содержится хотя бы одно правило с суф- фиксами, отличными от предопределенных, в нее необхо- димо включить правило: .SUFFIXES: список_суффиксов список_целей :[:] список_подцелей список_зависимостей. Список_подцелей может быть пус- тым. Правила с одним и двумя символами двоеточия в списке_зависимостей отличаются порядком выполнения списка_подцелей и списка_действий. имя_цели [имя_цели] список_целей. Имя_цели - идентификатор. Можно исполь- зовать символ / и точку. Имя_цели может быть именем файла или каталога, тогда включается выполнение меха- низма реконструкции. Имя_цели может не быть именем файла, тогда механизм реконструкции не включается, а имя_цели является меткой (именем правила, входа в Make-программу). имя_подцели [имя_подцели] [#комментарий] список_подцелей. Имя_подцели - идентификатор. Можно - 11 - использовать шаблоны имен файлов "*", "?", [...], сим- вол / и точку. Имя_подцели может быть именем файла, для которого записано или не записано правило в Make- программе, в этих случаях включается механизм реконст- рукции. Имя_подцели может не быть именем файла, в этом случае механизм реконструкции не включается, а имя_цели является меткой (именем правила, входа в Make- программу). строка_действия [#комментарий] ............... строка_действия [#комментарий] список_действий. Любые командные строки ДЕМОС и управ- ляющие конструкции Shell. 'табуляция'командная_строка_shell строка_действия. Строка_действия может быть указана в строке зависимос- тей через символ ";". Строку_действия можно указывать в следующих форматах: 'табуляция'командная__строка__shell 1 'табуляция'@командная_строка__shell 2 'табуляция'-командная_строка__shell 3 'табуляция'-@командная_строка_shell 4 В первом формате командная строка выводится на печать; если код возврата после ее выполнения не 0, make прек- ращает выполнение программы по ошибке. Во втором фор- мате командная строка не выводится на печать; если код возврата после ее выполнения не 0, make прекращает выполнение программы по ошибке. В третьем формате командная строка выводится на печать; если код возврата после ее выполнения не 0, make игнорирует ошибку и выполнение программы продолжается. В четвертом формате командная строка не выводится на печать; если код возв- рата после ее выполнения не 0, make игнорирует ошибку и выполнение программы продолжается. Простая командная строка (одна команда ДЕМОС с аргументами) выполняется без порождения оболочки. Другие командные строки выполняются sh следующим образом: sh -c командная_строка_shell Для сокращения обозначений предусмотрены макроперемен- ные с предопределенными именами. В правиле без суффиксов - 12 - строка_действия может включать следующие предопределенные макропеременные: @ имя цели; ? имена файлов из списка подцелей, которые МОЛОЖЕ файла_цели. Эти файлы участвуют в реконструкции цели. В правиле с суффиксами строка_действия может включать следующие предопределенные макропеременные: * основа_имени_цели; @ основа_имени_цели.второй_суффикс; <&lt; основа_имени_цели.первый_суффикс. 4. Использование макропеременных При выполнении Make-программы значения макропеременных устанавливаются в строках макроопределений и/или в командной строке при запуске make на исполнение. Кроме того, сущест- вуют макропеременные с предопределенными именами, значения которых устанавливаются при выполнении Make-программы. К ним относятся: макропеременная @, ее значение - имя_цели; макро- переменная ?, ее значение - имена тех файлов_подцелей, кото- рые МОЛОЖЕ файла_цели. Предопределенные макропеременные "@" и "?" используются только в списке действий правила и в каждом правиле имеют свои значения. Определять значения макропеременных можно в любом месте Make-программы, но не внутри правила. Интерпре- татор make составляет список имен макропеременных и присваи- вает им значения в процессе чтения Make-программы. Если зна- чение макропеременной переопределяется, то ей присваивается новое значение; если используются макроопределения с вложен- ными макроподстановками, то значения устанавливаются с уче- том всех присвоений в Make-программе. Если значение макро- переменной задается в командной строке при запуске Make- программы на исполнение, то все определения этой макропере- менной в Make-программе игнорируются и используется значе- ние, взятое из командной строки. Состояние ошибки порожда- ется, если используется рекурсия при присвоении значения макропеременным. Например, A = $B B = $A приведет к аварийному завершению выполнения Make-программы. В макроопределениях можно использовать метасимволы шаб- лонов имен файлов shell. Допустим, рабочий каталог имеет - 13 - вид: -rw-r--r-- 1 user 15658 Авг 6 16:03 1.m -rw-r--r-- 1 user 2158 Авг 8 16:38 2.m -rw-r--r-- 1 user 5185 Авг 9 17:38 3.m -rw-r--r-- 1 user 4068 Июл 28 20:56 6.m -rw-r--r-- 1 user 100 Авг 9 14:30 f2 -rw-r--r-- 1 user 66 Авг 9 17:42 f3 Пример Make-программы в Makefile : A = * B = f? C = [0-9].* aaa : echo $A echo $B echo $C После выполнения команды make -s получим на экране дисплея: 1.m 2.m 3.m 6.m f2 f3 f2 f3 1.m 2.m 3.m 6.m В Make-программе часто бывает необходимо манипулировать име- нами каталогов и файлов. Механизм макроподстановок предла- гает удобные средства для этого. Пример: A = * B = [pg]* C = f?r* DIR1 = . DIR2 = /etc DIR3 = /usr/bin aaa : echo ${DIR1}/$A echo ${DIR2}/$B echo ${DIR3}/$C После выполнения получим: ./1.m ./2.m ./3.m ./6.m ./f2 ./f3 /etc/getty /etc/group /etc/passwd /usr/bin/fgrep Рассмотрим пример, в котором демонстрируются всевозмож- ные способы использования макропеременных. Допустим, имеется Makefile - 14 - БИБЛИОТЕКА = ПОЛКА ${ДРУГОЕ} ДРУГОЕ = Документы Шкаф = ПОЛКА папка = справки, копии. СПРАВОЧНИКИ = ЖУРНАЛЫ = Словари = толковые, иностранных языков. ТЕХНИЧЕСКАЯ = $(СПРАВОЧНИКИ) $(Словари) ХУДОЖЕСТВЕННАЯ = проза, поэзия, драматургия. t = Справка с места жительства. x = Копия свидетельства о рождении. файлы = d e библиотека : ${БИБЛИОТЕКА} echo 'Действия правила' $@ echo '$$? - список подцелей :' $? echo '$$@ - имя цели :' $@ echo 'Техническая : ' $(ТЕХНИЧЕСКАЯ) echo 'Худ. : ' $(ХУДОЖЕСТВЕННАЯ) echo ' ' ${Шкаф} : b c echo 'Действия правила' $@ echo '$$? - список подцелей :' $? echo '$$@ - имя цели :' $@ echo ' ' ${ДРУГОЕ}: ${файлы} echo 'Действия правила' $@ echo '$$? - список подцелей :' $? echo '$$@ - имя цели :' $@ echo 'Папка : ' ${папка} echo $t echo $x echo ' ' b: c: d: e: Следует обратить внимание на то, что $буква используется для подстановки значения макропеременной, имя которой состоит из одной буквы, а $(идентификатор) и ${идентификатор} равно- ценны. Правила b, c, d и e включены исключительно для демонстрации значений макропеременной "?". Теперь, если выполнить команду make -s, получим на экране дисплея: - 15 - Действия правила ПОЛКА $? - список подцелей : b c $@ - имя цели : ПОЛКА Действия правила Документы $? - список подцелей : d e $@ - имя цели : Документы Папка : справки, копии. Справка с места жительства. Копия свидетельства о рождении. Действия правила библиотека $? - список подцелей : ПОЛКА Документы $@ - имя цели : библиотека Техническая :толковые, иностранных языков. Худ. : проза, поэзия, драматургия. В командной строке можно присвоить значение макропеременной. После команды make -s Словари = английский, немецкий. получим на экране дисплея: Действия правила ПОЛКА $? - список подцелей : b c $@ - имя цели : ПОЛКА Действия правила Документы $? - список подцелей : d e $@ - имя цели : Документы Папка : справки, копии. Справка с места жительства. Копия свидетельства о рождении. Действия правила библиотека $? - список подцелей : ПОЛКА Документы $@ - имя цели : библиотека Техническая : английский, немецкий. Худ. : проза, поэзия, драматургия. 5. Выполнение правил в Make-программе Существует несколько разновидностей правил: с одним и двумя двоеточиями; с одинаковыми именами целей; не содержащие списка действий; - 16 - не содержащие списка подцелей и/или списка действий; правила, предопределенные в интерпретаторе make, кото- рые программист может включать в Make-программу. Кроме того, имеются некоторые различия в выполнении Make-программы, когда имя цели не является файлом. В общем случае правило может содержать одно или два двоеточия в качестве разделителей списков целей и подцелей. Порядок выполнения в этих правилах одинаков, если в них указаны раз- личные имена целей. Правило выполняется следующим образом: сначала выполня- ются правила с именами целей из списка подцелей, затем спи- сок действий. Если в списке подцелей указано имя файла, для которого правило не определено, то время создания (модифика- ции) файла используется для определения необходимости реконструкции цели. Если имя подцели не является файлом, оно должно быть меткой правила, иначе порождается состояние ошибки. Допустим, в Make-программе записано правило monitor.c : monitor.h Это означает, что файл monitor.c зависит от файла monitor.h. Если monitor.h действительно имеется в рабочем каталоге, то любые изменения в нем приведут к реконструкции файла monitor.o, если файл monitor.h отстутствует, make прекращает выполнять программу по ошибке. В Make-программе могут встречаться случаи, когда необходимо для одной цели записать несколько правил, тогда существенно важно, сколько двоеточий указано в правиле. Ниже приведены схемы, в которых цифрами показан порядок выполнения этих правил. Порядок выполнения нескольких правил с одинаковым именем_цели и одним двоеточием: сначала выполняются правила, связанные со списками подцелей, затем список_действий одного из правил. Список действий разрешается указывать только в одном из таких правил: имя_цели_А : список_подцелей <---| 1 | имя_цели_А : список_подцелей <---| 2 | список_действий <---| 4 | имя_цели_А : список_подцелей <---| 3 | Порядок выполнения нескольких правил с одинаковым именем_цели и двумя двоеточиями. Список действий может быть в каждом правиле: - 17 - имя_цели_А :: список_подцелей <---| 1 | список_действий <---| 2 | имя_цели_А :: список_подцелей <---| 3 | список_действий <---| 4 | имя_цели_А :: список_подцелей <---| 5 | список_действий <---| 6 | 6. Режимы выполнения Make-программы Интерпретатор make предоставляет ряд возможностей для управления выполнением Make-программы. Для этой цели исполь- зуются следующие директивы: .SILENT - не печатать строки действий; .IGNORE - игнорировать ошибки действий; .DEFAULT - выполнить альтернативное действие; .PRECIOUS - удалить недостроенный файл. Директивы .SILENT и .IGNORE можно указывать как в Make- программе, так и в командной строке ключами -s и -i, DEFAULT и PRECIOUS только в Make-программе. Допустим имеется следу- ющая Make-программа: aa: bb echo Действия правила $@ bb: echo Действия правила $@ ppp # Несуществующая команда sort e # Нет файла e После выполнения получим сообщения: echo Действия правила bb Действия правила bb ppp # Несуществующая команда sh: ppp: не найден *** Код ошибки 1 Конец. Интерпретатор make прекратил работу по первой ошибке. Кроме того, на экран дисплея выводятся строки действий. Отменить вывод строк действий можно следующими способами: указать ключ -s в командной строке при запуске make; указать в Make-программе директиву SILENT; - 18 - начинать каждую строку действий символом @. В первых двух случаях результат одинаков - не будут выводиться строки действий. В третьем случае не будут выво- диться строки действий вида 'табуляция'@строка_действий Пример использования директивы SILENT. aa: bb echo Действия правила $@ bb: echo Действия правила $@ ppp # Несуществующая команда sort e # Нет файла e .SILENT: После выполнения программы получим: Действия правила bb sh: ppp: не найден *** Код ошибки 1 Конец. По любой ошибке make прекратит выполнение программы. Сущест- вуют следующие способы игнорирования ошибок (Make-программа продолжает выполняться): указать ключ -i при запуске make на выполнение; указать в Make-программе директиву IGNORE; после символа табуляция указать символ "-". В первом и втором случаях будут проигнорированы все ошибки при выполнении строк действий, в третьем игнорируются ошибки в тех строках действия, которые указаны следующим образом: 'табуляция'-строка_действий Пример использования директив SILENT и IGNORE. Обработка ошибок при выполнении действий в правилах - 19 - aa: bb echo Действия правила $@ bb: echo Действия правила $@ ppp # Несуществующая команда sort e # Нет файла e .SILENT: .IGNORE: После выполнения программы получим: Действия правила bb sh: ppp: не найден *** Код ошибки 1 (игнорирован) sort: не могу открыть e *** Код ошибки 1 (игнорирован) Действия правила aa Правило DEFAULT используется для указания альтернативных действий по отсутствующему в данный момент файлу. Правило DEFAULT позволяет записать список действий, которые будут выполняться для всех отсутствующих файлов, поэтому требуется определенная осторожность, например: - 20 - aa: bb echo Действия правила $@ bb: a b c d echo Действия правила $@ ppp # Несуществующая команда sort e # Нет файла e .SILENT: .IGNORE: .DEFAULT: echo Действия правила .DEFAULT для $@ После выполнения программы получим: Действия правила .DEFAULT для a Действия правила .DEFAULT для b Действия правила .DEFAULT для c Действия правила .DEFAULT для d Действия правила bb sh: ppp: не найден *** Код ошибки 1 (игнорирован) sort: не могу открыть e *** Код ошибки 1 (игнорирован) Действия правила aa Часто бывает необходимо прекратить выполнение Make- программы. Это не приведет к фатальным последствиям, так как сохраняется структура динамических (зависящих от вре- мени) связей файлов. Однако, если создание некоторого файла не завершилось и он тем не менее образовался, его желательно удалить перед повторным запуском интерпретатора. Это можно сделать автоматически, используя директиву PRECIOUS, напри- мер: aaa: file sort file > $@ .PRECIOUS: Если в момент синхронного исполнения Make-программы ввести сигнал CTRL/C, файл $@ будет удален. 7. Правила с суффиксами В Make-программе можно записать одно правило для обра- ботки различных файлов. В этом случае это одно правило мно- гократно выполняется для различных файлов, что существенно сокращает размеры Make-программ, упрощает их разработку. Все полезные свойства make при этом сохраняются. Механизм - 21 - выполнения таких правил строится на суффиксах имен файлов. Допустим, из файла с именем основа.суффикс_1 необходимо получить файл с именем основа.суффикс_2, тогда обычное пра- вило будет выглядеть так: основа.суффикс_2 : основа.суффикс_1 список действий Понятно, что для группы файлов, основы имен которых раз- личны, а первый и второй суффиксы имен одинаковы, желательно было бы записать одно правило обработки. Например, файлы *.c обычно преобразуются в файлы *.o одним списком действий, и, следовательно, эти правила желательно записывать в виде одного правила. Интерпретатор make предлагает эту возмож- ность в правилах вида .суффикс_1.суффикс_2: список_действий .SUFFIXES: .суффикс_1 .суффикс_2 Если в Make-программе записаны эти правила, интерпретатор, получив в качестве аргумента имя файла с именем основа.суффикс_1, выполнит указанное выше правило, и мы получим результат - файл с именем основа.суффикс_2. Поря- док выполнения правила с суффиксами такой же, как и в обыч- ном правиле. Предопределенное правило SUFFIXES используется для указания списка суффиксов, который может содержать более двух суффиксов. Порядок суффиксов в списке роли не играет. Естественно, для каждой пары суффиксов в Make-программе должны быть записаны соответствующие правила. В правилах с суффиксами используются предопределенные макропеременные: @ - имя_результатa (основа.суффикс_2); <&lt; - имя_аргументa (основа.суффикс_1); * - основа. Рассмотрим пример. Допустим, имеются исходные файлы *.c и *.k. Необходимо из них получить файлы *.t, а из них - файл result. Допустим также, что файлы *.c зависят от файла file.h (содержат строку #include file.h). Граф преобразова- ний файлов в этом случае выглядит так: - 22 - result | .t | -------- | | .c .k Программа, реализующая этот граф, может быть следующей: - 23 - result: d.t a.t b.t c.t echo 'Действия правила' $@ echo ' Значение $$@ - ' $@ echo ' Значение $$? - ' $? touch $@ .k.t : echo 'Действия правила .k.t :' echo ' Значение $$* - ' $* echo ' Значение $$@ - ' $@ echo ' Значение $$? - ' $? echo ' Значение $$< - ' $< touch $@ .c.t : echo 'Действия правила .c.t :' echo ' Значение $$* - ' $* echo ' Значение $$@ - ' $@ echo ' Значение $$? - ' $? echo ' Значение $$< - ' $< touch $@ a.c b.c c.c : file.h .SUFFIXES: .t .c .k После выполнения команды make -rs получим: Действия правила .k.t : Значение $* - d Значение $@ - d.t Значение $? - d.k Значение $< - d.k Действия правила .c.t :