Интерпретатор 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 -
строка_действия может  включать  следующие  предопределенные
макропеременные:
@    имя цели;
?    имена  файлов  из  списка  подцелей,   которые   МОЛОЖЕ
     файла_цели.  Эти файлы участвуют в реконструкции цели.
     В правиле с суффиксами строка_действия  может  включать
следующие предопределенные макропеременные:
*    основа_имени_цели;
@    основа_имени_цели.второй_суффикс;
<<    основа_имени_цели.первый_суффикс.
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);
<<    - имя_аргумент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 :