Производственно-внедренческий кооператив

"И Н Т Е Р Ф Е Й С"













Диалоговая Единая Мобильная

Операционная Система

Демос/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
$@ - имя цели : ПОЛКА

Действия правила Документы