Интерпретатор make

Содержание










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

      "И Н Т Е Р Ф Е Й С"













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

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

      Демос/P 2.1










      Интерпретатор

      make














      Москва

      1988















      АННОТАЦИЯ

      Описан интерпретатор make, используемый для сборки пакетов программ, минимизирующий число вызовов транслятора.





























































1. Введение

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

      редактор -> make -> проверка -> редактор
При такой технологии существенно повышается производитель- ность труда программиста,так как он освобождается от ручной сборки программ, сокращается загрузка ЭВМ - make "следит" за тем, чтобы при многократных компиляциях и отладках программ "не делалолсь то, что можно не делать".

      Важно отметить, что make является средством автоматиза- ции процедур установки компонент ДЕМОС. Например, компонента системы cat может включать следующие файлы:
выполняемый код - файл /bin/cat текст программы - файл ./src/cmd/cat/cat.c документацию - файл ./man/man1/cat.1 программу сборки - файл ./src/cmd/cat/Makefile
Файл ./src/cmd/cat/Makefile содержит всю необходимую для правильной компиляции и установки в ОС компоненты cat инфор- мацию. Особенно эффективен make для выполнения работ в программных проектах малой и средней (до 200 файлов)


      - 3 -









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

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

      a b c d e f
из которых определенным образом необходимо получить файл E. Пусть далее известно, что над различными комбинациями исход- ных файлов выполняются некоторые действия, а результаты будут размещены в промежуточных файлах A, B, C и D. Расс- мотрим граф, узлы которого - имена файлов. Дуги графа отра- жают зависимости файлов, стрелка указывает направление пре- образований от исходных файлов к файлам, которые необходимо получить.

      В Make-программе каждой паре (x,y) инцидентных узлов этого графа ставится в соответствие список действий, выпол- нение которых приведет к созданию x. Когда файл x сущест- вует, список действий не выполняется, но только в том слу- чае, если файл y создан (модифицирован) раньше по времени, чем файл x. Каждой дуге графа можно поставить в соответсвие значение функции t(x,y). Функция t(x,y) возвращает результат в виде




      /\
      цель E / \
      | /----\
      | ||
      t(E,D ) | t(E,C) ||
      ----------------------- ||
      | | ||
      цель D цель C ||
      t(D,A) | t(D,B) | ||
      ---------------- | ||
      | | | ||
      цель A цель B | ||
      | | t(C,e)| ||
      t(A,a)| t(A,b) t(B,c)| t(B,d) t(C,d)| ||
      ------------ ------------ ------- ||
      | | | | | | ||
      | | | | | | ||
      a b c d e f ||




      - 4 -











      x МОЛОЖЕ y - список действий не выполняется;

      x СТАРЕЕ y - список действий выполняется.

Множество значений функции t(x,y) образует структуру динами- ческих (зависящих от времени) связей между файлами. На этой основе интерпретатор make выделяет те разделы Make- программы, которые можно не выполнять.

      Выше предполагалось, что каждый узел графа - это файл. Существует возможность записать в Make-программe список действий, выполнение которых не связано с созданием файла. Поэтому в общем случае узел графа правильнее называть целью. Пара инцидентных узлов графа образует цель и подцель. В при- мере узел E - цель, узлы D и C - подцели цели E. Аналогично узел D - цель, узлы A и B - подцели цели D. Наконец, узел A - цель, узлы a и b - подцели узла A. Перечисление вида ЦЕЛЬ - ПОДЦЕЛИ отражает обобщенную структуру алгоритма достижения целей.

      Введем понятие реконструкция файла-цели. Если файл-цель существует и "МОЛОЖЕ" всех файлов, от которых зависит, то он остается без изменений, иначе, если файл-цель существует и "СТАРЕЕ" какого-либо файла, от которого зависит, он реконст- руируется (изготавливается заново).

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

      E : D C # E зависит от D и C
      cat D C > E # действие правила 1

      D : A B # D зависит от A и B
      cat A B > D # действие правила 2

      A : a b # A зависит от a, b
      cat a b > A # действие правила 3

      B : c d # B зависит от c, d
      cat c d > B # действие правила 4

      C : e f # C зависит от e, f
      cat e f > C # действие правила 5

      clean clear:
      -rm -f A B C D E
Здесь содержится 6 правил. Каждое правило включает строку зависимостей файлов и командную строку системы. Правило описывается просто: сначала указывается имя файла, который


      - 5 -









необходимо создать (цель), затем двоеточие, затем имена фай- лов, от которых зависит создаваемый файл (подцели), затем строки действий. Первую строку правила назовем строкой зависимостей. Следует обратить внимание на шестое правило: в нем пустой список подцелей в строке зависимостей. Синтак- сис строк действий соответствует синтаксису командных строк shell. Первым символом строки действия в Make-программе дол- жен быть символ табуляции (или 8 пробелов) - это обязатель- ное условие.

      Все последовательности символов, начиная от символа # и до конца строки, являются комментарием. Пустые строки и лиш- ние пробелы игнорируются. Если Make-программа размещена в файле Makefile, то имя файла с Make-программой в командной строке можно не указывать. Допустим, файл с Make-программой называется Makefile, в рабочем каталоге имеются файлы a, b, c и d. Файлы A, B, C и D отсутствуют, тогда по команде make мы получим результат - файл Е и файлы A, B, C и D. Рассмот- рим порядок выполнения Make-программы, когда эти файлы уже существуют, т.е. при повторном выполнении команды make.

      Первый шаг выполнения Make-программы:

      E : D C
      cat D C > E
Если файлы D и C существуют и не требуется их реконструкция, а файл E "МОЛОЖЕ", чем файлы D и C, то make прекратит выпол- нение программы - файл Е готов. Если требуется реконструк- ция файлов D и/или C, то осуществляется переход к выполнению подцелей D и/или C, затем возврат к этому правилу. Иначе, если требуется реконструкция файла E, то выполняется дейст- вие этого правила и make прекращает выполнение программы - готов реконструированный файл E. Иначе, если отсутствуют файлы D и/или C, будут выполнены подцели D и/или C в том порядке, в котором они указаны в списке зависимостей, затем выполняется действие этого правила и make прекратит выполне- ние программы - готов файл E.

      Второй шаг выполнения Make-программы:

      D : A B
      cat A B > D
Если файлы A, B и D существуют и не требуется их реконст- рукция, то выполняется переход к следующему шагу Make- программы (файл D уже готов). Если требуется реконструкция файлов A и/или B, происходит переход к выполнению подцелей A и/или C, затем возврат к этому правилу. Иначе, если требу- ется реконструкция файла D, выполняется действие этого пра- вила и переход к следующему шагу выполнения Make-программы. Иначе, если отсутствуют файлы A и/или B, будут выполнены подцели A и/или B в том порядке, в котором они указаны в


      - 6 -









списке зависимостей, затем действие этого правила и переход к выполнению первого правила Make-программы.

      Третий шаг выполнения Make-программы:

      A : a b
      cat a b > A
Проверяется наличие файлов a и b в рабочем каталоге. При отсутствии хотя бы одного из них выполнение программы прек- ращается. Затем проверяется наличие файла A, если его нет или требуется его реконструкция, выполняется действие этого правила. Иначе осуществляется переход к выполнению второго правила.

      Четвертый шаг выполнения Make-программы:

      B : c d
      cat c d > B
Действия аналогичны описанным в третьем шаге, переход осу- ществляется к выполнению второго правила.

      Пятый шаг выполнения Make-программ:

      C : e f
      cat e f > C
Проверяется наличие файлов e и f в рабочем каталоге. При отсутствии хотя бы одного из них выполнение программы прек- ращается. Затем проверяется наличие файла C, если его нет или требуется его реконструкция, выполняется действие этого правила. Иначе осуществляется переход к выполнению первого правила.

      При вызове интерпретатора make в командной строке можно указать имя цели. Если, например, необходимо получить файл D, то командная строка выглядела бы так

      % make D
или если необходимо получить файлы C и D, то командная строка выглядела бы

      % make C D
Таким образом, имя файла-цели в командной строке определяет вход в Make-программу. Если задано несколько входов, то make выполнит в указанном порядке все необходимые разделы Make- программы. Если же вход не указан, выполняется первое пра- вило Make-программы.




      - 7 -










      В шестом правиле примера цель не является файлом, это важная особенность make. Программисту предоставляется воз- можность записать правило, цель и/или подцели которого не являются файлами. В таком случае цель - это имя входа в Make-программу (или метка правила). Шестое правило исполь- зуется в программе для удаления файлов. Следует обратить внимание на то, что в этом правиле два имени цели (clean и clear), поэтому в командной строке можно указывать любое имя входа, например:

      % make clean
      или
      % make clear
В результате выполнения будут удалены файлы A, B, C, D и E.

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

      sh -c строка_действия
и должны нормально выполняться интерпретатором sh (код возв- рата 0), иначе (по получении другого кода завершения командной строки) make прекратит выполнение программы. Существует способ обойти это условие. Обратите внимание на действие в 6-м правиле: строка действий начинается с символа "-", что означает не прекращать работу при неудачном выпол- нении команды rm.

      В Make-программе можно использовать макропеременные. Механизм макроопределений и подстановок макропеременных в Make-программе по смыслу аналогичен механизму подстановок в shell, хотя по синтаксису несколько отличается. Рассмотрим приведенный выше пример с использованием макропеременных. Теперь Makefile будет выглядеть так:




















      - 8 -










      SRC1 = a b # макроопределения
      SRC2 = c d
      SRC3 = e f
      SRC4 = A B C D

      E : D C
      cat D C > E

      D : A B
      cat A B > D

      A : $(SRC1) # A зависит от SRC1
      cat $(SRC1) > A

      B : $(SRC2) # B зависит от SRC2
      cat $(SRC2) > B

      C : $(SRC3) # C зависит от SRC3
      cat $(SRC3) > C

      clean clear:
      -rm -f $(SRC4)
Первые строки Make-программы - строки с макроопределениями, где каждой переменной SRC присваиваются значения. В правилах выполняется операция подстановки значения макропеременной, например $(SRC1). Макропеременные позволяют манипулировать списками имен файлов при минимальных изменениях в тексте Make-программы.

      Интерпретатор make реализует механизм обработки умолча- ний зависимостей файлов со стандартными суффиксами имен. Например, файл с суффиксом имени .o можно получить из файлов с суффиксами имен .c (язык программирования Си) и .s (язык ассемблер). Рассмотрим пример. Допустим, имеются файлы a.c, b.c, c.c и d.s, образующие программу, которую назовем pro- gram. Файлы a.c, b.c и c.c содержат строку

      # include program.h
т.е. зависят от файла program.h. Make-программа для работы с этими файлами будет содержать 3 строки

      program: a.o b.o c.o d.o
      cc a.o b.o c.o d.o -o program

      a.o b.o c.o: program.h
По команде make будет создан файл program. При первом выполнении получим на экране дисплея:





      - 9 -










      cc -c a.c
      cc -c b.c
      cc -c c.c
      as - -o d.o d.s
      cc a.o b.o c.o d.o -o program
Обратите внимание на то, что интерпретатор определил необхо- димые действия над исходными файлами с суффиксами имен .c и .s, хотя имена этих файлов в Make-программе не указаны, и правильно осуществил сборку программы. Теперь, допустим, мы вызываем make на выполнениe второй раз после редактирования файла program.h, при этом получим:

      cc -c a.c
      cc -c b.c
      cc -c c.c
      cc a.o b.o c.o d.o -o program
Если выполнить Make-программу после редактирования файла b.c, то получим:

      cc -c b.c
      cc a.o b.o c.o d.o -o program
Наконец, если, допустим, необходимо получить файл c.o, то можно выполнить команду

      make c.o
Механизм умолчаний и обработки суффиксов спроектирован для автоматизации программирования Make-программ; он существенно сокращает размеры программ и количество ошибок в них.
3. Соглашения языка Make

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

идентификатор
      последовательность букв, цифр и символа "_", содержащая
      шаблоны имен файлов ([...], ?, *), символы / и "."
идентификатор = значение
      определение макропеременной. В правой части могут быть
      макроподстановки, а также вся правая часть может быть
      пустой строкой.

      $(идентификатор)
      ${идентификатор}
      $символ



      - 10 -










      подстановка значения макропеременной. Специальное зна-
      чение символа $ можно отменить, указывая $$.
комментарий
      текст, следующий за символом # и до конца строки. Спе-
      циальное значение символа # отменяется, если он указан
      в кавычках.
обратная наклонная черта
      символ продолжения строки. Специальное значение сим-
      вола \ отменяется, если он указан дважды.
пустая строка, пробелы
      пробелы служат разделителями слов в командной строке,
      лишние пробелы и табуляции игнорируются. Пустая строка
      всюду игнорируется.
список_зависимостей

список_действий




      правило в общем виде. Список_действий может быть пус-
      тым.

      .первый_суффикс.второй_суффикс:

список_действий




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

      .SUFFIXES: список_суффиксов

список_целей :[:] список_подцелей
      список_зависимостей. Список_подцелей может быть пус-
      тым. Правила с одним и двумя символами двоеточия в
      списке_зависимостей отличаются порядком выполнения
      списка_подцелей и списка_действий.
имя_цели [имя_цели]
      список_целей. Имя_цели - идентификатор. Можно исполь-
      зовать символ / и точку. Имя_цели может быть именем
      файла или каталога, тогда включается выполнение меха-
      низма реконструкции. Имя_цели может не быть именем
      файла, тогда механизм реконструкции не включается, а
      имя_цели является меткой (именем правила, входа в
      Make-программу).
имя_подцели [имя_подцели] [#комментарий]
      список_подцелей. Имя_подцели - идентификатор. Можно


      - 11 -










      использовать шаблоны имен файлов "*", "?", [...], сим-
      вол / и точку. Имя_подцели может быть именем файла,
      для которого записано или не записано правило в Make-
      программе, в этих случаях включается механизм реконст-
      рукции. Имя_подцели может не быть именем файла, в этом
      случае механизм реконструкции не включается, а имя_цели
      является меткой (именем правила, входа в Make-
      программу).
строка_действия [#комментарий]
      ............... строка_действия [#комментарий]


      список_действий. Любые командные строки ДЕМОС и управ-
      ляющие конструкции Shell.
'табуляция'командная_строка_shell
      строка_действия.


      Строка_действия может быть указана в строке зависимос-
      тей через символ ";". Строку_действия можно указывать в
      следующих форматах:

      'табуляция'командная__строка__shell 1

      'табуляция'@командная_строка__shell 2

      'табуляция'-командная_строка__shell 3

      'табуляция'-@командная_строка_shell 4

      В первом формате командная строка выводится на печать;
      если код возврата после ее выполнения не 0, make прек-
      ращает выполнение программы по ошибке. Во втором фор-
      мате командная строка не выводится на печать; если код
      возврата после ее выполнения не 0, make прекращает
      выполнение программы по ошибке. В третьем формате
      командная строка выводится на печать; если код возврата
      после ее выполнения не 0, make игнорирует ошибку и
      выполнение программы продолжается. В четвертом формате
      командная строка не выводится на печать; если код возв-
      рата после ее выполнения не 0, make игнорирует ошибку
      и выполнение программы продолжается. Простая командная
      строка (одна команда ДЕМОС с аргументами) выполняется
      без порождения оболочки. Другие командные строки
      выполняются sh следующим образом: sh -c
      командная_строка_shell


      Для сокращения обозначений предусмотрены макроперемен- ные с предопределенными именами. В правиле без суффиксов


      - 12 -









строка_действия может включать следующие предопределенные макропеременные:
@ имя цели;
? имена файлов из списка подцелей, которые МОЛОЖЕ
      файла_цели. Эти файлы участвуют в реконструкции цели.


      В правиле с суффиксами строка_действия может включать следующие предопределенные макропеременные:
* основа_имени_цели;
@ основа_имени_цели.второй_суффикс;
<&lt; основа_имени_цели.первый_суффикс.
4. Использование макропеременных

      При выполнении Make-программы значения макропеременных устанавливаются в строках макроопределений и/или в командной строке при запуске make на исполнение. Кроме того, сущест- вуют макропеременные с предопределенными именами, значения которых устанавливаются при выполнении Make-программы. К ним относятся: макропеременная @, ее значение - имя_цели; макро- переменная ?, ее значение - имена тех файлов_подцелей, кото- рые МОЛОЖЕ файла_цели.

      Предопределенные макропеременные "@" и "?" используются только в списке действий правила и в каждом правиле имеют свои значения. Определять значения макропеременных можно в любом месте Make-программы, но не внутри правила. Интерпре- татор make составляет список имен макропеременных и присваи- вает им значения в процессе чтения Make-программы. Если зна- чение макропеременной переопределяется, то ей присваивается новое значение; если используются макроопределения с вложен- ными макроподстановками, то значения устанавливаются с уче- том всех присвоений в Make-программе. Если значение макро- переменной задается в командной строке при запуске Make- программы на исполнение, то все определения этой макропере- менной в Make-программе игнорируются и используется значе- ние, взятое из командной строки. Состояние ошибки порожда- ется, если используется рекурсия при присвоении значения макропеременным. Например,

      A = $B
      B = $A
приведет к аварийному завершению выполнения Make-программы.

      В макроопределениях можно использовать метасимволы шаб- лонов имен файлов shell. Допустим, рабочий каталог имеет


      - 13 -









вид:

      -rw-r--r-- 1 user 15658 Авг 6 16:03 1.m
      -rw-r--r-- 1 user 2158 Авг 8 16:38 2.m
      -rw-r--r-- 1 user 5185 Авг 9 17:38 3.m
      -rw-r--r-- 1 user 4068 Июл 28 20:56 6.m
      -rw-r--r-- 1 user 100 Авг 9 14:30 f2
      -rw-r--r-- 1 user 66 Авг 9 17:42 f3
Пример Make-программы в Makefile :

      A = *
      B = f?
      C = [0-9].*

      aaa :
      echo $A
      echo $B
      echo $C
После выполнения команды make -s получим на экране дисплея:

      1.m 2.m 3.m 6.m f2 f3
      f2 f3
      1.m 2.m 3.m 6.m
В Make-программе часто бывает необходимо манипулировать име- нами каталогов и файлов. Механизм макроподстановок предла- гает удобные средства для этого. Пример:

      A = *
      B = [pg]*
      C = f?r*
      DIR1 = .
      DIR2 = /etc
      DIR3 = /usr/bin

      aaa :
      echo ${DIR1}/$A
      echo ${DIR2}/$B
      echo ${DIR3}/$C
После выполнения получим:

      ./1.m ./2.m ./3.m ./6.m ./f2 ./f3
      /etc/getty /etc/group /etc/passwd
      /usr/bin/fgrep


      Рассмотрим пример, в котором демонстрируются всевозмож- ные способы использования макропеременных. Допустим, имеется Makefile



      - 14 -










      БИБЛИОТЕКА = ПОЛКА ${ДРУГОЕ}
      ДРУГОЕ = Документы
      Шкаф = ПОЛКА
      папка = справки, копии.
      СПРАВОЧНИКИ =
      ЖУРНАЛЫ =
      Словари = толковые, иностранных языков.
      ТЕХНИЧЕСКАЯ = $(СПРАВОЧНИКИ) $(Словари)
      ХУДОЖЕСТВЕННАЯ = проза, поэзия, драматургия.

      t = Справка с места жительства.
      x = Копия свидетельства о рождении.
      файлы = d e

      библиотека : ${БИБЛИОТЕКА}
      echo 'Действия правила' $@
      echo '$$? - список подцелей :' $?
      echo '$$@ - имя цели :' $@
      echo 'Техническая : ' $(ТЕХНИЧЕСКАЯ)
      echo 'Худ. : ' $(ХУДОЖЕСТВЕННАЯ)
      echo ' '

      ${Шкаф} : b c
      echo 'Действия правила' $@
      echo '$$? - список подцелей :' $?
      echo '$$@ - имя цели :' $@
      echo ' '

      ${ДРУГОЕ}: ${файлы}
      echo 'Действия правила' $@
      echo '$$? - список подцелей :' $?
      echo '$$@ - имя цели :' $@
      echo 'Папка : ' ${папка}
      echo $t
      echo $x
      echo ' '

      b:
      c:
      d:
      e:
Следует обратить внимание на то, что $буква используется для подстановки значения макропеременной, имя которой состоит из одной буквы, а $(идентификатор) и ${идентификатор} равно- ценны. Правила b, c, d и e включены исключительно для демонстрации значений макропеременной "?". Теперь, если выполнить команду make -s, получим на экране дисплея:







      - 15 -










      Действия правила ПОЛКА
      $? - список подцелей : b c
      $@ - имя цели : ПОЛКА

      Действия правила Документы
      $? - список подцелей : d e
      $@ - имя цели : Документы
      Папка : справки, копии.
      Справка с места жительства.
      Копия свидетельства о рождении.

      Действия правила библиотека
      $? - список подцелей : ПОЛКА Документы
      $@ - имя цели : библиотека
      Техническая :толковые, иностранных языков.
      Худ. : проза, поэзия, драматургия.
В командной строке можно присвоить значение макропеременной. После команды

      make -s Словари = английский, немецкий.
получим на экране дисплея:

      Действия правила ПОЛКА
      $? - список подцелей : b c
      $@ - имя цели : ПОЛКА

      Действия правила Документы
      $? - список подцелей : d e
      $@ - имя цели : Документы
      Папка : справки, копии.
      Справка с места жительства.
      Копия свидетельства о рождении.

      Действия правила библиотека
      $? - список подцелей : ПОЛКА Документы
      $@ - имя цели : библиотека
      Техническая : английский, немецкий.
      Худ. : проза, поэзия, драматургия.

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

      Существует несколько разновидностей правил:

      с одним и двумя двоеточиями;

      с одинаковыми именами целей;

      не содержащие списка действий;




      - 16 -










      не содержащие списка подцелей и/или списка действий;

      правила, предопределенные в интерпретаторе make, кото-
      рые программист может включать в Make-программу.


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

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

      monitor.c : monitor.h
Это означает, что файл monitor.c зависит от файла monitor.h. Если monitor.h действительно имеется в рабочем каталоге, то любые изменения в нем приведут к реконструкции файла monitor.o, если файл monitor.h отстутствует, make прекращает выполнять программу по ошибке. В Make-программе могут встречаться случаи, когда необходимо для одной цели записать несколько правил, тогда существенно важно, сколько двоеточий указано в правиле. Ниже приведены схемы, в которых цифрами показан порядок выполнения этих правил.

      Порядок выполнения нескольких правил с одинаковым именем_цели и одним двоеточием: сначала выполняются правила, связанные со списками подцелей, затем список_действий одного из правил. Список действий разрешается указывать только в одном из таких правил:

      имя_цели_А : список_подцелей <---| 1 |

      имя_цели_А : список_подцелей <---| 2 |
      список_действий <---| 4 |

      имя_цели_А : список_подцелей <---| 3 |


      Порядок выполнения нескольких правил с одинаковым именем_цели и двумя двоеточиями. Список действий может быть в каждом правиле:




      - 17 -










      имя_цели_А :: список_подцелей <---| 1 |
      список_действий <---| 2 |

      имя_цели_А :: список_подцелей <---| 3 |
      список_действий <---| 4 |

      имя_цели_А :: список_подцелей <---| 5 |
      список_действий <---| 6 |

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

      Интерпретатор make предоставляет ряд возможностей для управления выполнением Make-программы. Для этой цели исполь- зуются следующие директивы:

      .SILENT - не печатать строки действий;
      .IGNORE - игнорировать ошибки действий;
      .DEFAULT - выполнить альтернативное действие;
      .PRECIOUS - удалить недостроенный файл.
Директивы .SILENT и .IGNORE можно указывать как в Make- программе, так и в командной строке ключами -s и -i, DEFAULT и PRECIOUS только в Make-программе. Допустим имеется следу- ющая Make-программа:

      aa: bb
      echo Действия правила $@

      bb:
      echo Действия правила $@
      ppp # Несуществующая команда
      sort e # Нет файла e

      После выполнения получим сообщения:

      echo Действия правила bb
      Действия правила bb
      ppp # Несуществующая команда
      sh: ppp: не найден
      *** Код ошибки 1
      Конец.
Интерпретатор make прекратил работу по первой ошибке. Кроме того, на экран дисплея выводятся строки действий. Отменить вывод строк действий можно следующими способами:


      указать ключ -s в командной строке при запуске make;

      указать в Make-программе директиву SILENT;




      - 18 -










      начинать каждую строку действий символом @.


      В первых двух случаях результат одинаков - не будут выводиться строки действий. В третьем случае не будут выво- диться строки действий вида

      'табуляция'@строка_действий
Пример использования директивы SILENT.

      aa: bb
      echo Действия правила $@

      bb:
      echo Действия правила $@
      ppp # Несуществующая команда
      sort e # Нет файла e

      .SILENT:

      После выполнения программы получим:

      Действия правила bb
      sh: ppp: не найден
      *** Код ошибки 1
      Конец.
По любой ошибке make прекратит выполнение программы. Сущест- вуют следующие способы игнорирования ошибок (Make-программа продолжает выполняться):


      указать ключ -i при запуске make на выполнение;

      указать в Make-программе директиву IGNORE;

      после символа табуляция указать символ "-".


      В первом и втором случаях будут проигнорированы все ошибки при выполнении строк действий, в третьем игнорируются ошибки в тех строках действия, которые указаны следующим образом:

      'табуляция'-строка_действий
Пример использования директив SILENT и IGNORE. Обработка ошибок при выполнении действий в правилах






      - 19 -










      aa: bb
      echo Действия правила $@

      bb:
      echo Действия правила $@
      ppp # Несуществующая команда
      sort e # Нет файла e

      .SILENT:

      .IGNORE:

      После выполнения программы получим:

      Действия правила bb
      sh: ppp: не найден
      *** Код ошибки 1 (игнорирован)
      sort: не могу открыть e
      *** Код ошибки 1 (игнорирован)
      Действия правила aa
Правило DEFAULT используется для указания альтернативных действий по отсутствующему в данный момент файлу. Правило DEFAULT позволяет записать список действий, которые будут выполняться для всех отсутствующих файлов, поэтому требуется определенная осторожность, например:





























      - 20 -










      aa: bb
      echo Действия правила $@

      bb: a b c d
      echo Действия правила $@
      ppp # Несуществующая команда
      sort e # Нет файла e

      .SILENT:

      .IGNORE:

      .DEFAULT:
      echo Действия правила .DEFAULT для $@

      После выполнения программы получим:

      Действия правила .DEFAULT для a
      Действия правила .DEFAULT для b
      Действия правила .DEFAULT для c
      Действия правила .DEFAULT для d
      Действия правила bb
      sh: ppp: не найден
      *** Код ошибки 1 (игнорирован)
      sort: не могу открыть e
      *** Код ошибки 1 (игнорирован)
      Действия правила aa
Часто бывает необходимо прекратить выполнение Make- программы. Это не приведет к фатальным последствиям, так как сохраняется структура динамических (зависящих от вре- мени) связей файлов. Однако, если создание некоторого файла не завершилось и он тем не менее образовался, его желательно удалить перед повторным запуском интерпретатора. Это можно сделать автоматически, используя директиву PRECIOUS, напри- мер:

      aaa: file
      sort file > $@

      .PRECIOUS:

Если в момент синхронного исполнения Make-программы ввести сигнал CTRL/C, файл $@ будет удален.
7. Правила с суффиксами

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


      - 21 -









выполнения таких правил строится на суффиксах имен файлов. Допустим, из файла с именем основа.суффикс_1 необходимо получить файл с именем основа.суффикс_2, тогда обычное пра- вило будет выглядеть так:

      основа.суффикс_2 : основа.суффикс_1

      список действий
Понятно, что для группы файлов, основы имен которых раз- личны, а первый и второй суффиксы имен одинаковы, желательно было бы записать одно правило обработки. Например, файлы *.c обычно преобразуются в файлы *.o одним списком действий, и, следовательно, эти правила желательно записывать в виде одного правила. Интерпретатор make предлагает эту возмож- ность в правилах вида

      .суффикс_1.суффикс_2:

      список_действий

      .SUFFIXES: .суффикс_1 .суффикс_2
Если в Make-программе записаны эти правила, интерпретатор, получив в качестве аргумента имя файла с именем основа.суффикс_1, выполнит указанное выше правило, и мы получим результат - файл с именем основа.суффикс_2. Поря- док выполнения правила с суффиксами такой же, как и в обыч- ном правиле. Предопределенное правило SUFFIXES используется для указания списка суффиксов, который может содержать более двух суффиксов. Порядок суффиксов в списке роли не играет. Естественно, для каждой пары суффиксов в Make-программе должны быть записаны соответствующие правила. В правилах с суффиксами используются предопределенные макропеременные:
@ - имя_результатa (основа.суффикс_2);
<&lt; - имя_аргументa (основа.суффикс_1);
* - основа.

      Рассмотрим пример. Допустим, имеются исходные файлы *.c и *.k. Необходимо из них получить файлы *.t, а из них - файл result. Допустим также, что файлы *.c зависят от файла file.h (содержат строку #include file.h). Граф преобразова- ний файлов в этом случае выглядит так:









      - 22 -










      result
      |
      .t
      |

      | |
      .c .k
Программа, реализующая этот граф, может быть следующей:














































      - 23 -










      result: d.t a.t b.t c.t
      echo 'Действия правила' $@
      echo ' Значение $$@ - ' $@
      echo ' Значение $$? - ' $?
      touch $@

      .k.t :
      echo 'Действия правила .k.t :'
      echo ' Значение $$* - ' $*
      echo ' Значение $$@ - ' $@
      echo ' Значение $$? - ' $?
      echo ' Значение $$< - ' $<
      touch $@

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

      a.c b.c c.c : file.h

      .SUFFIXES: .t .c .k

      После выполнения команды make -rs получим:

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

      Действия правила .c.t :
      Значение $* - 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 -


Подякувати Помилка?

Дочати пiзнiше / подiлитися