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

                    "И Н Т Е Р Ф Е Й С"













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

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

                        Демос/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 :
       Значение $* -  a
       Значение $@ -  a.t
       Значение $? -  file.h a.c
       Значение $< -  a.c

      Действия правила .c.t :
       Значение $* -  b
       Значение $@ -  b.t
       Значение $? -  file.h b.c
       Значение $< -  b.c

      Действия правила .c.t :
       Значение $* -  c
       Значение $@ -  c.t
       Значение $? -  file.h c.c
       Значение $< -  c.c

      Действия правила result


                           - 24 -










       Значение $@ -  result
       Значение $? -  d.t a.t b.t c.t

Заметим, что правило .k.t выполняется только один раз,  пра-
вило  .c.t - три раза, как и требовалось для списка исходных
файлов, указанных в списке подцелей  правила  result.  Смысл
макропеременной  "?"  в  правиле с суффиксом тот же, что и в
обычном файле - список подцелей. Макропеременная "@" в обыч-
ном правиле - имя цели, а здесь имя результата - файл с име-
нем основа.суффикс_2.

     Интерпретатор make содержит список правил для стандарт-
ных  суффиксов  имен  файлов  и определения самих суффиксов.
Этот список подключается к Make-программе пользователя, если
make  запускается  на  выполнение без ключа -r.  Программист
полностью освобождается от  указания  правил  преобразований
файлов  со  стандартными  суффиксами  имен.   Обрабатываются
файлы, имена которых включают следующие суффиксы:

     .out   -    файл в загрузочном формате;
     .o     -    объектный файл;
     .c     -    файл на языке Си;
     .f     -    файл на языке Фортран;
     .p     -    файл на языке Паскаль;
     .s     -    файл на ассемблере;
     .l     -    файл на lex;
     .y     -    файл на yacc;

Кроме того,  в  Make-программу  включаются  предопределенные
макропеременные:

LOADLIBES =   # имена библиотек
AS = as -     # имя ассемблера
CC = cc       # имя Си-компилятора
CFLAGS =      # ключи Си-компилятора
PC = pc       # имя Паскаль-компилятора
PFLAGS =      # ключи Паскаль-компилятора
FF = f77      # имя f77-компилятора
FFLAGS =      # ключи f77-компилятора
LEX = lex     # имя генератора
LFLAGS =      # ключи lex
YACC = yacc   # имя генератора
YFLAGS =      # ключи yacc

Значения предопределенных  макропеременных  можно  менять  в
Make-программе,  например,  если ввести строку  CFLAGS = -O,
то предопределенная макропеременная CFLAGS будет иметь новое
значение  в Make-программe.  Ниже приводятся граф зависимос-
тей целей и список правил Make-программы, реализующей  обра-
ботку файлов по суффиксам имен.





                           - 25 -










             .c   .f   .p   .s   .l   .y
              |    |    |    |    |    |
              |-------------------------
              |
              |
              --->  .out    <--- .o  ---
                                       |
                                       |
              --------------------------
             |    |    |    |    |    |
            .p   .f   .c   .s   .l   .y
                       |
                      ---
                     |   |
                    .l  .y








































                           - 26 -










 .l.out:
       $(LEX) $<
       $(CC) $(CFLAGS) lex.yy.c $(LOADLIBES) -ll -o $@
       rm lex.yy.c

 .y.out:
       $(YACC) $(YFLAGS) $<
       $(CC) $(CFLAGS) y.tab.c  $(LOADLIBES) -ly -o $@
       rm y.tab.c

 .f.out:
       $(FF) $(FFLAGS) $< $(LOADLIBES) -o $@
       -rm $*.o

 .o.out:
       $(CC) $(CFLAGS) $< $(LOADLIBES) -o $@

 .c.out:
       $(CC) $(CFLAGS) $< $(LOADLIBES) -o $@

 .p.out:
       $(PC) $(PFLAGS) $< $(LOADLIBES) -o $@

 .s.out:
       $(CC) $(CFLAGS) $< $(LOADLIBES) -o $@

 .l.c:
       $(LEX) $<
       mv lex.yy.c $@

 .y.c:
       $(YACC) $(YFLAGS) $<
       mv y.tab.c $@

 .l.o:
       $(LEX) $(LFLAGS) $<
       $(CC) $(CFLAGS) -c lex.yy.c
       rm lex.yy.c; mv lex.yy.o $@

 .y.o:
       $(YACC) $(YFLAGS) $<
       $(CC) $(CFLAGS) -c y.tab.c
       rm y.tab.c; mv y.tab.o $@

 .s.o:
       $(AS) -o $@ $<

 .f.o:
       $(FF) $(FFLAGS) -c $<

 .c.o:
       $(CC) $(CFLAGS) -c $<



                           - 27 -










 .p.o:
       $(PC) $(PFLAGS) -c $<

 .SUFFIXES: .out .o .c .f .p .y .l .s

Допустим, имеются файлы f[1-6].c с исходными текстами  прог-
раммы result. Файлы f[1-3].c содержат строки

    # include file1.h
    # include file2.h

    и файлы f[4-6].c содержат строку

    # include file3.h

Следующая программа управляет созданием программы result:

 CFLAGS = -O
 LDFLAGS = -s -n -o
 OBJS = f1.o f2.o f3.o f4.o f5.o f6.o

 result:  ${OBJS}
        ${CC} ${OBJS} ${LDFLAGS} $@

 f1.o f2.o f3.o : file1.h  file2.h

 f4.o f5.o f6.o : file3.h

Так выглядит протокол выполнения:

 cc -O -c f1.c
 cc -O -c f2.c
 cc -O -c f3.c
 cc -O -c f4.c
 cc -O -c f5.c
 cc -O -c f6.c
 cc f1.o f2.o f3.o f4.o f5.o f6.o -s -n -o result

Теперь изменим время модификации файла командой

    touch file3.h

и снова выполним программу, в результате получим:

     cc -O -c f4.c
     cc -O -c f5.c
     cc -O -c f6.c
     cc f1.o f2.o f3.o f4.o f5.o f6.o -s -n -o result

Теперь изменим время модификации файла командой touch f3.c и
снова выполним программу




                           - 28 -










     cc -O -c f3.c
     cc f1.o f2.o f3.o f4.o f5.o f6.o -s -n -o result

Программист может отключить стандартные определения и список
правил  с суффиксами (ключ -r), может их использовать наряду
с теми, что определены в Make-программе. Допустим,  к  имею-
щимся  файлам  предыдущего  примера  добавляются файлы a1.t,
a2.t и a3.t, их необходимо обработать программой sed,  выхо-
дом  которой  будут  файлы  a1.c  a2.c  a3.c.   Теперь Make-
программа выглядит так:

     CFLAGS = -O
     LDFLAGS = -o
     OBJS = a1.o a2.o a3.o f1.o f2.o f3.o f4.o f5.o f6.o

     result:  ${OBJS}
            ${CC} ${OBJS} ${LDFLAGS} $@

     f1.o f2.o f3.o : file1.h  file2.h

     f4.o f5.o f6.o : file3.h

     a1.c: a1.t

     a2.c: a2.t

     a3.c: a3.t

     .t.c:
           sed s/aaa/bbb/ < $< > $*.c

     .SUFFIXES: .t

Протокол выполнения программы:

 sed s/aaa/bbb/ < a1.t > a1.c
 cc -O -c a1.c
 sed s/aaa/bbb/ < a2.t > a2.c
 cc -O -c a2.c
 sed s/aaa/bbb/ < a3.t > a3.c
 cc -O -c a3.c
 cc -O -c f1.c
 cc -O -c f2.c
 cc -O -c f3.c
 cc -O -c f4.c
 cc -O -c f5.c
 cc -O -c f6.c
 cc a1.o a2.o a3.o f1.o f2.o f3.o f4.o f5.o f6.o -o result

Make допускает обработку суффиксов только одного уровня вло-
женности.  В  правиле SUFFIXES указан только суффикс t, суф-
фикс c определен в подключаемом списке суффиксов.



                           - 29 -










8.  Управление архивом в Make-программе

     В ДЕМОС существуют два типа  архивов:  архив  текстовых
файлов  и  архив объектных файлов (имеющий структуру библио-
теки объектных модулей).   Созданный  архив  является  одним
файлом,  а  файлы, из которых он собран, образуют его части.
Управление   архивом   включает   две    задачи:    создание
файла_архива   определенной   структуры  и  его  модификация
(добавление, удаление и замена частей, изменение  структуры,
декомпозиция  архива на файлы, из которых он был образован).
Для решения таких задач Make-программа  должна  обеспечивать
работу  с целями двух типов: файл_архив и файл для включения
в архив.  При этом оценивается время  последней  модификации
включаемого  в  архив  файла (а не время создания архива или
записи файла_части в архив).  Имя файла_архива может  указы-
ваться в списке зависимостей правил как обычная цель:

    имя_архивного_файла(имя_файла_для_включения_в_архив)

Кроме имен файлов, при работе с библиотекой объектных  моду-
лей можно указывать имена функций

    имя_файла_библиотеки((_внешнее_имя_библ_функции))

Рассмотрим фрагмент Make-программы для построения библиотеки
с именем libP.a:

    L      =   libP.a
    CFLAGS =  -O

    $(L)::
           ar r $(L)

    $(L):: $(L)(Ia.o) $(L)(La.o) $(L)(Da.o)

    # Iabs, Labs, Dabs - имена функций

    $(L)(Iabs.o):     lib/Ia.c
           $(CC) $(CFLAGS) lib/Ia.c
           ar r $(L) Ia.o
           -rm -f Ia.o

    $(L)(Labs.o):     lib/La.c
           $(CC) $(CFLAGS) lib/La.c
           ar r $(L) La.o
           -rm -f La.o

    $(L)(Dabs.o):     lib/Da.c
           $(CC) $(CFLAGS) lib/Da.c
           ar r $(L) Da.o
           -rm -f Da.o

У такого способа работы  с  библиотекой  есть  недостаток  -


                           - 30 -










Make-программа должна содержать структуру библиотеки. Список
имен библиотечных модулей во втором правиле  "$(L)::"  соот-
ветствует порядку их размещения в библиотеке.  Еще одно неу-
добство заключается в том, что если бы библиотека  содержала
большое  количество  модулей, например 100, то потребовалась
бы запись 100 правил в программе.  Для  построения  однопро-
ходных  библиотек  такой  способ  указания  структуры  имеет
существенный недостаток, так как изменение исходного  текста
объектного  модуля  может  привести к необходимости изменить
структуру библиотеки, а это,  в  свою  очередь,  приведет  к
необходимости  реконструировать Make-программу.  Кроме того,
при построении библиотеки необходимо,  чтобы  все  объектные
файлы были в рабочем каталоге.

     Рассмотрим Make-программу,  в  которой  эти  недостатки
устранены.   Возьмем  в  качестве  примера файлы с исходными
текстами модулей объектной библиотеки mylib

    m1.c m2.c m3.c m4.s m5.c m6.c m7.s

Допустим, структура однопроходной библиотеки с учетом  вызо-
вов модулей должна быть такой:

    m4.o m2.o m1.o m5.o m6.o m7.o m3.o

Текст Make-программы:





























                           - 31 -










    CFLAGS = -O
    SRC    =  m1.c m2.c m3.c m4.s m5.c m6.c m7.s
    LIB    =  mylib

    ${LIB}:  ${SRC}
         echo $? | sed s/\\.[cs]/\\.o/g > list
         make `cat list`
         ar cr $@ `cat list`
         lorder $@ | tsort > list
        -@if cmp list topology ; \
         then \
             rm -f `cat list` list;\
         else \
             ar x ${LIB}; rm $@;\
             mv list topology;\
             ar cr $@ `cat topology`;\
             rm -f `cat topology`;\
             echo Структура $@ изменилась.;\
         fi
         ranlib ${LIB}
         echo Библиотека $@ готова.

    m1.c : x.h
            touch m1.c

    m2.c : x.h y.h
            touch m2.c

    m3.c : x.h
            touch m3.c

    m5.c : y.h
            touch m5.c

    m6.c : x.h
            touch m6.c

Рассмотрим простые  случаи  реконструкции  уже  существующей
библиотеки.   Допустим,  изменился  исходный текст одного из
модулей. В этом случае достаточно на его место в  библиотеке
включить  новую версию объeктного файла этого модуля.  Чтобы
не компилировать другие файлы библиотеки, можно использовать
предопределенную  макропеременную "?" - список файлов, кото-
рые стали МОЛОЖЕ файла mylib. Как  уже  говорилось  выше,  в
каталоге   нет  объектных  файлов.  Следовательно,  в  Make-
программу  необходимо  включить  предопределенные   средства
обработки  суффиксов, а в качестве аргумента формировать имя
цели с суффиксом o,  тогда make автоматически построит новый
объектный  файл  этого модуля. В примере файл list использу-
ется в качестве временного рабочего файла. Строка вида

    echo $? | sed s/\\.[cs]/\\.o/g > list



                           - 32 -










записывает  в файл list список целей с суффиксом o. Редактор
sed  используется в этой командной строке для замены суффик-
сов c и s на o.  Таким образом,  файл  list  содержит  имена
файлов-целей,  которые  необходимо  создать и на этой основе
реконструировать библиотеку. Это  можно  сделать,  например,
так:

    make `cat list`

В  результате  выполнения  будут  созданы  нужные  объектные
файлы.   После этого можно включить объектные модули на свои
места в библиотеке mylib

    ar rc mylib `cat list`

Если же библиотека mylib отсутствует,то она создается,  если
модуль  в библиотеке исходно отсутствовал, он записывается в
конец библиотеки (так работает команда ar с ключами cr).

     По команде "make `cat list`" выполняться будет Makefile
(здесь  срабатывает  механизм  умолчания имени файла с Make-
программой). Таким образом, имеет  место  рекурсивный  вызов
Make-программы.   При  рекурсивном  вызове  в  качестве имен
целей  передаются имена объектных файлов, которые необходимо
получить и включить в библиотеку.  В интерпретаторе make нет
средств, позволяющих менять список целей в процессе выполне-
ния Make-программы.  Когда это необходимо, список целей соз-
дается в Make-программе и передается на выполнение как  спи-
сок  аргументов при вызове подпрограммы.  Рекурсия в примере
понадобилась для того, чтобы  не  записывать  полный  список
правил  для  всех  файлов-целей, а вызвать make с актуальным
списком аргументов.

     Возможна такая реконструкция библиотеки, когда меняется
ее  структура.   Для  этого  в  Make-программе  используются
команды lorder и tsort.  Lorder выводит список вызовов моду-
лей  существующей  библиотеки, а tsort сортирует этот список
таким образом, чтобы структура библиотеки была  непротиворе-
чивой,  т.е.  однопроходный  редактор  связей мог бы за одно
чтение библиотечного файла найти все необходимые модули.   В
Make-программу   включаются  действия,  в  которых  строится
структура библиотеки во временном файле list и  запоминается
в  сохраняемом  файле  topology.  Возможны  следующие случаи
реконструкции библиотеки:

     Реконструкция библиотеки не изменила  ее  структуры,  в
этом случае файл topology не отличается от файла list.

     Реконструкция изменила  структуру  библиотеки.  В  этом
случае  файл  topology отличается от файла list и требуется,
во-первых, получить верную структуру и запомнить ее в  файле
topology,  во-вторых,  извлечь  из  библиотеки все объектные
модули (разобрать библиотеку и удалить файл с  библиотекой),


                           - 33 -










затем  собрать ее в соответствии с новой структурой.  Разоб-
рать библиотеку можно командой

    ar x mylib

В рабочем каталоге будут созданы копии объектных модулей  из
библиотечного файла. Библиотечный файл при этом сохраняется.
Разобранную  библиотеку  можно  собрать  заново,   используя
информацию   о  структуре  библиотеки  в  файле  topology  и
команду:

    ar rc mylib `cat topology`

В shell допускается  записать  if  одной  строкой  следующим
образом:

    if     список_команд;\
    then \
           список_команд;\
    else \
           список_команд;\
    fi

В Makefile эта конструкция записана:

    -@if cmp list topology ; \
      then \
          rm -f `cat list` list;\
      else \
          ar x $(LIB); rm $@;\
          mv list topology;\
          ar cr $@ `cat topology`;\
          rm -f `cat topology`;\
          echo Структура $@ изменилась.;\
      fi

Первая строка в ней выглядит так:

     'табуляция'-@if cmp list topology ; \

Остальные строки имеют более 8 ведущих пробелов.  Символ "-"
указан,  так  как  в отдельных версиях shell оператор if при
нормальном завершении возвращает не 0. Символ  "@"  отменяет
вывод этой строки перед выполнением.

     Приведенная Make-программа позволяет работать с  любыми
объектными  библиотеками.  Для  конкретной  библиотеки  (или
архива) нужно изменить макропеременные LIB, SRC  и  записать
зависимости от файлов включений.  Если необходимо работать с
текстовыми архивами, то достаточно  удалить  строку   ranlib
$@.   Рассмотрим  на примерах работу программы при различных
исходных условиях.



                           - 34 -










     Библиотеки нет, структура неизвестна

     make -s
     cc  -c m1.c
     cc  -c m2.c
     cc  -c m3.c
     as - -o m4.o m4.s
     cc  -c m5.c
     cc  -c m6.c
     as - -o m7.o m7.s
     cmp: не могу открыть topology
     Структура mylib изменилась.
     Библиотека mylib готова.


     Библиотека mylib имеется, структура остается без  изме-
нений, модифицируется файл x.h

     touch x.h
     make -s
     cc  -c m1.c
     cc  -c m2.c
     cc  -c m3.c
     cc  -c m6.c
     Библиотека mylib готова.


     Меняется содержимое библиотечного модуля  m5.c.   Меня-
ется  структура библиотеки: модуль m5 вызывает теперь модуль
m1

     make -s
     cc  -c m5.c
     Структура mylib изменилась.
     Библиотека mylib готова.

В файле topology теперь новая структура библиотеки

    m4.o m2.o m5.o m1.o m6.o m7.o m3.o


     Добавляется новый модуль в библиотеку.  Придется  изме-
нить  строку  SRC в Make-программе.  Имя модуля m8.c , вызы-
вает  он модуль m5.c

     cc  -c m8.c
     list topology различны: char 12, line 3
     Структура mylib изменилась.
     Библиотека mylib готова.

В файле topology теперь новая структура библиотеки

    m4.o m2.o m8.o m5.o m1.o m6.o m7.o m3.o


                           - 35 -










     Изменим модуль m1.c так, чтобы он вызывал модуль  m2.c,
а модуль m2.c вызывал m1.c, т.е. получается зацикленная вза-
имная зависимость библиотечных модулей m1 и m2

     make -s
     cc  -c m1.c
     tsort: зацикленная зависимость
     tsort: m2.o
     tsort: m1.o
     Структура mylib изменилась.
     Библиотека mylib готова.

Команда tsort вывела сообщение об ошибке в структуре библио-
теки.   Библиотека собрана, но пользоваться ею нельзя, необ-
ходимо исправить структуру модуля.  Удалять  файл  mylib  не
нужно,  так  как  он  содержит все объектные модули, которые
понадобятся для новой сборки.

9.  Особенности программирования на языке Make

     Всюду в примерах  Make-программа  размещалась  в  одном
Makefile.  Существует  возможность  разместить  ее в файле с
другим именем и при вызове интерпретатора make  указать  это
имя

    make -f имя_файла

Иногда возникает необходимость использовать несколько  Make-
файлов,  образующих  одну  Make-программу,  тогда при вызове
make можно указать

    make -f имя_файла1 -f имя_файла2 и т.д.

Указанные файлы составят текст одной  Make-программы  в  том
порядке, в котором они указаны в командной строке.

     Внутри одной  Make-программы  можно  вызывать  make  на
выполнение другой Make-программы, например:

    LLL: a b c d
          make -k -f имя_Make-файла $?

В том случае, если эта командная строка не может  быть  нор-
мально выполнена, ключ -k указывает на необходимость продол-
жить выполнение других разделов Make-программы,  которые  не
зависят  от  цели  данного  правила.  Если в этом примере не
указать имя файла, в котором  размещена  Make-программа,  то
автоматически будет выполняться Makefile и будет иметь место
рекурсивный вызов на выполнение одной программы.

     Есть некоторые особенности при использовании макропере-
менных.  Допустим, в Make-программе указана строка



                           - 36 -










    SRC = a1.c a2.c a3.c     # комментарий

Между a3.c и символом # 9 пробелов, они  будут  передаваться
всюду, где будет использовано значение макропеременной SRC.

     Предопределенные макропеременные "<" и "*"  в  правилах
без  суффиксов  не определены, и их использование может при-
вести к непредсказуемым результатам.

     Все, что указано за символом табуляция в строке  дейст-
вий  передается на выполнение shell. Однако идущие за симво-
лом  табуляция  символы  "-"  и  "@"  обрабатываются   make.
Интерпретатор  make  оптимизирует скорость выполнения дейст-
вий.  Если строка действий - простая  команда  системы,  она
выполняется  без порождения процесса shell. По этой причине,
например, такая строка вызовет состояние ошибки

     'табуляция'#cat file

Действительно,  как  бы  выполнялась  строка   "exec(#   cat
file);" в Си-программе?

     Если в списке зависимостей отсутствуют имена  подцелей,
можно  использовать сокращенную форму записи правила с одним
действием. Оно имеет вид:

    имя_цели:[:];  одна_строка_действия [# комментарий]

символ ";" обязателен.

     Особую осторожность необходимо соблюдать при указании в
Make-программе  имени  цели,  которая  не является файлом. В
этом случае программист должен учитывать, что он сознательно
исключает  возможность  использования этой цели при реконст-
рукциях, так как она не связана соотношениями времен  созда-
ния  (модификации)  с другими объектами Make-программы.  Это
препятствие можно обойти, создавая ЛОЖНЫЙ файл-цель,  напри-
мер:

    print: f1 f2 f3
           print $?
           touch print

     .DEFAULT:
           touch print

В рабочем каталоге создан пустой файл с именем print. Теперь
выводиться  на  печать будут только те файлы, которые требу-
ется распечатать как изменившиеся. Правило DEFAULT  записано
на тот случай, когда файл print отсутствует.

     Команду touch можно использовать, когда необходимо раз-
рушить  динамическую  структуру  связей  между файлами. Надо


                           - 37 -










учитывать, что при  этом  make  будет  реконструировать  все
файлы заново.

     Ниже перечислены все ключи  интерпретатора  make  и  их
действие:

-d   отладочный режим, в  котором  выводится  дополнительная
     информация о выполнении Make-программы.

-f   следующий параметр является именем Make-файла. По умол-
     чанию  ищется  Makefile или makefile. Если имеются оба,
     то выполняется Makefile. В командной строке можно  ука-
     зать несколько ключей -f и параметров.

-i   режим игнорирования кодов завершения команд  не  равных
     нулю.  Эквивалентно директиве IGNORE.

-k   если код завершения команды не равен  нулю,  прекратить
     выполнение текущего правила и перейти к выполнению дру-
     гих разделов, не зависящих от файла-цели этого правила.

-n   вывести,  но  не  выполнять   строки   действий   Make-
     программы.

-p   вывести полную информацию о структуре Make-программы.

-q   получить информацию о необходимости реконструкции цели.
     Если реконструкция указанной цели не требуется, возвра-
     щается -1, иначе 0.

-r   отменяет предопределенную обработку  правил  с  суффик-
     сами, предопределенные макропеременные и суффиксы.

-s   отменить вывод выполняемых строк.  Эквивалентно  дирек-
     тиве SILENT.

-S   прервать выполнение Make-программы при ошибочном завер-
     шении какой-либо команды.

-t   уничтожить сложившуюся структуру динамических  (завися-
     щих от времени) связей между файлами.

10.  Автоматизация программирования Make-программ

     Для создания новой  Make-программы  можно  иметь  файл-
шаблон,  добавляя в него необходимые строки мы получим гото-
вую к использованию программу.  Такой принцип  реализован  в
программе mkmf.  Рассмотрим ее работу на примере. Пусть име-
ются исходные файлы f.h, f1.c, f2.c и f3.c, из которых необ-
ходимо получить файл a.out:





                           - 38 -










     /*
     ** файл f.h
     */
     # include       <stdio.h>
     # include       <ctype.h>
     # include       <time.h>

     /*
     ** файл f1.c
     */
     # include       f.h

     main(ac, av)
     int ac;
     char **av;
     {
           f1(); f2(); f3();

     printf("Результат выполнения программы example.\n");
     }
     f1(){
           return;
     }

     /*
     ** файл f2.c
     */
     # include       f.h

     int f2(){
           return( a2());
     }
     # include       <stat.h>
     char *a2(){
          return;
     }

     /*
     ** файл f3.c
     */
     # include       f.h

     int f3(){
            return( nn());
     }

     char *nn(){
            return;
     }

Пусть все эти файлы размещены  в  одном  каталоге.  Выполним
команду  mkmf.   В  результате  ее  выполнения  будет создан
Makefile с программой сборки файла a.out:


                           - 39 -










    DEST          = .

    EXTHDRS       = /usr/include/ctype.h \
                    /usr/include/stat.h  \
                    /usr/include/stdio.h \
                    /usr/include/time.h

    HDRS          = f.h

    LDFLAGS       =

    LIBS          =

    LINKER        = cc

    MAKEFILE      = Makefile

    OBJS          = f1.o f2.o f3.o

    PRINT         = pr

    PROGRAM       = a.out

    SRCS          = f1.c f2.c f3.c

    all:            $(PROGRAM)

    $(PROGRAM): $(OBJS) $(LIBS)
                @echo -n "Сборка $(PROGRAM) ..."
                @$(LINKER) $(LDFLAGS) $(OBJS) \
                           $(LIBS) -o $(PROGRAM)
                @echo "готово."

    clean:;     @rm -f $(OBJS)

    depend:;    @mkmf -f $(MAKEFILE) \
                PROGRAM=$(PROGRAM) DEST=$(DEST)

    index:;     @ctags -wx $(HDRS) $(SRCS)

    install:    $(PROGRAM)
                @echo Установка $(PROGRAM) в $(DEST)
                @install -s $(PROGRAM) $(DEST)

    print:;     @$(PRINT) $(HDRS) $(SRCS)

    program:;   $(PROGRAM)

    tags:       $(HDRS) $(SRCS)
                @ctags $(HDRS) $(SRCS)

    update:     $(DEST)/$(PROGRAM)



                           - 40 -










    $(DEST)/$(PROGRAM): $(SRCS) $(LIBS) \
                        $(HDRS) $(EXTHDRS)
                @make -f $(MAKEFILE) \
                    DEST=$(DEST) install

    ###
    f1.o: f.h /usr/include/stdio.h \
              /usr/include/ctype.h \
              /usr/include/time.h

    f2.o: f.h /usr/include/stdio.h \
              /usr/include/ctype.h \
              /usr/include/time.h  \
              /usr/include/stat.h

    f3.o: f.h /usr/include/stdio.h \
              /usr/include/ctype.h \
              /usr/include/time.h

Программой mkmf в качестве исходного файла-шаблона использо-
ван  стандартный файл /usr/new/lib/p.Makefile, но можно ука-
зать для использования и любой другой.

     Программа  mkmf  работает  следующим  образом:  сначала
выбираются и вносятся в файл-шаблон имена всех исходных фай-
лов рабочего каталога, далее определяется от каких  include-
файлов зависят исходные файлы, формируются правила и записы-
ваются  в  файл-шаблон.  Для  обозначения  исходных   файлов
используются правила с суффиксами.

     Makefile можно редактировать, изменять значения  макро-
переменных.   При этом, если повторить вызов программы mkmf,
в нем появятся только те изменения, которые  необходимы  для
сборки с учетом изменений в исходных текстах.

     В Makefile, полученном из  стандартного  файла-шаблона,
определены следующие макропеременные:

CFLAGS
     ключи Си-компилятора;

DEST
     каталог, в котором будет размещен результат;

EXTHDRS
     перечень полных имен include-файлов;

HDRS
     перечень имен  include-файлов,  размещенных  в  рабочем
     каталоге;

LIBS
     список объектных библиотек для сборки программы;


                           - 41 -










MAKEFILE
     имя файла с Make-программой;

OBJS
     список объектных файлов,  участвующих  в  сборке  прог-
     раммы;

PROGRAM
     имя программы, которую необходимо получить;

SRCS
     список имен всех файлов с исходными текстами;


     Значения  макропеременных  EXTHDRS,  HDRS,  OBJS,  SRCS
устанавливаются  программой  mkmf  и всегда имеют актуальные
значения.  Остальные макропеременные получают  при  создании
Makefile  значения по умолчанию, их можно изменять по своему
усмотрению.

     Рассмотрим  правила  Make-программы,   котороые   можно
использовать как самостоятельные входы:

all
     трансляция, сборка и запуск  на  выполнение  полученной
     программы;

clean
     удаление ненужных файлов;

depend
     изменение структуры Make-программы с учетом  существую-
     щего Makefile;

index
     печать индексов функций собираемой программы;

install
     трансляция, сборка и установка  программы  в  указанный
     каталог;

print
     печать include-файлов и текстов программы;

tags
     создание файла ./tags - ссылок программ, написанных  на
     языках Си, Паскаль и Фортран;

update
     изменение Makefile, перегенерация, сборка  и  установка
     программы  в  указанный каталог.  С учетом произошедших
     изменений в текстах  исходных  файлов  будет  выполнено
     только то, что необходимо в данный момент времени.


                           - 42 -










     Пусть имеются файлы f[123].c, f.h и Makefile, заменим в
нем  значение  макропеременной DEST на /usr/tmp и макропере-
менной PROGRAM - на example.  Выполним  следующую  командную
строку:

    % make program install clean

    получим на экране сообщение

    cc  -c f1.c
    cc  -c f2.c
    cc  -c f3.c
    Сборка example ... готово.
    Результат выполнения программы example
    Установка example в /usr/tmp

Выполним командную строку

     % make index

    получим имена функций и места их определений

     a2       5 f2.c      char *a2(){
     f1      11 f1.c      f1(){
     f2       2 f2.c      int f2(){
     f3       2 f3.c      int f3(){
     main     5 f1.c      main(ac, av)
     nn       6 f3.c      char *nn(){

Программа mkmf позволяет создавать Makefile для сборки  биб-
лиотеки.      Для     этого     используется     файл-шаблон
/usr/new/lib/l.Makefile и дополнительно вводятся  макропере-
менная LIBRARY (имя библиотеки) и  правила extract (извлече-
ние из библиотеки всех  частей  в  виде  отдельных  файлов),
library (трансляция и загрузка библиотеки).

     Программист может  отказаться  от  стандартных  файлов-
шаблонов /usr/new/lib/[lp].Makefile и создать свои шаблоны в
рабочем  каталоге.   Файлы  шаблоны   должны   иметь   имена
l.Makefile и p.Makefile.















                           - 43 -










ЛИТЕРАТУРА

 1. "Банахан М., Раттер Э. Введение в  операционную  систему
    UNIX. - М.: Радио и связь, 1986." AI

 2. "Баурн С. Операционная система UNIX.- М.: Мир, 1986." AN

 3. "Браун П. Введение в операционную систему  UNIX.  -  М.:
    Мир, 1987." AM

 4. "Готье Р. Руководство по операционной  системе  UNIX.  -
    М.: Финансы и статистика, 1985." AE

 5. "Диалоговая единая мобильная операционная система ДЕМОС.
    - Калинин: ЦЕНТРПРОГРАММСИСТЕМ, 1985." AK

 6. "Инструментальная мобильная операционная система  ИНМОС/
    М.И.  Беляков,  А.Ю. Ливеровский, В.П. Семик и др. - М.:
    Финансы и статистика, 1985." AH

 7. "Керниган Б., Ритчи Д., Фьюер А.  Язык  программирования
    Си.  Задачи  по  языку  Си.  - М.: Финансы и статистика,
    1985." AF

 8. "Кристиан К. Введение в операционную систему UNIX. - М.:
    Финансы и статистика, 1985." AJ

 9. "Хенкок Л., Кригер М.  Введение  в  программирование  на
    языке СИ. - М.: Радио и связь, 1986." AG

10. "Aho A. V., Kernighan Brian V. W., Weinberger  Peter  J.
    AWK - a pattern scanning and processing language. Second
    edition. UNIX Programmers manual,  42  BSD,  1980.  Bell
    Laboratries: Murray Hill, New Jersey, 1978." AL

11. "Feldman S. I. Make - a program maitaining computer pro-
    gramms.  Bell  Laboratries:  Murray  Hill,  New  Jersey,
    1978." AB

12. "Joy W. N. An introduction the UNIX C-shell.  UNIX  Pro-
    grammers  manual, 42 BSD, 1980. Bell Laboratries: Murray
    Hill, New Jersey, 1978." AA

13. "Johnson S. C. YACC  -  yet  another  compiler-compiler.
    Comp.  Sci.  tech.  rep.  N 32. Bell Laboratries: Murray
    Hill, New Jersey, 1975." AD

14. "Lesk M. E. Lex - lexical analyzer generator. Comp. Sci.
    tech. rep. N 39. Bell Laboratries: Murray Hill, New Jer-
    sey, 1975." AC





                           - 44 -










                         СОДЕРЖАНИЕ



    АННОТАЦИЯ .........................................    2

1.  Введение ..........................................    3

2.  Принципы выполнения Make-программы ................    4

3.  Соглашения языка Make .............................   10

4.  Использование макропеременных .....................   13

5.  Выполнение правил в Make-программе ................   16

6.  Режимы выполнения Make-программы ..................   18

7.  Правила с суффиксами ..............................   21

8.  Управление архивом в Make-программе ...............   30

9.  Особенности программирования на языке Make ........   36

10. Автоматизация программирования Make-программ ......   38

    ЛИТЕРАТУРА ........................................   44




























                           - 45 -




Популярность: 26, Last-modified: Mon, 29 Jun 1998 14:13:47 GmT