Версия для печати

Архив документации на OpenNet.ru / Раздел "Программирование, языки" (Многостраничная версия)
Вперед Назад Содержание

Программа управления компиляцией GNU make 3.73

Ричард Столлман (Richard M. Stallman)
Роланд МакГрат (Roland McGrath)

Апрель 1995 Редакция 0.48


Утилита make автоматически определяет, какие части большой программы должны быть перекомпилированы и команды для их перекомпиляции, Это руководство описывает GNU make, который был реализован Ричардом Столлманом и Роландом МакГратом.

1. Обзор make

2. Введение в make-файлы

3. Написание make-файлов

4. Написание правил

5. Написание команд в правилах

6. Как использовать переменные

7. Условные части make-файла

8. Функции преобразования текста

9. Как запускать make

10. Использование неявных правил

11. Использование make для обновления архивных файлов

12. Особенности GNU-версии программы make

13. Несовместимость и недостающие возможности

14. Соглашения о make-файлах

15. Приложение. Комплексный пример Make-файла.


Вперед
Вперед Назад Содержание

Программа управления компиляцией GNU make 3.73

Ричард Столлман (Richard M. Stallman)
Роланд МакГрат (Roland McGrath)

Апрель 1995 Редакция 0.48


Утилита make автоматически определяет, какие части большой программы должны быть перекомпилированы и команды для их перекомпиляции, Это руководство описывает GNU make, который был реализован Ричардом Столлманом и Роландом МакГратом.

1. Обзор make

2. Введение в make-файлы

3. Написание make-файлов

4. Написание правил

5. Написание команд в правилах

6. Как использовать переменные

7. Условные части make-файла

8. Функции преобразования текста

9. Как запускать make

10. Использование неявных правил

11. Использование make для обновления архивных файлов

12. Особенности GNU-версии программы make

13. Несовместимость и недостающие возможности

14. Соглашения о make-файлах

15. Приложение. Комплексный пример Make-файла.


Вперед Назад Содержание
Вперед Назад Содержание

1. Обзор make

Утилита make автоматически определяет, какие части большой программы должны быть перекомпилированы и команды для их перекомпиляции, Это руководство описывает GNU make, который был реализован Ричардом Столлманом и Роландом МакГратом, GNU make удовлетворяет разделу 6.2 стандарта IEEE 1003.2-1992 (POSIX.2).

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

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

Как только существует подходящий make-файл, для выполнения всех необходимых перекомпиляций при изменении исходных файлов достаточно просто набрать в командной строке:

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

Вы можете при вызове make использовать аргументы командной строки для управления тем, какие файлы следует перекомпилировать и как это делать. Смотрите главу 9 [Как запускать make].

1.1 Как читать это руководство

Если вы начинающий пользователь make или вы ищете общее описание, читайте несколько первых разделов каждой главы, пропуская остальные. В каждой главе несколько первых разделов содержат введение или общую информацию, а следующие разделы- специализированную или техническую информацию. Исключение составляет глава 2 [Введение в make-файлы], целиком являющаяся введением.

Если вы знакомы с другими версиями программы make, смотрите главу 12 [Особенности GNU-версии программы make], в которой перечисляются все дополнительные возможности, имеющиеся в GNU-версии программы make, а также главу 13 [Несовместимость и недостающие возможности], в которой объясняются те немногие возможности, которые отсутствуют в GNU-версии программы make и имеются в других версиях.

Краткий обзор возможностей утилиты можно увидеть в разделе 9.7 [Обзор опций], приложении А [Краткий справочник] и в разделе 4.7 [Специальные цели].

1.2 Проблемы и ошибки

Если у вас возникли проблемы с использованием утилиты make или вам кажется, что вы обнаружили ошибку в ее работе, сообщите об этом разработчикам; мы не можем обещать сделать все, что угодно, но мы хотели бы исправить ошибки.

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

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

Как только вы точно выявили проблему, пошлите, пожалуйста, сообщение по электронной почте через Internet или посредством UUCP:

 адрес в Internet : bug-gnu-<htmlurl name="utils@prep.ai.mit.edu" url="mailto:utils@prep.ai.mit.edu"> UUCP-путь : mit-eddie!prep.ai.mit.edu!bug-gnu-utils
Включите, пожалуйста, в письмо, номер версии make, которой вы пользуетесь. Вы можете получить эту информацию, набрав в командной строке 'make --version'. Проверьте также, что вы включили в сообщение тип используемых Вами машины и операционной системы. Включите, если возможно, содержимое файла 'config.h', который генерируется в процессе конфигурации.

Сообщения, не связанные с ошибками, также всегда приветствуются. Если у вас появились вопросы, связанные с моментами, неясно освещенными в документации, или просто непонятными возможностями, пошлите сообщение на адрес для сообщений об ошибках. Мы не можем гарантировать, что вы получите помощь по вашей проблеме, однако почтовый список читают многолетние пользователь make, и они, вероятно, попытаются вам помочь.


Вперед Назад Содержание
Вперед Назад Содержание

2. Введение в make-файлы

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

В этой главе мы обсудим простой make-файл, который описывает, как компилировать и компоновать тектовый редактор, состоящий из восьми исходных C-файлов и трех заголовочных файлов. Этот make-файл может также указывать программе make, как выполнить различные команды, если явно указан запрос на их исполнение (например, удалить определенные файлы в качестве команды clean). Более сложный пример make-файла можно увидеть в приложении Б [Сложный make-файл].

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

2.1 На что похоже правило

Простой make-файл состоит из "правил" следующего вида:

         ЦЕЛЬ ...        : ЗАВИСИМОСТЬ ...   
              КОМАНДА   
              ...   
              ...   
>
ЦЕЛЬ обычно представляет собой имя файла, генерируемого программой make; примерами целей являются исполняемые или объектные файлы. Цель может также быть именем выполняемого действия, как, например, 'clean' (смотрите раздел 4.4 [Цели-имена действий]).

ЗАВИСИМОСТЬ - это файл, используемый как вход для порождения цели. Часто цель зависит от нескольких файлов.

КОМАНДА - это действие, которое выполняет make. Правило может иметь более, чем одну команду - каждую на своей собственной строке. Важное замечание: вы должны начинать каждую строку, содержащую команды, с символа табуляции. Это является незаметным средством борьбы с неострожностью.

Обычно команда появляется в правиле с зависимостями и служит для создания целевого файла, если какая-либо из зависимостей изменилась. Однако, правило, определяющее команды для цели, не обязательно должно иметь зависимости. Например, правило, содержащее команду удаления, связанную с целью 'clean', не имеет зависимостей.

Правила описывают, как и когда заново порождать определенные файлы, которые являются целями правил. Правило может также описывать, как и когда выполнять действие. Смотрите раздел 4 [Написание правил].

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

2.2 Простой make-файл

Вот простой make-файл, который описывает, как исполняемый файл, называемый edit, зависит от восьми объектных файлов, которые, в свою очередь, зависят от восьми исходных C-файлов и трех заголовочных файлов.

В этом примере все C-файлы включают 'defs.h', но файл 'command.h' включают только те, которые определяют команды редактирования, а файл 'buffer.h' - только файлы низкого уровня, изменяющие буфер редактирования.

      edit : main.o kbd.o command.o display.o \   
             insert.o search.o files.o utils.o   
              cc -o edit main.o kbd.o command.o display.o \   
                         insert.o search.o files.o utils.o   
    
      main.o : main.c defs.h   
              cc -c main.c   
      kbd.o : kbd.c defs.h command.h   
              cc -c kbd.c   
      command.o : command.c defs.h command.h   
              cc -c command.c   
      display.o : display.c defs.h buffer.h   
              cc -c display.c   
      insert.o : insert.c defs.h buffer.h   
              cc -c insert.c   
      search.o : search.c defs.h buffer.h   
              cc -c search.c   
      files.o : files.c defs.h buffer.h command.h   
              cc -c files.c   
      utils.o : utils.c defs.h   
              cc -c utils.c   
      clean :   
              rm edit main.o kbd.o command.o display.o \   
                 insert.o search.o files.o utils.o   
Мы разбиваем каждую длинную строку на две строки, используя обратную косую черту, за которой следует перевод строки; это аналогично использованию одной длинной строки, но легче для чтения.

Чтобы использовать этот make-файл для создания исполняемого файла с именем 'edit', наберите в командной строке:

         make

Чтобы использовать этот make-файл для удаления исполняемого файла и всех объектных файлов из текущего каталога, наберите в командной строке:

         make clean   

В приведенном примере make-файла к целям относятся, в частности, исполняемый файл 'edit' и объектные файлы 'main.o' и 'kbd.o'. К зависимостям относятся такие файлы, как 'main.c' и 'defs.h'. Фактически, каждый объектный файл является как целью, так и зависимостью. Примерами команд являются 'cc -c main.c' и 'cc -c kbd.c'.

Когда цель является файлом, этот файл должен быть перекомпилирован или перекомпонован, если изменилась любая из его зависимостей. Кроме того, любые зависимости, которые сами автоматически генерируются, должны обновляться первыми. В этом примере, 'edit' зависит от каждого из девяти объектных файлов; объектный файл 'main.o' зависит от исходного файла 'main.c' и заголовочного файла 'defs.h'.

За каждой строкой, содержащей цель и зависимости, следует команда. Эти команды указывают, как обновлять целевой файл. В начале каждой командой строки должен располагаться символ табуляции, чтобы отличать командные строки от других строк make-файла. (Держите в уме, что make ничего не знает о том, как работают команды. Обеспечить команды, которые корректно обновят целевой файл - целиком ваша забота. Все, что делает make - это выполнение команд из опреденного вами правила, когда целевой файл должен быть обновлен.)

Цель 'clean' является не файлом, а просто именем действия. Так как обычно вы не хотите выполнять действия из этого правила, 'clean' не является зависимостью какого-либо другого правила. Следовательно, make никогда ничего с ним не сделает, если вы этого специально не укажете. Обратите внимание, что это не только не является зависимостью, оно также не имеет никаких зависимостей, таким образом, единственным предназначением правила является выполнение определенных в правиле команд. Цели, которые не указывают на файлы, а являются просто действиями, называются целями-именами действий. Смотрите раздел 4.4 [Цели-имена действий] для информации об этой разновидности целей. Смотрите раздел 5.4 [Ошибки в командах], где показывается, как заставить make игнорировать ошибки от rm и любых других команд.

2.3 Как make обрабатывает make-файл

По умолчанию, make начинает с первого правила (не считая правил, имена целей у которых начинаются с '.'). Это называется главной целью по умолчанию. ( Главной целью называется цель, обновление которой является изначальной задачей программы make. Смотрите раздел 9.2 [Аргументы для определения главных целей].)

В простом примере из предыдущего раздела главной целью по умолчанию является обновление исполняемой программы 'edit'; следовательно, мы располагаем это правило первым.

Таким образом, когда вы даете команду:

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

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

Перед перекомпиляцией объектного файла make рассматривает время обновления его зависимостей: исходного файла и заголовочных файлов. Данный make-файл не определяет ничего, что должно делаться для их порождения - файлы, имена которых оканчиваются на '.c' и '.h' не являются целями каких-либо правил - таким образом, make ничего не делает для этих файлов. Однако make мог бы обновить автоматически генерируемые C-программы, например, получаемые с помощью программ Bison или Yacc, если бы для них, в этом случае, были определены свои правила.

После перекомпиляции всех объектных файлов, для которых это необходимо, make решает, перекомпоновывать ли 'edit'. Это должно быть сделано, если файл 'edit' не существует, или какой-либо из объектных файлов обновлен позднее его. Если объектный файл был только что перекомпилирован, то сейчас он новее, чем 'edit', так что 'edit' перекомпоновывается.

Таким образом, если мы изменим файл 'insert.c' и запустим make, make откомпилирует этот файл для обновления 'insert.o', и затем скомпонует 'edit'. Если мы изменим файл 'command.h' и запустим make, make перекомпилирует объектные файлы 'kbd.o', 'command.o', и 'files.o', а затем скомпонует 'edit'.

2.4 Переменные упрощают make-файл

В нашем примере мы вынуждены были дважды перечислять все объектные файлы в правиле для 'edit':

      edit : main.o kbd.o command.o display.o \   
                    insert.o search.o files.o utils.o   
              cc -o edit main.o kbd.o command.o display.o \   
                         insert.o search.o files.o utils.o   
Такое дублирование способствует появлению ошибок - если в систему добавляется новый объектный файл, мы можем добавить его в один список и забыть про другой. Мы можем устранить риск и упростить make-файл при помощи использования переменных. Переменная позволяет один раз определить текстовую строку и затем подставлять ее во многих местах (смотрите главу 6 [Как использовать переменные]).

Для любого make-файла стандортной практикой является наличие переменной, называемой objects, OBJECTS, objs, OBJS, obj или OBJ, которая представляет собой список имен всех объектных файлов. Мы могли бы определить такую переменную objects со значением, являющимся списком объектных файлов из приведенного make-файла:

         objects = main.o kbd.o command.o display.o \   
                   insert.o search.o files.o utils.o   
Тогда везде, где мы хотим поместить список имен объектных файлов, мы можем подставить значение переменной, написав '$(objects)' (смотрите главу 6 [Как использовать переменные]).

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

      objects = main.o kbd.o command.o display.o \   
                insert.o search.o files.o utils.o   
    
      edit : $(objects)   
              cc -o edit $(objects)   
      main.o : main.c defs.h   
              cc -c main.c   
      kbd.o : kbd.c defs.h command.h   
              cc -c kbd.c   
      command.o : command.c defs.h command.h   
              cc -c command.c   
      display.o : display.c defs.h buffer.h   
              cc -c display.c   
      insert.o : insert.c defs.h buffer.h   
              cc -c insert.c   
      search.o : search.c defs.h buffer.h   
              cc -c search.c   
      files.o : files.c defs.h buffer.h command.h   
              cc -c files.c   
      utils.o : utils.c defs.h   
              cc -c utils.c   
      clean :   
              rm edit $(objects)   

2.5 Возможность использования неявных команд

Писать команды для компиляции отдельных исходных файлов не является необходимым, поскольку make может сам их определить: он имеет неявное правило для обновления '.o'-файла из соответствующего '.c'-файла, используя команду 'cc -c'. Например, он будет использовать команду 'cc -c main.c -o main.o' для компиляции 'main.c' в 'main.o'. Следовательно, мы можем опустить команды из правил для объектных файлов. Смотрите главу 10 [Использование неявных правил].

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

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

      objects = main.o kbd.o command.o display.o \   
                insert.o search.o files.o utils.o   
    
      edit : $(objects)   
              cc -o edit $(objects)   
    
      main.o : defs.h   
      kbd.o : defs.h command.h   
      command.o : defs.h command.h   
      display.o : defs.h buffer.h   
      insert.o : defs.h buffer.h   
      search.o : defs.h buffer.h   
      files.o : defs.h buffer.h command.h   
      utils.o : defs.h   
    
      .PHONY : clean   
      clean :   
              -rm edit $(objects)   

Именно так нам следует писать make-файл в реальной практике. (Усложнения, связанные с 'clean', опиываются в другом месте. Смотрите раздел 4.4 [Цели-имена действий] и раздел 5.4 [Ошибки в командах].)

Неявные правила важны из-за их удобства. Вы увидите, что они используются часто.

2.6 Еще один стиль make-файла

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

      objects = main.o kbd.o command.o display.o \   
                insert.o search.o files.o utils.o   
    
      edit : $(objects)   
              cc -o edit $(objects)   
    
      $(objects) : defs.h   
      kbd.o command.o files.o : command.h   
      display.o insert.o search.o files.o : buffer.h   
В данном случае 'defs.h' является зависимостью для всех объектных файлов; 'command.h' и 'buffer.h' является зависимостью для определенных файлов, перечисленных в соответствующих правилах.

Является ли это лучшим способом - дело вкуса; этот способ более компактен, тем не менее некоторые недолюбливают его, поскольку считают более удобным располагать информацию о каждой цели в одном месте.

2.7 Правила для очистки каталога

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

Вот как мы могли бы написать правило make для очистки нашего редактора из примера:

         clean:   
              rm edit $(objects)   
На практике, мы могли бы захотеть написать правило несколько более сложным способом, чтобы обработать непредвидельные ситуации. Сделаем следующее:

      .PHONY : clean   
      clean :   
              -rm edit $(objects)   
Это не дает программе make нарушить логику работы, когда используемый файл называется 'clean' и заставляет ее продолжаться вопреки ошибкам со стороны rm. ( смотрите раздел 4.4 [Цели-имена действий]) 5.4 [Ошибки в командах]).

Правило, подобное этому, не следует размещать в начале make-файла, поскольку мы не хотим выполнять его по умолчанию! Таким образом, в примере make-файла мы хотим, чтобы правило для 'edit', которое перекомпилирует редактор, оставалось главной целью по умолчанию.

Так как 'clean' не является зависимостью 'edit', это правило вообще не будет выполняться, если вы дали команду 'make' без аргументов. Для того, чтобы заставить правило выполниться, мы должны набрать 'make clean'. Смотрите главу 9 [Как запускать make].


Вперед Назад Содержание
Вперед Назад Содержание

3. Написание make-файлов

Информация, указывающая программе make, как перекомпилировать систему, получается из специального make-файла.

3.1 Что содержат make-файлы

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

3.2 Как назвать make-файл

По умолчанию, когда программа make ищет make-файл, она пытается использовать следующие имена: 'GNUmakefile', 'makefile' и 'Makefile' (в указанном порядке).

Обычно вам имеет смысл назвать ваш make-файл либо 'makefile', либо 'Makefile'. (Мы рекомендуем 'Makefile', поскольку в этом случае при выводе содержимого каталога он будет выделяться, появляясь в начале списка, рядом с такими важными файлами, как 'README'.) Первое из указанных имен, 'GNUmakefile', не рекомендуется для большинства make-файлов. Вам следует использовать это имя, если ваш make-файл специфичен для GNU make и не будет воспринят другими версиями программы make. Другие версии программы make ищут файлы с именами 'makefile' и 'Makefile', но 'GNUmakefile'.

Если make не находит файла ни с одним из этих имен, он не использует никакого make-файла. Затем вы должны главную цель как аргумент командной строки, и make попытается выяснить, как заново породить ее, используя только встроенные неявные правила. Смотрите главу 10 [Использование неявных правил].

Если вы хотите использовать нестандартное имя для вашего make-файла, вы можете определить имя make-файла с помощью опций '-f' или '--file'. Аргументы '-f <имя файла>' или '--file=<имя файла>'. указывают программе make читать файл с именем <имя файла> в качестве make-файла. При использовании более, чем одной опции '-f <имя файла>' или '--file=<имя файла>', вы можете определить несколько make-файлов. Все указанные make-файлы просто присоединяются друг за другом в указанном порядке. Имена make-файла по умолчанию ('GNUmakefile', 'makefile' и 'Makefile') не проверяются автоматически, если вы определяете опции '-f' или '--file'.

3.3 Включение других make-файлов

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

         include <имя файла> ...   
В качестве имени файла может использоваться шаблон имени файла, используемый в командной оболочке.

В начале строки допустимы пробелы, которые игнорируются, однако символы табуляции недопустимы (если строка начинается с табуляции, она будет рассматриваться как командная строка). Между словом 'include' и именами файлов, а также между именами файлов необходим пробел, а лишние пробелы здесь и в конце директивы игнорируются. В конце строки допустим комментарий, начинающийся с символа '#'. Если имена фалов содержат какие-либо ссылки на переменные или функции, подставляются их значения. Смотрите главу 6 [Как использовать переменные].

Например, если у вас есть три '.mk'-файла , 'a.mk', 'b.mk', и 'c.mk', а вместо $(bar) подставляется 'bish bash', то строка make-файла

         include foo *.mk $(bar)   
эквивалентна строке

         include foo a.mk b.mk c.mk bish bash   
Когда make обрабатывает директиву include, он приостанавливает чтение текущего make-файла и считывает по очереди каждый файл, перечисленный в списке. По завершении этого, make продолжает чтение make-файла, в котором появилась директива.

Одной из причин использования директивы include является наличие нескольких программ, которые обрабатываются индивидуальными make-файлами в различных каталогах, и которым требуется общий набор определений переменных (смотрите раздел 6.5 [Установка переменных]) или шаблонных правил (смотрите раздел 10.5 [Определение и переопределение шаблонных правил]).

Еще одной такой причиной является желание использовать автоматическую генерации зависимостей из исходного файла; зависимости могут быть помещены в файл, который включается в основной make-файл. Такая практика является, вообще говоря, более ясной, чем просто добавление зависимостей в конец основного make-файла, как традиционно делалось в других версиях make. Смотрите раздел 4.12 [Автоматические зависимости].

Если указанное имя не начинается с символа '/' и файл не найден в текущем каталоге, производится поиск еще в нескольких каталогах. Во-первых, поиск производится во всех каталогах, определенных вами с помощью опции '-I' или '--include-dir' (смотрите раздел 9.7 [Обзор опций]). Затем поиск ведется в следующих каталогах: '/usr/local/include' (вместо '/usr/local' может быть другой префикс), '/usr/gnu/include', '/usr/local/include', '/usr/include' (именно в таком порядке).

Если включаемый make-файл не может быть найден ни в одном из этих каталогов, порождается предепреждающее сообщение, но оно само по себе не является фатальной ошибкой - обработка make-файла, содержащего include, продолжается. Завершив чтение make-файлов, make попытается переделать все make-файлы, которые устарели или не существуют. Смотрите раздел 3.5 [Как переделываются make-файлы]. Только после неудачной попытки найти способ переделать make-файл make сообщит об отсутствии файла как о фатальной ошибке.

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

         -include <имя файла> ...   
Эта директива действует так, что от нее не будет сообщений об ошибке (даже предупреждений, если любой из указанных файлов не существует).

3.4 Переменная MAKEFILES

Если определена переменная окружения MAKEFILES, make рассматривает ее значение как список имен (разделенных пробелами) дополнительных make-файлов, которые считываются перед другими. Это работает во многом так же, как и директива include: поиск этих файлов производится в различных каталогах (смотрите раздел 3.3 [Включение других make-файлов]). При этом главная цель по умолчанию никогда не берется из этих make-файлов, а при неудачном поиске файлов, указанных в MAKEFILES сообщение об ошибке не порождается.

Основное использование переменной MAINFILES - связь между рекурсивными вызовами make (смотрите раздел 5.6 [Рекурсивное использование программы make]). Обычно нежелательно устанавливать переменные окружения перед вызовом make на верхнем уровне, поскольку лучше не беспокоиться о внутренностях make-файла извне. Однако, если вы запускаете make, не определяя make-файл, make-файл, указанный в переменной окружения $MAKEFILES, может сделать что-нибудь полезное, чтобы улучшить работу встроенных неявных правил, например определить пути поиска (смотрите раздел 4.3 [Поиск по каталогам]).

Некоторые пользователь соблазняются возможностью автоматически устанавливать переменную окружения MAKEFILES при входе в систему, и создают make-файлы в расчете на это. Это очень плохая идея, поскольку такие make-файлы не смогут работать где-либо еще. Намного лучше явно написать директиву include в make-файле. Смотрите раздел 3.3 [Включение других make-файлов])

3.5 Как переделываются make-файлы

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

Для этого после считывания всех make-файлов make будет рассматривать каждый из них в качестве главной цели и попытается произвести обновление. Если make-файл имеет правило, указывающее, как обновлять его (найденное в том же самом make-файле или в каком-либо другом) или если имеется неявное правило, применимое к нему (смотрите главу 10 [Использование неявных правил]), то он, при необходимости, будет обновлен. После того, как были проверены все make-файлы, в том случае, если какой-нибудь из них на самом деле был изменен, make начинает все с нуля и заново считывает все make-файлы. (Он снова попытается обновить каждый из них, но обычно они уже не изменятся, так как обновление только что было произведено).

Если make-файлы определяют для порождения файла заново правило с двойным двоеточием, у которого есть команды, но нет зависимостей, этот файл всегда будет переделываться (смотрите раздел 4.11 [Двойное двоеточие]). В случае make-файла, make-файл, для которого существует правило с двойным двоеточием, в котором есть команды, но нет зависимостей будет переделываться каждый раз при запуске make, затем - еще раз, когда make начнет считывание с нуля и прочитает заново все make-файлы. Это приведет к бесконечному циклу: make будет постоянно переделавать make-файл, и никогда не займется ничем другим. Таким образом, чтобы избежать этого, make не будет пытаться переделать make-файлы, которые определены как цели правил с двойным двоеточием, но не имеют зависимостей.

Если вы не определяете никакой из make-файлов для считывания при помощи опций '-f' или '--file', make попробует использовать имена make-файлов по умолчанию - смотрите раздел 3.2 [Как назвать make-файл]. В отличие от make-файлов, явно указанных с использованием опций '-f' или '--file', make не уверен, что эти файлы должны существовать. Однако, если make-файл по умолчанию не существует, но может быть создан выполнением правил make, вы , вероятно захотите, чтобы эти правила выполнились, и полученный make-файл мог быть использован.

Следовательно, если ни один из make-файлов по умолчанию не существует, make попробует породить каждый из них в том же порядке, в котором они ищутся (смотрите раздел 3.2 [Как назвать make-файл]), до тех пор пор пока его попытки порождения make-файла не увенчаются успехом или он не переберет все возможные имена. Заметьте, что невозможность найти или породить make-файл не является ошибкой - make-файл не всегда необходим.

При использовании опции '-t' или '--touch', (смотрите раздел 9.3 [Вместо исполнения команд]), вы бы не хотели использовать устаревший make-файл для определения того, какие цели необходимо пометить как обновленные. Таким образом, опция '-t' не оказывает влияния на обновление make-файлов - они обновляются даже тогда, когда она указана. Аналогично, опции '-q' (или '--question') и '-n' (или '--just-print') не предотвращают обновления make-файлов, поскольку устаревший make-файл привел бы к некорректному результату для других целей. Таким образом, 'make -f mfile -n foo' обновит 'mfile', считает его, и затем напечатает команды для обновления 'foo' и его зависимости без исполнения команд. Команды, печатаемые для 'foo' будут браться из обновленного файла 'mfile'.

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

Таким образом, 'make -f mfile -n mfile foo' прочитает make-файл 'mfile', напечатает команды, необходимые для его обновления без их выполнения, а затем напечатает команды, необходимые для обновления 'foo' без их выполнения. Команды, печатаемые для 'foo' будут браться из существующего файла 'mfile'.

3.6 Перекрытие части другого make-файла

Иногда полезно иметь make-файл, который большей частью похож на другой make-файл. Часто вы можете использовать директиву 'include' для включения одного файла в другой, и добавлять дополнительные цели или определения переменных. Однако, если два make-файла предложат различные команды для одной и той же цели, make не позволит вам сделать этого. Тем не менее есть еще один способ.

Во включающем make-файле (в make-файле, в который включается другой make-файл) вы можете использовать шаблонное правило произвольного соответствия, чтобы указать программе make, что для порождения целей, которые не могут быть созданы на основе информации из включающего файла, необходимо использовать другой make-файл. Смотрите раздел 10.5 [Шаблонные правила] для дополнительной информации о шаблонных правилах.

Например, если у вас есть make-файл с именем 'Makefile', который указывает, как порождать 'foo' (и другие цели), вы можете написать make-файл с именем 'GNUMakefile', который содержит:

      foo:   
           frobnicate > foo   
    
      %: force   
               @      $(MAKE) -f Makefile $@   
      force: ;   
Если вы напишете в командной строке 'make foo', make найдет 'GNUMakefile', прочитает его и выяснит, что для порождения 'foo' необходимо выполнить команду 'frobnicate > foo'.Если вы напишете в командной строке 'make bar', make не найдет в 'GNUMakefile' способа для порождения 'bar'. Таким образом, он будет использовать команду из шаблонного правила: 'make -f Makefile bar'. Если в 'Makefile' имеется правило для порождения bar, оно будет применено. Аналогично будет обработана любая другая цель, для которой правило порождения не указано в 'GNUMakefile'.

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


Вперед Назад Содержание
Вперед Назад Содержание

4. Написание правил

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

Порядок правил несущественнен, за исключением определения главной цели по умолчанию: цели, с которой начинается работа make, если вы ее не определили. По умолчанию главной целью make является цель первого правила в первом make-файле. Если в первом правиле есть несколько целей, то только первая цель берется в качестве главной цели по умолчанию. Есть два исключения: цель, начинающаяся с точки, не является главной целью по умолчанию, если она не содержит при этом один или более символа '/'; кроме того, цель, определяющая шаблонное правило, не воздействует на определение главной цели по умолчанию. Смотрите раздел 10.5 [Определение и переопределение шаблонных правил].

Поэтому обычно make-файл пишется так, чтобы первое правило было правилом для компиляции всей программы или всех программ, описываемых make-файлом (часто с именем цели 'all'). Смотрите раздел 9.2 [Аргументы для определения целей].

4.1 Синтаксис правила

В общем виде, правило имеет следующий вид:

         ЦЕЛИ : ЗАВИСИМОСТИ   
              КОМАНДА   
              ...   
или такой:

         ЦЕЛИ : ЗАВИСИМОСТИ ; КОМАНДА   
              КОМАНДА   
              ...   
Слева от двоеточия необходимо указать список имен файлов, разделенных пробелами. При этом могут использоваться шаблонные символы (смотрите раздел 4.2 [Использование шаблонных символов в именах файлов]), а имя в форме 'a(m)' представляет элемент m архивного файла a (Смотрите раздел 11.1 [Элементы архива в качестве целей]). Обычно в правиле присутствует только одна цель, но иногда есть смысл сделать больше (смотрите раздел 4.8 [Несколько целей в правиле]).

Командные строки начинаются с символа табуляции. Первая команда может появится после строки зависимостей, предваренная символом табуляции, или на той же строке, что и зависимости, предваренная символом ';'. Оба способа имеют одинаковый эффект. Смотрите главу 5 [Написание команд в правилах].

Поскольку знак доллара используется в начале переменных, в том случае, если вы хотите поместить сам по себе знак доллара, напишите '$$' (смотрите главу 6 [Как использовать переменные]). Вы можете разбивать длинную строку путем вставки обратной косой чертой, за которой следует перевод строки, однако это не является обязательным требованием, потому что make не устанавливает ограничения на длину строк в make-файле.

Правило несет два вида информации: когда цели находятся в неактуальном состоянии и как, при необходимости, обновить их.

Критерий неактуального состояния определяется в терминах зависимостей, которые состоят из имен файлов, разделенных пробелами. (Допустимы также шаблонные символы и элементы архивов (Смотрите главу 11 [Элементы архива в качестве целей])). Цель считается неактуальной, если она не существует, или она более старая, чем одна из зависимостей (по результатам сревнения времен последних изменений). Идея состоит в том, что содержимое целевого файла вычисляется на основе информации, содержащейся в зависимостях; таким образом, как только любая из зависимостей изменяется, содержимое существующего целевого файла необязательно будет корректнм.

То, как надо обновлять цели, определяется набором команд. Команды представляют собой строки, которые будут выполнены командной оболочкой, но с некоторыми дополнительными возможностями. (Смотрите главу 5 [Написание команд в правилах]).

4.2 Использование шаблонных символов в именах файлов

При использовании шаблонных символов одно имя файла может определять несколько файлов. Шаблонными символами для make являются '*', '?' и '[...]', как и в командной оболочке Bourne shell. Например, '*.c' определяет список всех файлов (в рабочем каталоге), чьи имена заканчиваются на '.c'.

Символ '~' в начале имени файла также имеет специальное значение. Если он один или за ним следует символ '/', он представляет ваш домашний каталог. Например, '~/bin' означает 'home/you/bin'. Если за символом '~' следует слово, строка представляет домашний каталог пользователя, именем которого является это слово. Например, '~john/bin' означает 'home/john/bin'.

Обработка шаблонов автоматически осуществляется в целях, в зависимостях или в командах (где обработку шаблонов осуществляет командная оболочка). В других ситуациях обработка шаблонов производится только тогда, когда явно ее закажете путем использования функции wildcard.

Специальное значение шаблонного символа выключается предшествующей ему обратной косой чертой. Таким образом, 'foo\*bar' ссылается на особый файл, чье имя состоит из 'foo', звездочки и 'bar'.

Примеры шаблонов

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

      clean:   
              rm -f *.o   

Шаблоны также полезны в зависимостях правила. При использовании следующего правила в make-файле, 'make print' напечает все '.c'-файлы, которые были изменены с моменты последней их печати:

      print: *.c   
              lpr -p $?   
              touch print   
Это правило использует 'print' как пустой целевой файл; смотрите раздел 4.6 [Пустые целевые файлы для фиксации событий]. (Автоматическая переменная '$?' используется для печати тех файлов, которые были изменены; смотрите раздел 10.5.3 [Автоматические переменные].)

Обработка шаблонов не осуществляется в момент определения переменной. Таким образом, если вы напишете:

      objects = *.o   
то значением переменной objects будет именно строка '*.o'. Однако, если вы используете значение этой переменной в цели, зависимости или команде, то при обработке соответствующего правила произойдет обработка шаблона. Чтобы установить в objects результат обработки шаблона, используйте следующую конструкцию:

      objects := $(wildcard *.o)   

Ловушки в использовании шаблонов

Здесь приводится пример наивного использования обработки шаблонов, при которой делается не то, что вы могли бы предположить. Предположим, вы хотели бы указать, что исполняемый файл 'foo' создается из всех объектных файлов каталога, и вы пишете следующее:

         objects = *.o   
    
         foo : $(objects)   
               cc -o foo $(CFLAGS) $(objects)   
Значение переменной objects - строка '*.o'. Обработка шаблона происходит в правиле для 'foo', поэтому каждый существующий '.o'-файл становится зависимостью для 'foo' и будет, при необходимости, перекомпилироваться.

Но что будет, если вы удалите все '.o'-файлы? Когда шаблону не соответствует ни один файл, он остается в первозданном виде, и, таким образом, 'foo' будет зависеть от файла со странным именем '*.o'. Поскольку, вероятнее всего, такого файла не существует, make выдаст вам ошибку, говорящую о том, что он не может выяснить, как породить '*.o'. Это не то, чего вы хотите!

На самом деле, достичь желаемого результата при помощи обработки шаблонов возможно, но для этого нужны более развитые методы, включающие в себя функцию wildcard и строковые подстановки. Они описываются в следующем разделе.

Функция wildcard

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

      $(wildcard ШАБЛОН...)   
Эта строка, будучи использованной в любом месте make-файла, заменяется на разделенный пробелами список имен существующих файлов, соответствующих одному из данных шаблонов имени файла. Если ни один существующий файл не удовлетворяет шаблону, то шаблон не включается в вывод функции wildcard. Обратите внимание, что это отличается от того, как обрабатываются шаблоны без соответствий в правилах make-файла, где они не игнорируются, а используются в первоначальном виде (смотрите раздел 4.2.2 [Ловушки в использовании шаблонов]).

Одно из использований функции wildcard - получение списка всех исходных C-файлов каталога, что делается следующим образом:

      $(wildcard *.c)   
Мы может заменить список исходных C-файлов на список объектных файлов путем замены в результате функции суффикса '.c' на '.o', как показано ниже:

      $(patsubst %.c,%.o,$(wildcard *.c))   
(Здесь мы использовали еще одну функцию, patsubst. Смотрите раздел 8.2 [Функции подстановки и анализа строк].)

Таким образом, make-файл для компиляции всех исходных C-файлов в каталоге и последующей их компоновки мог бы быть написан следующим образом:

      objects := $(patsubst %.c,%.o,$(wildcard *.c))   
    
      foo : $(objects)   
              cc -o foo $(objects)   
(Здесь используются преимущества неявного правила для компиляции C-программ, поэтому нет необходимости писать явные правила для компиляции файлов. Смотрите раздел 6.2 [Две разновидности переменных] для объяснения знака ':=', являющегося вариантом знака '='.)

4.3 Поиск зависимостей по каталогам

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

VPATH: Путь поиска для всех зависимостей

Значение переменной программы make VPATH определяет список каталогов, в которых следует осуществлять поиск. Чаще всего предполагается, что в этих каталогах содержатся файлы зависимостей, которых нет в текущем каталоге, однако, VPATH определяет список путей поиска, который make применяет ко всем файлам, включая файлы, являющиеся целями правил.

Таким образом, если файл, упомянутый как цель или зависимость, не существует в текущем каталоге, make ищет файл с таким именем в каталогах, перечисленных в VPATH. Если в одном из них такой файл найден, то он становится зависимостью. Таким образом, правила могут указывать среди зависимостей имена исходных файлов, как если бы они они все существовали в текущем каталоге. Смотрите раздел 4.3.3 [Написание команд командной оболочки с учетом поиска по каталогам].

В переменной VPATH имена каталогов разделяются двоеточиями или пробелами. При поиске make перебирает каталоги в том порядке, в котором они перечислены.

Например,

      VPATH = src:../headers   
определяет пути поиска, включающие два каталога, 'src' и '../headers', которые make будет в таком порядке перебирать при поиске.

При этом значении VPATH следующее правило:

      foo.o : foo.c   
интерпретируется так, как будто оно написано так:

      foo.o : src/foo.c   
при условии, что файл 'foo' не существует в текущем каталоге, но найден в каталоге 'src'.

Директива vpath

Средством, аналогичным переменной VPATH, но более гибким, является директива vpath (обратите внимание на маленькие буквы), которая позволяет определить путь поиска для определенного класса имен файлов, удовлетворяющих определенному шаблону. Таким образом, вы можете выделить некоторые каталоги поиска для одного класса имен файлов, а другие (или никаких) - для других имен файлов.

Есть три формы директивы VPATH:

vpath ШАБЛОН КАТАЛОГИ

Определяет пути поиска для имен файлов, соответствующих ШАБЛОНу. КАТАЛОГИ представляют собой список каталогов для поиска, разделенный двоеточиями или пробелами, по аналогии с путями поиска, используемыми в переменной VPATH

vpath ШАБЛОН

Очищает пути поиска, связанные с ШАБЛОНом

vpath

Очищает все пути поиска, ранее назначенные директивами vpath

Шаблон vpath является строкой, содержащей символ '%'. Имя файла зависимости, поиск которого осуществляется, должно соответствовать этой строке, причем символ '%' соответствует любой последовательности, содержащей нуль или более символов (как в шаблонных правилах; смотрите раздел 10.5 [Определение и переопределение шаблонных правил]). Например, '%.h' соответствует файлам, которые заканчиваются на .h. (Если нет символа '%', то зависимость должна точно соответствовать шаблону, что бывает нужным не очень часто).

Специальное назначение символа '%' в шаблоне директивы vpath может быть отменено предшествующим символом '\'. Специальное назначение символа '\', который в противном случае отменял бы специальное назначение последующего символа '%', может быть отменено еще одним символом '\'. Символы '\', отменяющие специальное назначение символов '%' или других символов '\', удаляются из шаблона перед тем, как ему будут сопоставляться имена файлов. Символы '\', которые заведемо не влияют на трактовку символа '%', остаются нетронутыми.

Если файл зависимости в текущем каталоге не существует, то в том случае, когда его имя соответствует шаблону из директивы vpath, поиск осуществляется в каталогах, указанных в той директиве, как если бы они были упомянуты в переменной VPATH (причем, поиск в этих каталогах осуществляется перед поиском в тех каталогах, которые на самом деле указаны в переменной VPATH).

Например, строка

      vpath %.h ../headers   
указывает программе make искать любой файл зависимости, чье имя заканчивается на '.h' в каталоге '../headers', если такой файл не найден в текущем каталоге.

Если имя файла зависимости удовлетворяет нескольким шаблонам vpath, make обрабатывает одну за другой каждую подходящую директиву vpath, осуществляя поиск во всех каталогах, упомянутых в каждой такой директиве. make обрабатывает несколько директив vpath в том порядке, в котором они появляются в make-файле; несколько директив с одинаковым шаблоном не влияют друг на друга.

Таким образом, этот фрагмент

      vpath %.c foo   
      vpath %   blish   
      vpath %.c bar   
означает поиск файла, оканчивающегося на '.c' в каталоге 'foo', затем 'blish', затем 'bar', в то время как этот фрагмент

      vpath %.c foo:bar   
      vpath %   blish   
означает поиск файла, оканчивающегося на '.c' в каталоге 'foo', затем 'bar', затем 'blish'.

Написание команд командной оболочки с учетом поиска по каталогам

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

Это делается с помощью автоматических переменных, таких как '$^' (смотрите раздел 10.5.3 [Автоматические переменные]). Например, значением '$^' является список всех зависимостей правила, включая имена каталогов, в которых они были найдены, а значением '$@ ' - цель. Например:

      foo.o : foo.c   
              cc -c $(CFLAGS) $^ -o $@         
(Переменная CFLAGS существует для тог, чтобы вы могли определить флаги для C-компиляции посредством неявных правил. Мы используем ее из соображений последовательности, в результате чего она будет одинаково влиять на C-компиляцию. Смотрите раздел 10.3 [Переменные, используемые неявными правилами].)

Часто зависимости также включают в себя заголовочные файлы, которые вы не хотите упоминать в команде. Автоматическая переменная '$<' является просто первой зависимостью.

      VPATH = src:../headers   
      foo.o : foo.c defs.h hack.h   
              cc -c $(CFLAGS) $< -o $@         

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

Поиск в каталогах, определенных в переменной VPATH или при помощи директивы vpath происходит также в случае неявных правил (смотрите главу 10 [Использование неявных правил])

Например, если файл 'foo.o' не имеет явных правил, make рассматривает неявные правила, такие как встроенное правило для компиляции 'foo.c', если такой файл существует. Если такого файла нет в текущем каталоге, то он ищется в соответствующих каталогах для поиска. Если файл 'foo.c' существует (или упоминается в make-файле) в любом из каталогов, применяется неявное правило для C-компиляции.

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

Поиск по каталогам библиотек для компоновки

Поиск по каталогам библиотек, используемых компоновщиком, применяется особым образом. Эта специфическая особенность вступает в силу, когда вы пишете зависимость, имя которой имеет форму '-l<имя файла>'. (Вы можете сказать, что здесь происходит что-то странное, поскольку зависимость обычно является именем файла, а имя библиотечного файла имеет вид 'lib<имя файла>.a', а не '-l<имя файла>'.)

Когда имя зависимости имеет форму '-l<имя файла>', make специально обрабатывает его, устраивая поиска файла 'lib<имя файла>.a' в текущем каталоге, в каталогах, определенных путями поиска, соответствующими шаблонам директивы vpath и путями поиска из переменной VPATH, а затем в каталогах '/lib', '/usr/lib' и <префикс>/lib (обычно '/usr/local/lib').

Например, правило

         foo : foo.c -lcurses   
               cc $^ -o $@         
вызовет исполнение команды 'cc foo.c /usr/lib/libcurses.a -o foo', если 'foo' более старый, чем 'foo.c' или '/usr/lib/libcurses.a'.

4.4 Цели-имена действий

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

Если вы пишете правило, команды которого не будут создавать целевой файл, команды будут выполняться каждый раз, когда придет время порождать цель. Вот пример:

      clean:   
              rm *.o temp   
Поскольку команда rm не создает файл с именем 'clean', вероятно такой файл никогда не будет существовать.

Цель-имя действия прекратит работу, если кто-нибудь когда-нибудь создаст в этом каталоге файл 'clean'. По причине отсутствия зависимостей, файл 'clean' непременно будет считаться свежим, и команды из соответствующего правила не выполняться не будут. Чтобы избежать этой проблемы, вы можете явно объявить цель как имя действия, используя специальную цель .PHONY (смотрите раздел 4.7 [Специальные встроенные имена целей]), как показано ниже:

      .PHONY : clean   
Как только это сделано, 'make clean' выполнит команды, независимо от того, есть ли файл с именем 'clean'.

Зная, что цель-имя действия не именует настоящий файл, который может быть переделан из других файлов, make пропускает поиск неявного правила для цели-имени действия (смотрите главу 10 [Использование неявных правил]). Именно поэтому объявление цели-имени действия положительно сказывается на производительности, даже если вас не беспокоит возможное существование настоящего файла с таким именем.

Таким образом, вы сначала пишете строку, которая устанавливает clean в качестве цели-имени действия, а затем пишете правило, как показано ниже:

      .PHONY: clean   
      clean:   
              rm *.o temp   
Цель-имя дествия не должна быть зависимостью реального целевого файла; если это так, ее команды выполняются каждый раз, когда make обновляет этой файл. До тех пор, пока цель-имя действия не является зависимостью никакой реальной цели, ее команды будут исполняться только тогда, когда цель-имя действия определена как главная цель (смотрите раздел 9.2 [Аргументы для определения целей]).

Цели-имена действий могут иметь зависимости. Когда в одном каталоге содержится много программ, наиболее удобно описать все программы в одном make-файле './Makefile'. Поскольку заново порождаемой целью по умолчанию станет первая цель в make-файле, удобно сделать ею цель-имя действия под названием 'all' и дать ей в качестве зависимостей все отдельные программы. Например:

      all : prog1 prog2 prog3   
      .PHONY : all   
    
      prog1 : prog1.o utils.o   
              cc -o prog1 prog1.o utils.o   
    
      prog2 : prog2.o   
              cc -o prog2 prog2.o   
    
      prog3 : prog3.o sort.o utils.o   
              cc -o prog3 prog3.o sort.o utils.o   

Теперь вы можете просто набрать в командной строке 'make', чтобы переделать все три программы или определить в качестве аргументов те, что необходимо переделать (например, 'make prog1 prog2').

Когда одна цель-имя действия является зависимостью другой, она служит в качестве ее подпрогораммы. Например, здесь 'make cleanall' удалит объектные файлы, файлы различий и файл 'program'.

      .PHONY: cleanall cleanobj cleandiff   
    
      cleanall : cleanobj cleandiff   
              rm program   
    
      cleanobj :   
              rm *.o   
    
      cleandiff :   
              rm *.diff   

4.5 Правила без команд и зависимостей

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

Проиллюстрируем это примером:

      clean: FORCE   
              rm $(objects)   
      FORCE:   
Здесь правило для цели 'FORCE' удовлетворяет указанным условиям, поэтому цель 'clean', зависящая от нее, вынуждена выполнять свои команды. В имени 'FORCE' нет ничего специального, однако это имя часто используется в таких случаях.

Как можно видеть, использование 'FORCE' таким способом дает такой же результат, как и использование '.PHONY : clean'.

Использование '.PHONY' более наглядно и более эффективно. Однако, другие версии make не поддерживают '.PHONY', поэтому 'FORCE' появляется во многих make-файлах. Смотрите раздел 4.4 [Цели-имена действий].

4.6 Пустые целевые файлы для фиксации событий

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

Предназначение пустого целевого файла - зафиксировать, с помощью времени его последней модификации, когда в последний раз исполнялись команды из правила. Это делается при помощи включения в набор команд команды touch для обновления целевого файла.

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

      print: foo.c bar.c   
              lpr -p $?   
              touch print   
Согласно этому правилу, 'make print' выполнит команду lpr, если какой-нибудь исходный файл был изменен с момента последнего 'make print'. Автоматическая переменная '$?' используется для того, чтобы печатать только те файлы, которые изменились (смотрите раздел 10.5.3 [Автоматические переменные]).

4.7 Специальные встроенные имена целей

Некоторые имена, появляясь в качестве целей, имеют специальное значение.

.PHONY

Зависимости специальной цели .PHONY рассматриваются как цели-имена действий. Когда придет время рассматривать такую цель, make выполнит команды в безусловном режиме, независимо от того, существует ли такой файл и от того, какого время его последней модификации. Смотрите раздел 4.4 [Цели-имена действий].

.SUFFIXES

Зависимости специальной цели .SUFFIXES представляют собой список суффиксов, которые будут использоваться при проверке суффиксных правил. Смотрите раздел 10.7 [Устаревшие суффиксные правила].

.DEFAULT

Команды, определенные для .DEFAULT, используются с любыми целями, для которых не найдено правил (как явных, так и неявных). Смотрите раздел 10.6 [Последняя возможность]. Если определены команды для .DEFAULT, то они будут исполняться для каждого файла, упомянутого в качестве зависимости, но не являющегося целью какого-либо правила. Смотрите раздел 10.8 [Алгоритм поиска неявного правила].

.PRECIOUS

Цели, от которых зависит .PRECIOUS, подвергаются специальной обработке: если make уничтожается или прерывается при выполнении соответствующих им команд, цель не удаляется. Смотрите раздел 5.5 [Прерывание или уничтожение программы make]. Кроме того, если цель представляет собой промежуточный файл, он не будет удален после того, как необходимость в нем отпала, как это обычно делается. Смотрите раздел 10.4 [Цепочки неявных правил].

Вы можете также указать шаблон цели неявного правила (как, например, '%.o') в качестве файла зависимости специальной цели .PRECIOUS, чтобы сохранить промежуточные файлы, созданные посредством правил, шаблонам целей которых соответствуют имена этих файлов.

.IGNORE

Если вы определяете зависимости для .IGNORE, то make будет игнорировать ошибки при выполнении команд, запускаемых для этих особых файлов. Команды для .IGNORE роли не играют.

Если .IGNORE определяется как цель без зависимостей, это значит, что необходимо игнорировать ошибки при выполнении команд для всех файлов. Такое использование .IGNORE

поддерживается только для исторической совместимости. Этот прием не очень полезен, поскольку он воздействует на любую команду в make-файле; мы рекомендуем вам использовать более гибкие способы игнорирования ошибок в отдельных командах. Смотрите раздел 5.4 [Ошибки в командах].

.SILENT

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

Если .IGNORE определяется как цель без зависимостей, это значит, что необходимо подавлять печать любой команды перед ее выполнением. Такое использование .SILENT поддерживается только для исторической совместимости. Мы рекомендуем вам использовать более гибкие способы подавления печати перед выполнением отдельных команд. Смотрите раздел 5.1 [Отображение команды]. Если вы хотите подавить печать всех команд при определенном запуске make, используйте опцию '-s' или '--silent' (смотрите раздел 9.7 [Обзор опций]).

.EXPORT_ALL_VARIABLES

Будучи просто упомянутой в качестве цели, указывает программе make по умолчанию экспортировать порожденным процессам все переменные. Смотрите раздел 5.6.2 [Связь порожденным процессом make через переменные].

В качестве специальной цели рассматривается также любой суффикс из определения неявного правила, так же как и конкатенация двух суффиксов, как, например, '.c.o'. Эти цели представляют собой суффиксные правила, устаревший способ определения неявных правил (однако, все еще широко распространенный). В принципе, любое имя цели могло бы таким образом стать специальным, если бы вы разбили его на две части и добавили обе к списку суффиксов. На практике же суффиксы обычно начинаются с '.', поэтому эти специальные имена цели также начинаются с '.'. Смотрите раздел 10.7 [Устаревшие суффиксные правила].

4.8 Несколько целей в правиле

Правило с несколькими целями эквивалентно написанию нескольких правил, каждое из которых имеет одну цель, и идентичных во всем остальном. Ко всем целям применяются одни и те же команды, но их действия могут меняться, поскольку вы можете подставлять в команду конкретное имя цели, используя '$@ '. Правило также распространяет действие всех зависимостей на все цели этого правила.

Это полезно в двух случаях.

Допустим, вы хотели бы изменять зависимости в соответствии с целью аналогично тому, как переменная '$@ ' позволяет вам изменять команды. Вы не можете сделать этого при использовании обычного правила с несколькими целями, но это можно сделать при помощи статического шаблонного правила. Смотрите раздел 4.10 "Статические шаблонные правила".

4.9 Несколько правил для одной цели

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

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

Дополнительное правило, содержащее только зависимости, может быть использовано для добавления нескольких дополнительных зависимостей одновременно к нескольким файлам. Например, обычно имеется переменная с именем objects, содержащая список всех файлов, являющихся выходом компилятора в порождаемой системе. Легкий способ указать, что все они должны быть перекомпилированы, если изменился файл 'config.h' - написать следующее :

      objects = foo.o bar.o   
      foo.o : defs.h   
      bar.o : defs.h test.h   
      $(objects) : config.h   
Это могло быть вставлено или убрано без изменения правил, которые действительно определяют, как порождать объектные файлы, что является удобным для использования способом, если вы хотите в произвольном месте добавлять дополнительные зависимости.

Еще один полезный совет состоит в том, что дополнительные зависимости могут быть определены при помощи переменной, которую вы устанавливаете в аргументе командной строки для make. (смотрите раздел 9.5 [Перекрывающиеся переменные]). Например, правило

      extradeps=   
      $(objects) : $(extradeps)   
означает, что команда 'make extradeps=foo.h' будет рассматривать 'foo.h' в качестве зависимости для каждого объектного файла, а просто 'make' - не будет.

Если ни одно из явных правил для цели не имеет команд, то make организует поиск применимого неявного правила, чтобы найти какие-нибудь команды (смотрите главу 10 [Использование неявных правил]).

4.10 Статические шаблонные правила

Статические шаблонные правила - это правила, которые определяют несколько целей и создают имена зависимостей для каждой цели на основе имени цели. Они являются более общими, чем обычные правила с несколькими целями, поскольку цели не должны иметь одинаковые зависимости. Их цели должны быть похожими, но не обязательно одинаковыми.

Синтаксис статических шаблонных правил

Здесь приведен синтаксис статического шаблонного правила:

      ЦЕЛИ ...: ШАБЛОН ЦЕЛИ: ШАБЛОНЫ ЗАВИСИМОСТЕЙ ...   
              КОМАНДЫ   
              ...   
Список ЦЕЛЕЙ определяет цели, к которым применяется правило. Цели могут содержать шаблонные символы, так же как и цели обычных правил (смотрите раздел 4.2 [Использование шаблонных символов в именах файлов]).

ШАБЛОН ЦЕЛИ и ШАБЛОНЫ ЗАВИСИМОСТЕЙ указывают, как вычислять зависимости каждой цели. К каждой цели применяется шаблон цели для получения части имени цели, называемой основой. Эта основа подставляется в каждый из шаблонов зависимостей, в результате чего порождаются имена зависимостей (по одному из каждого шаблона зависимости).

Обычно каждый шаблон содержит ровно один символ '%'. Когда цель сопоставляется шаблону цели, символ '%' соответствует незафиксированной части имени цели - эта часть называется основой. Оставшаяся часть шаблона должна точно соответствовать имени цели. Например, цель 'foo.o' удовлетворяет шаблону '%.o', при этом 'foo' является основой. Цели 'foo.c' и 'foo.out' не удовлетворяют шаблону.

Имена зависимостей для каждой цели соэдаются путем подстановки основы вместо символа '%' в каждый шаблон зависимости. Например, если единственный шаблон зависимости - '%.c', то подстановка основы 'foo' дает имя зависимости 'foo.c'. Является законным написание шаблона зависимости, не содержащего '%' - в таком случае данная зависимость одинакова для всех целей.

Специальное назначение символа '%' в шаблоне правила может быть отменено предшествующим символом '\'. Специальное назначение символа '\', который в противном случае отменял бы специальное назначение последующего символа '%', может быть отменено еще одним символом '\'. Символы '\', отменяющие специальное назначение символов '%' или других символов '\', удаляются из шаблона перед тем, как он будет сравниваться с именами файлов или в него будет подставляться основа. Символы '\', которые заведомо не влияют на трактовку символа '%', остаются нетронутыми. Например, в шаблоне 'the\%weird\\%pattern\\', фрагмент 'the%weird\' предшествует действующему символу '%', а фрагмент 'pattern\\' следует за ним. Последние два символа '\' остаются на месте, поскольку они не могут воздействовать ни на какой символ '%'.

Вот пример, который компилирует или 'foo.o' или 'bar.o' из соответствующего '.c'-файла:

      objects = foo.o bar.o   
    
      $(objects): %.o: %.c   
              $(CC) -c $(CFLAGS) $< -o $@         
Здесь '$<' является автоматической переменной, которая содержит имя зависимости, а '$@ ' - автоматической переменной которая содержит имя цели; смотрите раздел 10.5.3 [Автоматические переменные].

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

      files = foo.elc bar.o lose.o   
    
      $(filter %.o,$(files)): %.o: %.c   
              $(CC) -c $(CFLAGS) $< -o $@         
      $(filter %.elc,$(files)): %.elc: %.el   
              emacs -f batch-byte-compile $<   
В этом примере результатом '$(filter %.o,$(files))' является 'bar.o lose.o', и первое статическое шаблонное правило вызывает обновление каждого из этих объектных файлов путем компиляции соответствующих исходных 'C'-файлов. Результатом '$(filter %.elc,$(files))' является 'foo.elc', поэтому этот файл порождается из 'foo.el'.

Еще один пример показывает, как использовать '$*' в статических шаблонных правилах:

      bigoutput littleoutput : %output : text.g   
              generate text.g -$* > $@         

Статические шаблонные правила в сравнении с неявными правилами

Статические шаблонные правила имеют много общего с неявными правилами, определенными как шаблонные правила (смотрите раздел 10.5 [Определение и переопределение шаблонных правил]). В обоих случаях имеется шаблон для цели и шаблоны для построения имен зависимостей. Различие заключается в том, как make определяет, когда применяются правила.

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

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

Статическое шаблонное правило может быть предпочтительнее неявного правила по следующим причинам:

4.11 Правила с двумя двоеточиями

Правила с двойным двоеточием представляют собой правила, записываемые при помощи '::', а не ':' после имени цели. Их обработка отличается от обработки обработки обычных правил в том случае, когда одна и та же цель появляется более, чем в одном правиле.

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

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

Правила с двойным двоеточием для цели выполняются в том порядке, в котором они появляются в make-файле. Однако, в тех случаях, когда действительно есть смысл в правилах с двойным двоеточием, порядок выполнения команд не играет роли.

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

Каждое правило с двойным двоеточием должно определять команды - если они не определены, будет использовано неявное правило, в случае его применимости. Смотрите главу 10 [Использование неявных правил].

4.12 Автоматическая генерация зависимостей

В make-файле для программы, многие из правил, которые вам приходится писать, указывают только на то, что некоторый объектный файл зависит от некоторого заголовочного файлов. Например, если 'main.c' использует 'defs.h' посредством директивы #include, вы бы написали:

      main.o: defs.h   
Вам это правило нужно для того, чтобы make знал, что он должен обновлять 'main.o' всегда, когда изменяется 'defs.h'. Можно заметить, что для большой программы вы бы написали в вашем make-файле десятки таких правил. Кроме того, вы всегда должны быть очень внимательны в отношении обновления make-файла каждый раз, когда вы добавляете или удаляете директиву #include.

Чтобы избавиться от этого неудобства, большинство современных C-компиляторов могут написать для вас эти правила, просмотрев в исходном файле строки с директивой #include. Обычно это делается при помощи опции компилятора '-M'. Например, команда:

      cc -M main.c   
генерирует на выходе:

      main.o : main.c defs.h   
Таким образом, вам больше не требуется самим писать все такие правила. Компилятор сделает это за вас.

Обратите внимание, что такая зависимость порождает упоминание 'main.o' в make-файле, таким образом он впоследствии не может рассматриваться как промежуточный файл при поиске неявного правила. Это означает, что make никогда не будет удалять файл после его использования - смотрите раздел 10.4 [Цепочки неявных правил].

В старых программах make традиционной практикой было использование возможности компилятора генерировать зависимости с помощью команды вида 'make depend'. Эта команда создавала файл 'depend', содержащий все автоматически генерируемые зависимости - в таком случае make-файл мог использовать директиву include для их чтения (смотрите раздел 3.3 [Включение]).

В GNU-версии программы make из-за возможности обновления make-файлов такая практика становится устаревшей - вам никогда не требуется явно указывать программе make перегенерировать зависимости, поскольку она всегда перегенерирует любой make-файл, который является необновленым. Смотрите раздел 3.5 [Как переделываются make-файлы].

Рекомендуемая нами практика автоматической генерации зависимостей заключается в том, чтобы иметь для каждого исходного файла соответствующий make-файл. Для каждого исходного файла '<имя файла>.c' заводится make-файл '<имя файла>.d', в котором перечисляются файлы, от которых зависит объектный файл '<имя файла>.o'. В таком случае для порождения новых зависимостей требуется заново просмотреть только измененный файл.

Вот шаблонное правило для порождения файла зависимостей (т.е. make-файла) с именем '<имя файла>.d' из исходного C-файла с именем '<имя файла>.c':

      %.d: %.c   
              $(SHELL) -ec '$(CC) -M $(CPPFLAGS) $< \   
                            | sed '\''s/$*\\.o[ :]*/& $@/g'\'' > $@'   
Смотрите раздел 10.5 [Шаблонные правила] для информации об определении шаблонных правил. Благодаря флагу командной оболочки '-e', непосредственно после неудачного выполнения команды $(CC) (завершения с ненулевым результатом) происходит завершение работы оболочки. В противном случае командная оболочка завершалась бы с результатом последней команды в конвейере (в данном случае sed), поэтому программа make не замечала бы ненулевой результат компилятора.

При использовании компилятора GNU C вы можете захотеть вместо флага '-M' использовать флаг '-MM'. Его использование приводит к пропуску зависимостей от системных заголовочных файлов. Подробности смотрите в разделе "Опции управления препроцессором" руководства по использованию GNU CC.

Предназначением программы sed является преобразование (например):

      main.o : main.c defs.h   
в:

      main.o main.d : main.c defs.h   

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

После того, как вы определили правило для обновления '.d'-файлов, вы используете директиву include для чтения их всех. Смотрите раздел 3.3 [Включение]. Например:

      sources = foo.c bar.c   
    
      include $(sources:.c=.d)   
(В этом примере для преобразования списка исходных файлов 'foo.c bar.c' в список make-файлов с зависимостями 'foo.d bar.d' используется ссылка на переменную с заменой. Смотрите раздел 6.3.1 [Cсылки с заменой] для полной информации о подстановочных ссылках). Так как '.d'-являются такими же make-файлами, как и любые другие, make при необходимости обновит их без какой-либо дополнительной работы с вашей стороны. Смотрите раздел 3.5 [Как переделываются make-файлы].


Вперед Назад Содержание
Вперед Назад Содержание

5. Написание команд в правилах

Команды правила состоят из командых строк командной оболочки, предназначенных для выполнения их одной за другой. Каждая командная строка должна начинаться с символа табуляции, за исключением того, что первая командная строка может быть присоединена к строке целей и зависимостей через точку с запятой. Среди командных строк могут появляться пробельные строки и строки, состоящие только из комментария - они игнорируются. (Но будьте осторожны - кажущаяся пробельной, сторока, начинающаяся с символа табуляции, не является пробельной! Это пустая команда - смотрите раздел 5.8 [Пустые команды]).

Пользователи используют в качестве программных оболочек различные программы, но команды из make-файла всегда интерпретируются программой '/bin/sh', если в make-файле не определена другая. Смотрите раздел 5.2 [Выполнение команд].

Используемая командная оболочка определяет, могут ли быть написаны комментарии в командных строках, и какой синтаксис они используют. Когда командной оболочкой является '/bin/sh', символ '#' начинает комментарий, который продолжается до конца строки. Символ '#' не обязательно должен быть в начале строки. Текст строки перед символом '#' не является частью комментария.

5.1 Отображение команды

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

Когда строка начинается с '@', отображение этой строки подавляется. Символ '@' отбрасывается, прежде чем команда передается командной оболочке. Обычно вам следует использовать это для тех команд, единственным действием которых является вывод чего-либо на экран, например для команды echo, применяемой в целях индикации прохождения по make-файлу:

         @echo   About to make distribution files   
Когда программе make передается опция '-n' или '--just-print', происходит только отображение, без выполнения. Смотрите раздел 9.7 [Обзор опций]. В этом и только в этом случае печатаются даже команды, начинающиеся с символа '@ '. Эта опция полезна для выяснения того, какие команды make рассматривает как необходимые, без реального их выполнения.

Опции программы make '-s' или '--silent' предотвращают все отображения, как будто все команды начинаются с '@ '. Появление в make-файле правила без зависимостей для специальной цели .SILENT дает такой же эффект (смотрите раздел 4.7 [Специальные встроенные имена целей]). .SILENT представляет собой явно устаревшую возможность, так как использование символа '@ ' является более гибким.

5.2 Выполнение команд

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

ЗАМЕЧАНИЕ: это означает, что команды командной оболочки, такие, как cd, которая устанавливает для каждого процесса местоположение его данных, не будут воздействовать на следующие командные строки. Если вы хотите, чтобы команда cd воздействовала на следующую команду, разместите обе на одной строке с точкой с запятой между ними. В этом случае make будет рассматривать их как одну команду и передаст их вместе командной оболочке, которая последовательно выполнит их. Например:

      foo : bar/lose   
              cd bar; gobble lose > ../foo   
Если вам хотелось бы разбить одну команду командной оболочки на несколько тексовых строк, вы должны использовать символ '\' в конце всех ее подстрок, кроме последней. Такая последовательность текстовых строк объединяется в одну посредством удаления последовательностей 'обратная косая черта - перевод строки' перед передачей ее командной оболочке. Таким образом, написанное ниже эквивалентно предыдущему примеру:

      foo : bar/lose   
              cd bar;  \   
              gobble lose > ../foo   
Программа, используемая в качестве командной оболочки, определяется при помощи переменной SHELL. По умолчанию, используется программа '/bin/sh'.

В отличие от большинства переменных, переменная SHELL никогда не устанавливается из командной среды. Так дело обстоит из-за того, что переменная окружения SHELL используется для определения вашей личной настройки программы командной оболочки для диалогового использования. Было бы очень плохо, если бы такого рода личная настройка влияла на функционирование make-файлов. Смотрите раздел 6.9 [Переменные из командной среды].

5.3 Параллельное выполнение

GNU-версия программы make умеет одновременно выполнять несколько команд. Обычно make будет выполнять одновременно только одну команду, ожидая ее завершения, прежде, чем запускать следующую. Однако, опция '-j' или '--jobs' дает программе make указание выполнять параллельно несколько команд.

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

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

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

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

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

Если выполнение команды не удается (она уничтожается с помощью сигнала или завершается с ненулевым результатом), и ошибки для этой команды не игнорируются (смотрите раздел 5.4 [Ошибки в командах]), оставшиеся командные строки для обновления той же самой цели не будут выполняться. Если выполнение команды не удается, и при этом не установлена опция '-k' или '--keep-going' (смотрите раздел 9.7 [Обзор опций]), make прерывает выполнение. Если make разрушается по любым причинам (включая сигнал) в тот момент, когда выполняются порожденные процессы, он ожидает их окончания, прежде чем на самом деле выйти.

Когда система сильно загружена, вы, вероятно захотите выполнять меньше заданий, чем тогда, когда она загружена слабо. Вы можете использовать опцию '-l', чтобы задать программе make ограничение на количество одновременно выполняемых заданий на основе средней загрузки. За опцией '-l' или '--max-load' следует число с плавающей точкой. Например, опция

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

Более точно, когда make собирается запустить задание, и у него уже выполняется одно задание, он проверяет текущую среднюю загрузку - если она не меньше чем предел, определенный с помощью '-l', make ожидает до тех пор, пока средняя загрузка не опустится ниже предела, или пока не завершится другое задание.

По умолчанию предел загрузки не установлен.

5.4 Ошибки в командах

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

Если встретилась ошибка (возвращаемый результат - ненулевой), make прекращает выполнение текущего правила и, возможно, всех правил.

Иногда неудачное выполнение определенной команды не является признаком проблемы. Например, вы можете использовать команду mkdir, чтобы убедиться, что каталог существует. Если каталог существует, mkdir сообщит об ошибке, но, тем не менее, вы, вероятно, захотите, чтобы make продолжил работу.

Чтобы игнорировать ошибки в командной строке, напишите символ '-' в начале ее текста (после начального символа табуляции). Этот символ отбрасывается, прежде чем команда передается для исполнения командной оболочке.

Например:

      clean:   
    
              -rm -f *.o   
Это приводит к тому, что после rm выполнение команд будет продолжаться, даже если попытка удаления файлов окажется неудачной.

Когда вы запускаете make с опцией '-i' или '--ignore-errors', ошибки игнорируются во всех командах всех правил. Правило make-файла со специальной целью .IGNORE имеет такой же эффект, если у него нет зависимостей. Эти способы игнорирования ошибок являются устаревшими, поскольку использование символа '-' - более гибко.

Когда ошибка игнорируется из-за символа '-' или из-за флага '-i', make обрабатывает ошибочное завершение так же, как и успешное, за исключением того, что он печатает сообщение, которое указывает вам код результата, с которым завершилась команда, и говорит о том, что ошибка была игнорирована.

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

Обычно в такой ситуации make прекращает работу, возвращая ненулевой результат. Однако, если указана опция '-k' или '--keep-going', make, прежде, чем прекратить работу и возвратить ненулевой результат, продолжит обработку других зависимостей оставшихся целей, при необходимости обновляя их. Например, после ошибки при компиляции одного из объектных файлов, 'make -k' продолжит компиляцию других объектных файлов, хотя он знает, что их компоновка будет невозможна. Смотрите раздел 9.7 [Обзор опций].

Обычное поведение предполагает, что вашей задачей является получение обновленных целей; как только make выясняет, что это невозможно, он может непосредственно в этот же момент сообщить о неудаче. Опция '-k' указывает, что на самом деле задачей является тестирование максимально возможного количества изменений в программе, а также, возможно, выявление нескольких независимых проблем, с тем, чтобы вы могли могли скоректировать их всех перед следующей попыткой компиляции. Вот почему команда редактора Emacs 'compile' по умолчанию передает опцию '-k'.

Обычно в случае неудачного выполнения команды, если она вообще изменяла целевой файл, файл становится поврежденным и не может быть использован - или, по крайней мере, он не полностью обновлен. Кроме того, время последнего изменения файла говорит о том, что он в данный момент является обновленным, поэтому при следующем своем запуске make не попытается обновить этот файл. Ситуация точно такая же, как и при уничтожении команды с помощью сигнала - смотрите раздел 5.5 [Прерывания]. Таким образом, в общем случае то, что нужно сделать - это удалить целевой файл, если команда неудачно завершилась после начала изменения файла. make будет делать это, если в качестве цели указано .DELETE_ON_ERROR. Это почти всегда является тем, что вы хотите, чтобы делал make, но это не является исторически сложившейся практикой; поэтому для совместимости вы должны явно потребовать этого.

5.5 Прерывание или уничтожение программы make

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

Целевой файл удаляется для увеpенности в том, что он будет коppектно пеpегенеpиpован пpи следующем запуске пpогpаммы make. Почему именно так ? Пpедположим, вы нажимаете Ctrl-c пpи выполнении компиляции в тот момент, когда началась запись в объектный файл 'foo.c'. Hажатие Ctrl-c уничтожает компилятоp, и в pезультате получается неполный файл, вpемя последней модификации котоpого более позднее, чем вpемя последней модификации файла 'foo.c'. Hо make также получает сигнал Ctrl-c и удаляет этот неполный файл. Если бы make не сделал этого, то пpи следующем его вызове считалось бы, что 'foo.o' не тpебует обновления, что пpивело бы к стpанному сообщению об ошибке от компоновщика, котоpый попытался бы скомпоновать объектный файл, половина содеpжимого котоpого отсутствует.

Вы можете пpедотвpатить удаление целевого файла в такой ситуации, указав его в качестве зависимости специальной цели .PRECIOUS. Пеpед обновлением цели make пpовеpяет, находится ли она в числе зависимостей .PRECIOUS и на основании этого pешает, должна ли удаляться цель пpи возникновении сигнала. Hекотоpые пpичины, по котоpым вы могли бы сделать это : цель обновляется каким-либо элементаpным способом, цель существует только для фиксации вpемени модификации или цель должна существовать все вpемя, чтобы пpедотвpатить непpиятности дpугого pода.

5.6 Рекурсивное использование программы make

Рекуpсивное использование пpогpаммы make означает ее использование в качестве команды в make-файле. Это метод полезен тогда, когда вы хотите иметь отдельные make-файлы для pазличных подсистем, составляющих сложную систему. Hапpимеp, пpедположим, что у вас есть подкаталог 'subdir', котоpый имеет свой собственный make-файл, и вы хотели бы, чтобы make-файл объемлющего каталога запускал пpогpамму make для подкаталога. Вы можете сделать это, написав следующее:

      subsystem:   
              cd subdir; $(MAKE)   
или, что эквивалентно, следующее (смотpите pаздел 9.7 [Обзоp опций]):

      subsystem:   
              $(MAKE) -C subdir   

Вы можете писать pекуpсивные команды make пpосто путем копиpования этого пpимеpа, но есть много моментов, котоpые необходимо знать относительно того, как и почему они pаботают, а также относительно того, как взаимодействуют между собой поpожденный пpоцесс make (make нижнего уpовня) и make веpнего уpовня.

Как pаботает пеpеменная make

Рекуpсивные команды make всегда должны использовать пеpеменную MAKE, а не непосpедственное имя команды 'make', как показано ниже:

      subsystem:   
              cd subdir; $(MAKE)   

Значением этой пеpеменной является имя файла, с помощью котоpого была вызвана пpогpамма make. Если этим именем файла было '/bin/make', то выпоняемая команда - 'cd subdir; /bin/make'. Если вы используете специальную веpсию пpогpаммы make для обpаботки make-файла веpнего уpовня, то та же специальная веpсия будет исполняться пpи pекуpсивных вызовах.

Как специальная возможность, использование пеpеменной MAKE в командах пpавила изменяет действие опций '-t' ('--touch'), '-n'('--just-print') и '-q' ('--question'). Использование пеpеменной MAKE имеет такой же эффект, как и использование символа '+' в начале командной стpоки (смотpите pаздел 9.3 [Вместо исполнения команд]).

Рассмотpим команду 'make -t' в пpиведенном выше пpимеpе. (Опция '-t' помечает цели как обновленные без pеального выполнения каких-либо команд - смотpите pаздел 9.3 [Вместо исполнения команд]). Согласно обычному опpеделению '-t', в данном пpимеpе команда 'make -t' создала бы файл с именем 'subsystem' больше ничего не сделала бы. Hа самом деле, вам бы хотелось, чтобы запустилось 'cd subdir; make -t', но это потpебовало бы выполнения команды, а опция '-t' указывает на то, что следует не выполнять команды.

Специальная обpаботка некотоpых опций напpавлена на то, чтобы они выполняли то, чего вы от них хотите: всегда в тех случаях, когда командная стpока пpавила содеpжит пеpеменную MAKE, опции '-t', '-n' и '-q' не пpименяются к данной стpоке. Командные стpоки, содеpжащие MAKE, исполняются обычным обpазом, несмотpя на наличие опции, пpиводящей к тому, что большинство команд не исполняются. Обычный механизм с использованием пеpеменной MAKEFLAGS пеpедает опции порожденному процессу make (смотpите pаздел 5.6.3 [Опции для связи с порожденным процессом make]), поэтому ваш запpос на обновление файлов без исполнения соответствующих команд или на печать команд pаспpостpаняется на подсистему.

Связь порожденным процессом make через переменные

Значения пеpеменных пpоцесса make веpхнего уpовня могут быть по явному тpебованию пеpеданы поpожденному пpоцессу make чеpез командную сpеду. Эти пеpеменные по умолчанию опpеделены в поpожденном пpоцессе make, но они не пеpекpывают то, что опpеделено в make-файле, используемом поpожденным пpоцессом make, если вы не используете опцию '-e' (смотpите pаздел 9.7 [Обзор опций]).

Чтобы пеpедать, или, дpугими словами, экспоpтиpовать, пеpеменную, make добавляет пеpеменную и ее значение в командную сpеду для выполнения каждой команды. Поpожденный пpоцесс make, в свою очеpедь, использует командную сpеду для инициализации своей таблицы значений пеpеменных. Смотpите pаздел 6.9 [Переменные из командной среды].

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

Специальные пеpеменные 'SHELL' и 'MAKEFLAGS' экспоpтиpуются всегда (если вы не отменяете их экспоpтиpование). 'MAKEFILES' экспоpтиpуется, если вы устанавливаете во что-нибудь ее значение.

make автоматически пеpедает значения пеpеменных, котоpые были опpеделены в командной стpоке путем добавления их к пеpеменной MAKEFLAGS. Смотpите следующий pаздел.

Обычно пеpеменные не пеpедаются, если они были по умолчанию созданы пpоцессом make (смотpите pаздел 10.3 [Пеpеменные, используемые неявными пpавилами]). Поpожденный пpоцесс make сам опpеделит их.

Если вы хотите экспоpтиpовать опpеделенные пеpеменные поpожденному пpоцессу make, используйте диpективу make, как показано ниже:

      export ПЕРЕМЕHHАЯ ...   
Если вы хотите отменить экспоpтиpование пеpеменной, используйте диpективу unexport, как показано ниже:

      unexport ПЕРЕМЕHHАЯ ...   
Для удобства вы можете опpеделить пеpеменную и одновpеменно экпоpтиpовать ее следующим способом:

      export ПЕРЕМЕHHАЯ = ЗHАЧЕHИЕ   
что имеет такой же эффект, как и следующая запись:

      ПЕРЕМЕHHАЯ = ЗHАЧЕHИЕ   
      export ПЕРЕМЕHHАЯ   
а

      export ПЕРЕМЕHHАЯ := ЗHАЧЕHИЕ   
имеет такой же эффект, как и следующая запись:

      ПЕРЕМЕHHАЯ := ЗHАЧЕHИЕ   
      export ПЕРЕМЕHHАЯ   

Аналогично,

      export ПЕРЕМЕHHАЯ += ЗHАЧЕHИЕ   
является дpугой фоpмой такой записи:

      ПЕРЕМЕHHАЯ += ЗHАЧЕHИЕ   
      export ПЕРЕМЕHHАЯ   
Смотpите pаздел 6.6 [Добавление дополнительного фрагмента к пеpеменным].

Вы можете заметить, что диpективы export и unexport pаботают в пpогpамме make таким же обpазом, как они pаботают в командной оболочке, sh.

Если вы хотите, чтобы по умолчанию экспоpтиpовались все пеpеменные, вы можете использовать диpективу export без указания пеpеменных:

      export   
Она указывает пpогpамме make на то, что пеpеменные, котоpые не упоминаются явным обpазом в диpективах export или unexport, должны быть экспоpтиpованы. Любая пеpеменная, указанная в диpективе unexport, не будет экспоpтиpована. Если вы используете диpективу export без указания пеpеменных для того, чтобы по умолчанию пеpеменные экспоpтиpовались, пеpеменные, чьи имена содеpжат символы, отличные от алфавитно-цифpовых символов и символов подчеpкивания, не будут экспоpтиpованы, если они не упоминаются в диpективе export.

Поведение, опpеделяемое диpективой export без указания пеpеменных было поведением по умолчанию в более стаpых GNU-веpсиях пpогpаммы make. Если ваш make-файл постpоен в pасчете на такое поведения и вы хотите, чтобы он был совместим с более стаpыми веpсиями пpогpаммы make, вы можете написать пpавило со специальной целью .EXPORT_ALL_VARIABLES вместо использования диpективы export. Это будет игноpиpовано стаpыми веpсиями пpогpаммы make, в то вpемя как диpектива export вызовет синтаксическую ошибку.

Аналогично, вы можете использовать unexport без указания пеpеменных для того, чтобы указать пpогpамме make то, что по умолчанию пеpеменные не должны экспоpтиpоваться. Поскольку такое поведение пpедусмотpено по умолчанию, вам потpебуется делать это только в том случае, если pанее (возможно, во включаемом make-файле) была использована диpектива export без указания пеpеменных. Вы не можете использовать диpективы export и unexport без указания пеpеменых для того, чтобы для одних команд пеpеменные экспоpтиpовались, а для дpугих - нет. Последняя диpектива без указания пеpеменых export или unexport опpеделяет поведение всего сеанса выполнения make.

В качестве дополнительной возможности, пеpеменная MAKELEVEL изменяется пpи пеpедаче ее с одного уpовня на дpугой. Значением этой пеpеменной является стpока, пpедставляющая глубину вложенности в виде десятичного числа. Для пpоцесса make веpхнего уpовня ее значение - '0', для поpожденного пpоцесса make - '1', для пpоцесса make, поpожденного из поpожденного пpоцесса make - '2', и так далее. Увеличение значения пpоисходит тогда, когда make устанавливает сpеду для команды.

Основное пpедназначение пеpеменной MAKELEVEL - пpовеpка ее значения в условной диpективе (смотpите главу 7 [Условные части make-файла]); таким способом вы можете написать make-файл, котоpый ведется себя по-pазному, в зависимости от того, запущен ли он pекуpсивно или же - напpямую вами.

Вы можете использовать пеpеменную MAKEFILES для того, чтобы заставить все команды запуска поpожденных пpоцессов make использовать дополнительные make-файлы. Значением пеpеменной MAKEFILES является pазделенный пpобелами список имен файлов. Эта пеpеменная, будучи опpеделенной на самом внешнем уpовне, пеpедается чеpез командную сpеду; затем она служит в качестве списка дополнительных make-файлов, читаемых поpожденным пpоцессом make пеpед чтением обычных или опpеделенных пpи помощи паpаметpов make-файлов. Смотpите pаздел 3.4 [Переменная MAKEFILES].

Опции для связи с порожденным процессом make

Такие флаги, как '-s' и '-k' автоматически передаются порожденному процессу make через переменную MAKEFLAGS. Эта переменная, автоматически устанавливаемая программой make, содержит буквы тех опций, которые получает данный экземпляр make. Таким образом, если вы запускаете 'make -ks', то MAKEFLAGS получает значение 'ks'.

Следовательно, каждый порожденный процесс make получает в своей командной среде значение MAKEFLAGS. В ответ на это он берет опции из этого значения и обрабатывает их так, как будто они были переданы в качестве аргументов. Смотрите раздел 9.7 [Обзор опций].

Таким же образом переменные, определенные в командной строке, передаются порожденному процессу make через MAKEFLAGS. Те слова из значения MAKEFLAGS, которые содержат символ '=', make обрабатывает как определения переменных, как будто они появились в командной строке. Смотрите раздел 9.5 [Перекрывающиеся переменные].

Опции '-C', '-f', '-o' и '-W' не указываются в MAKEFLAGS - эти опции не передаются порожденному процессу make.

Опция '-j' представляет собой особый случай (смотрите раздел 5.3 [Параллельное выполнение]). Если вы устанавливаете ее в численное значение, то в MAKEFLAGS всегда подставляется '-j 1' вместо определенного вами значения. Это из-за того, что при передаче опции '-j' порожденным процессам make вы бы получили гораздо больше параллельно исполняющихся заданий, чем запрашивали. Если вы указываете '-j' без числового аргумента, что означает параллельное исполнение максимально возможного количества заданий, то такая опция передается без изменений, так как несколько бесконечностей в сумме дают одну бесконечность.

Если вы нехотите передавать порожденному процессу make другие опции, вам следует изменить значение MAKEFLAGS, как показано ниже:

         MAKEFLAGS=   
         subsystem:   
                    cd subdir; $(MAKE)   
или так:

         subsystem:   
                    cd subdir; $(MAKE) MAKEFLAGS=   

На самом деле определения переменных командной строки появляются в переменной MAKEOVERRIDES, а MAKEFLAGS содержит ссылку на эту переменную. Если вы хотите обычным образом передать порожденным процессам make опции, но не хотите передавать им определения переменных командной строки, вы можете переустановить в пустое значение MAKEOVERRIDES, как показано ниже:

         MAKEOVERRIDES=   
Это не является типичным полезным действием. Однако, некоторые системы имеют сильное фиксированное ограничение на размер командной среды, и помещение такого большого количества информации в значение переменой MAKEFLAGS может превысить его. Если вы видите сообщение об ошибке 'Arg list too long', именно это может быть причиной. (Для строгой совместимости с POSIX.2, изменение MAKEOVERRIDES не влияет на MAKEFLAGS, если в make-файле появляется специальная цель '.POSIX'. Вы, вероятно, на это не обращаете внимание.)

В целях исторической совместимости существует также похожая переменная MFLAGS. Она имеет такое же значение, как и MAKEFLAGS, за исключением того, что она не содержит определения переменных командной строки, и она всегда, когда непустая, начинается с символа '-' (MAKEFLAGS начинается с символа '-' только тогда, когда она начинается с опции, не имеющей однобуквенной версии, например '--warn-undefined-variables'). MFLAGS традиционно использовалась явным образом в рекурсивной команде make, как показано ниже:

         subsystem:   
                    cd subdir; $(MAKE) $(MFLAGS)   
но сейчас MAKEFLAGS делает такое использование излишним. Если вы хотите, чтобы ваши make-файлы были совместимыми со старыми make-программами, используйте этот метод - он будет также прекрасно работать с более новыми версиями программмы make.

Переменная MAKEFLAGS также может быть полезной, если вы хотите иметь определенные опции, такие как '-k' (смотрите раздел 9.7 [Обзор опций]), установленными каждый раз, когда вы запускаете make. Вы просто определяете значение переменной MAKEFLAGS в вашей командной среде. Вы также можете установить в MAKEFLAGS в make-файле для того, чтобы определить дополнительные опции, которые также должны иметь силу для соответствующего make-файла. (Обратите внимание, что вы не можете таким способом использовать MFLAGS. Эта переменная установлена только для совместимости - make не интерпретирует значение, в которое вы ее каким-либо способом устанавливаете.)

Когда программа make интерпретирует значение переменной MAKEFLAGS (либо из командной среды, либо из make-файла), она в первую очередь подставляет в его начало символ '-', если значение переменной не начинается уже с него. Затем make разрубает значение на слова, разделенные пробелами, и обрабатывает эти слова так, как будто они являются опциями, передаваемыми через командную строку (за исключением того, что опции '-C', '-f', '-h', '-o', '-W' и их версии с длинными именами игнорируются, а также не фиксируется ошибок для некорректных опций).

Если вы устанавливаете MAKEFLAGS в вашей командной среде, вам следует убедиться в том, что вы не включили какие-либо опции, которые серьезно повлияют на действия программы make и изменят предназначение make-файлов и самой программы make. Например, если бы в этой переменной была указана одна из опций '-t', '-n', или '-q', это могло бы вызвать разрушительные последствия, и, конечно, имело бы, по меньшей мере, удивительные, и, возможно, надоедающие эффекты.

Опция '--print-directory'

Если вы используете несколько уровней рекурсивных вызовов программы make, опция '-w' или '--print-directory' может сделать выход программы намного более легким для понимания посредством показа каждого каталога в момент начала и окончания его обработки. Например, если 'make -w' выполняется в каталоге '/u/gnu/make', то make напечатает строку следующей формы:

         make: Entering directory '/u/gnu/make'   
прежде, чем что-либо сделать, и строку следующей формы:

         make: Leaving directory '/u/gnu/make'   
когда обработка завершена.

Обычно вам не требуется определять эту опцию, поскольку тогда, когда вы пишете 'make', это делается за вас: '-w' автоматически включается, когда вы используете опцию '-C' и в порожденных процессах make. Программа make не будет автоматически включать опцию '-w', если вы при этом используете '-s', которая подавляет вывод, или '--no-print-directory', для явного ее выключения.

5.7 Определение именованных командных последовательностей

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

Вот пример определения именованной последовательности команд:

         define run-yacc   
         yacc $(firstword $^)   
         mv y.tab.c$ $@         
         endef   
Здесь run-yacc является именем определяемой переменной, endef обозначает конец определения, строки между именем и концом определения представляют собой команды. Директива define не заменяет ссылки на переменные и вызовы функции в именованной последовательности - символы '$', скобки, имена переменных и т.п., все они становятся частью переменной, которую вы определяете. Смотрите раздел 6.8 [Определение многостроковых переменных] для полной информации о директиве define.

Первая команда в этом примере запускает Yacc для первой зависимости любого правила, использующего эту именованную последовательность. Выходной файл программы Yacc всегда называется 'y.tab.c'. Вторая команда переименовывает выходной файл в имя целевого файла правила.

Чтобы использовать именованную последовательность, подставьте переменную в команды правила. Вы можете подставить ее так же, как и любую другую переменную (смотрите раздел 6.1 [Основы обращения к переменным]). Поскольку переменные, определенные с помощью директивы define, являются рекурсивно подставляемыми переменными, все обращения к переменным, которые вы написали внутри конструкции define, в этот момент заменяются на их значения. Например, в правиле

         foo.c : foo.y   
               $(run-yacc)   
'foo.y' будет подставлено вместо переменной '$^' в том месте, где она встречается в значении переменной run-yacc, а 'foo.c' - вместо '$@ '.

Это реалистичный пример, однако именно он не требуется на практике, поскольку make имеет неявное правило, действующее для файлов с указанными именами, для выполнения этих команд (смотрите главу 10 [Использование неявных правил]).

При выполении команд каждая строка именованной последовательности обрабатывается точно так же, если бы она сама появилась в правиле, с предшествующим символом табуляции. В частности, make вызывает командные подоболочки для каждой строки. Вы можете использовать специальные префиксные символы, которые воздействуют на командные строки ('@ ', '-' и '+') в каждой строке именованной последовательности. Смотрите главу 5 [Написание команд в правилах]. Например, при использовании такой именованной последовательности:

         define frobnicate   
         <htmlurl name="@echo" url="mailto:@echo"> "frobnicating target $@   
         frob-step-1 $< -o $@      -step-1   
         frob-step-2 $@      -step-1 -o $@   
         endef   
программа make не будет отображать первую строку, команду echo. Но следующие две командные строки будут отображены.

С другой стороны, префиксные символы в командной строке, относящиеся к именованной последовательности, применяются к каждой строке последовательности. Таким образом, правило:

         frob.out: frob.in   
         @      $(frobnicate)   
не отображает ни одну команду. (Смотрите раздел 5.1 [Отображение команды] для полного объяснения символа '@ '.)

5.8 Использование пустых команд

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

         target: ;   
определяет пустую командную строку для target. Вы могли бы также использовать текстовую строку, начинающуюся с символа табуляции, для определения пустой командной строки, но это приводило бы к путанице, поскольку такая текстовая строка выглядела бы пустой.

Вы можете удивиться, почему бы вы могли захотеть определить командную строку, которая ничего не делает. Единственная причина заключается в том, что это полезно для защиты цели от использования неявных команд (из неявных правил или специальной цели .DEFAULT - смотрите главу 10 [Неявные правила] и раздел 10.6 [Определение правил последней возможности, используемых по умолчанию]).

Вы могли склониться к определению пустых командных строк для для целей, которые не являются настоящими файлами, а существуют только для того, чтобы их зависимости могли быть перегенерированы. Однако, это не лучший способ действия в такой ситуации, поскольку зависимости могут не быть должным образом перегенерированы, если целевой файл на самом деле существует. Смотрите раздел 4.4 [Цели-имена действий], где описывается более подходящий для этого способ.


Вперед Назад Содержание
Вперед Назад Содержание

6. Как использовать переменные

Переменная представляет собой имя, определенное в make-файле для представления текстовой строки, называемой значением переменной. Такое значение подставляется, при явном указании на это, в цели, зависимости, команды и другие части make-файла. (В некоторых других версиях программы make переменные называются макросами.)

Переменные и функции во всех частях make-файла вычисляются при их чтении, за исключением команд командной оболочки в правилах, правой части определения переменной с использованием символа '=' и тел определений переменных с использованием директивы define.

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

Именем переменной может быть любая последовательность символов, не содержащая символов ':', '#', '=' , а также начальных или конечных пробелов. Однако, следует избегать имен переменных, содержащих символы, отличные от букв, цифр и символов подчеркивания, поскольку таким символам в будущем может быть назначено специальное значение, а в некоторых командных оболочках их нельзя будет передать через командную среду порожденному процессу make (смотрите раздел 5.6.2 [Связь порожденным процессом make через переменные]).

Имена переменных чувствительны к регистру. Каждое из имен 'foo', 'FOO' и 'Foo' ссылается на отдельную переменную.

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

Несколько переменных имеют имена, представляющие собой одиночный символ пунктуации или несколько таких символов. Это автоматические переменные, и они имеют отдельно оговоренное использование. Смотрите раздел 10.5.3 [Автоматические переменные].

6.1 Основы обращения к переменным

Для подстановки значения переменной напишите знак доллара с последующим именем переменной в круглых или фигурных скобках: как '$(foo)', так и '${foo}' являются правильными ссылками на переменную foo. Это специальное значение символа '$' является причиной того, что вы должны писать '$$' для обеспечения эффекта появления одного знака доллара в имени файла или команде.

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

      objects = program.o foo.o utils.o   
      program : $(objects)   
              cc -o program $(objects)   
    
      $(objects) : defs.h   
Ссылки на переменные обрабатываются при помощи строгой текстуальной подстановки. Таким образом, правило

      foo = c   
      prog.o : prog.$(foo)   
              $(foo)$(foo) -$(foo) prog.$(foo)   
могло бы быть использовано для компиляции C-программы 'prog.c'. Так как при присвоении переменной значения пробелы, предшествующие ему, игнорируются, значением переменной foo является именно 'c'. (На самом деле вам не рекомендуется писать make-файлы таким образом !)

Если за знаком доллара следует символ, отличный от знака доллара или открывающейся круглой или квадратной скобки, то этот символ обрабатывается как имя переменной. Таким образом, вы могли бы обратиться к переменной x при помощи '$x'. Однако, такая практика крайне нежелательна, за исключением случая автоматических переменных (смотрите раздел 10.5.3 [Автоматические переменные]).

6.2 Две разновидности переменных

Есть два способа, с помощью которых переменная в GNU-версии программы make может получить значение - мы будем называть их двумя разновидностями переменных. Две разновидности различаются тем, как они определяются и что с ними просиходит при их вычислении.

Первая разновидность переменной - это рекурсивно вычисляемая переменная. Переменные такого рода определяются в пределах одной строки make-файла с использованием символа '=' (смотрите раздел 6.5 [Установка переменных]), или при помощи директивы define (смотрите раздел 6.8 [Определение многостроковых переменных]). Определяемое вами значение устанавливается неявным образом - если переменная содержит ссылки на другие переменные, они заменяются на значения всегда, когда происходит подстановка переменной (во время вычисления какой-либо другой строки). Когда такое происходит, это называется рекурсивным вычислением.

Например, фрагмент make-файла

      foo = $(bar)   
      bar = $(ugh)   
      ugh = Huh?   
    
      all:;echo $(foo)   
отобразит на экране 'Huh?': ссылка на переменную '$(foo)' заменяется на ссылку на переменную '$(bar)', которая заменяется на ссылку на переменную '$(ugh)', которая, наконец, заменяется на 'Huh?'.

Только эта разновидность переменных поддерживается другими версиями программы make. Она имеет свои достоинства и недостатки. Преимущество (по мнению большинства) заключается в том, что следующий фрагмент:

      CFLAGS = $(include_dirs) -O   
      include_dirs = -Ifoo -Ibar   
сделает то, что предполагается: когда в команде происходит 'CFLAGS' вычисление, результатом вычисления будет '-Ifoo -Ibar -O'. Основным недостатком является то, что вы не можете ничего добавить в конец переменной, как показано ниже:

      CFLAGS = $(CFLAGS) -O   
поскольку это вызовет бесконечный цикл при вычислении переменной. (На самом деле, программа make обнаруживает бесконечный цикл и сообщает об ошибке.)

Еще один недостаток состоит в том, что любая функция (смотрите главу 8 [Функции преобразования текста]), упомянутая в определении, будет выполняться каждый раз при вычислении переменной. Это замедляет выполнение программы make; хуже того, это приводит к тому, что функции wildcard и shell дают непредсказуемые результаты, так как вы не можете легко проконтролировать, когда, и даже сколько раз, они вызываются.

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

Упрощенно вычисляемые переменные определяются в пределах одной строки make-файла с использованием ':=' (смотрите раздел 6.5 [Установка переменных]). Значение упрощенно вычисляемой переменной просматривается один раз за все время работы с ней, при этом в ее определении происходит замена всех ссылок на другие переменные и функции на их значения. В действительности, значением упрощенно вычисляемой переменной является результат вычисления написанного вами текста. Оно не содержит никаких ссылок на другие переменные - она содержит их значения на тот момент, когда она определялась. Следовательно, данный фрагмент:

      x := foo   
      y := $(x) bar   
      x := later   
эквивалентнен следующему:

      y := foo bar   
      x := later   
При ссылке на упрощенно вычисляемую переменную, происходит просто подстановка ее значения.

Вот несколько более сложный пример, иллюстрирующий использование ':=' вместе с функцией shell. (смотрите раздел 8.6 [Функция shell]). Этот пример также показывает использование переменной MAKELEVEL, которая изменяется при ее передаче с одного уровня на другой. (Смотрите раздел 5.6.2 [Связь порожденным процессом make через переменные] для информации о переменной MAKELEVEL.)

      ifeq (0,${MAKELEVEL})   
      cur-dir   := $(shell pwd)   
      whoami    := $(shell whoami)   
      host-type := $(shell arch)   
      MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}   
      endif   
Преимущество такого использования ':=' состоит в том, что типичная команда 'спуска в каталог' выглядит в данном случае так:

      ${subdirs}:   
            ${MAKE} cur-dir=${cur-dir}/$@       -C $@      all   
Упрощенно вычисляемые переменные, вообще говоря, делают программирование сложных make-файлов более предсказуемым, поскольку они работают, как переменные в большинстве языков программирования. Они позволяют вам переопределять переменную, используя ее собственное значение (или ее значение, обработанное некоторым образом одной из преобразующей функций) и намного более эффективно использовать преобразующие функции (смотрите главу 8 [Функции преобразования текста]).

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

      nullstring :=   
      space := $(nullstring) # конец строки   
Здесь значением переменной space является ровно один пробел. Комментарий '# конец строки' вставлен сюда только для ясности. Так как ведомые пробельные символы не удаляются из значений переменых, просто пробел в конце строки имел бы такой же эффект (но это было бы довольно сложно читать). Если вы добавляете пробел в конце значениея переменной, неплохо бы добавить в конце строки подобный комментарий, чтобы сделать ваш замысел ясным. Напротив, если вы не хотите никаких пробельных символов в конце значения вашей переменной, вы должны запомнить, что не следует добавлять случайный комментарий в конце строки после нескольких пробелов, как показано ниже:

      dir := /foo/bar    # directory to put the frobs in   
Здесь значением переменной dir является '/foo/bar ' (с четырьмя ведомыми пробелами), что, вероятно, не является замыслом. (Представьте что-либо типа '$(dir)/file' с таким определением !)

6.3 Дополнительные возможности для ссылки на переменные

Этот раздел описывает некоторые дополнительные возможности, которые вы можете использовать для обращения с переменными более гибкими способами.

Cсылки с заменой

На место ссылки на замену подставляется значение переменной с определяемыми вами изменения. Она имеет форму '$(var:a=b)' (или '${var:a=b}') и означает, что в значении переменной var, вхождение 'a' в конце каждого слова в этом значении заменяется на 'b', а получившаяся строка будет подставлена на место ссылки.

Когда мы говорим "в конце каждого слова", мы имеем ввиду, что либо за вхождением 'a' должен следовать пробел, либо оно должно находиться в конце значения для того, чтобы быть замененным; другие вхождения 'a' в значение остаются неизмененными. Например, фрагмент make-файла

      foo := a.o b.o c.o   
      bar := $(foo:.o=.c)   
устанавливает переменную 'bar' в 'a.c b.c c.c'. Смотрите раздел 6.5 [Установка переменных].

На самом деле, ссылка с заменой является сокращением использования преобразующей функции patsubst (смотрите раздел 8.2 [Функции подстановки и анализа строк]). Для совместимости с лругими реализациями программы make, данная версия поддерживает ссылку с заменой, также как и patsubst.

Еще один вид ссылки с заменой позволяет вам использовать всю мощь функции patsubst. Он имеет такую же форму '$(var:a=b)', описанную выше, за исключением того, что теперь 'a' должна содержать один, и только один, символ '%'. Этот случай эквивалентен вызову '$(patsubst A,B,$(VAR))'. Смотрите раздел 8.2 [Функции подстановки и анализа строк] для описания функции patsubst.

Например, фрагмент make-файла

      foo := a.o b.o c.o   
      bar := $(foo:%.o=%.c)   
устанавливает переменную 'bar' в 'a.c b.c c.c'.

Вычисляемые имена переменных

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

На переменные можно ссылаться в имени переменной. Это называется вычисляемым именем переменной или вложенной ссылкой на переменную. Например, фрагмент make-файла

      x = y   
      y = z   
      a := $($(x))   
определяет 'z' в качестве значения переменной a: ссылка '$(x)' внутри '$($(x))' заменяется на 'y', поэтому '$($(x))' заменяется на ссылку '$(y)', которая, в свою очередь, заменяется на 'z'. Здесь имя ссылающейся переменной не указано явным образом - оно вычисляется путем замены '$(x)'. В данном случае ссылка '$(x)' вложена в более внешнюю ссылку на переменную.

Предыдущий пример показывает два уровня вложенности, но возможно любое количество уровней. Например, здесь три уровня вложенности:

      x = y   
      y = z   
      z = u   
      a := $($($(x)))   
В этом примере самая внутрення ссылка '$(x)' заменяется expands to 'y', поэтому '$($(x))' заменяется на ссылку '$(y)', которая, в свою очередь, заменяется на 'z'; теперь мы имеет ссылку '$(z)', которая превращается в 'u'.

Ссылки на рекурсивно вычисляемые переменные внутри имени переменной перевычисляются обычным образом. Например, данный фрагмент make-файла:

      x = $(y)   
      y = z   
      z = Hello   
      a := $($(x))   
определяет 'Hello' в качестве значения переменной a: ссылка '$($(x))' превращается в ссылку '$($(y))', которая превращается в ссылку '$(z)', которая превращается в 'Hello'.

Вложенные ссылки на переменные могут также содержать модифицированные ссылки и вызовы функций (смотрите главу 8 [Функции преобразования текста]), так же, как и любые другие ссылки. Например, использование функции subst (смотрите раздел 8.2 [Функции подстановки и анализа строк]), как в данном примере:

      x = variable1   
      variable2 := Hello   
      y = $(subst 1,2,$(x))   
      z = y   
      a := $($($(z)))   
определяет 'Hello' в качестве значения переменной a. Сомнительно, что кто-нибудь когда-либо захочет написать вложенную ссылку, запутанную так же, как и эта, но она работает: ссылка '$($($(z)))' заменяется на ссылку '$($(y))', которая превращается в '$($(subst1,2,$(x)))'. Здесь из переменной x берется значение 'variable1', которое заменяется путем подстановки на 'variable2', таким образом строка целиком принимает вид '$(variable2)', что является простой ссылкой на переменную , значением которой является 'Hello'.

Вычисляемому имени переменной не обязательно состоять целиком из одной ссылки на переменную. Оно может содержать несколько ссылок на переменные, а также какой-нибудь неизменяемый текст. Например, в данном фрагменте make-файла:

      a_dirs := dira dirb   
      1_dirs := dir1 dir2   
    
      a_files := filea fileb   
      1_files := file1 file2   
    
      ifeq "$(use_a)" "yes"   
      a1 := a   
      else   
      a1 := 1   
      endif   
    
      ifeq "$(use_dirs)" "yes"   
      df := dirs   
      else   
      df := files   
      endif   
    
      dirs := $($(a1)_$(df))   
переменной dirs будет дано, такое же значение, как переменной 'a_dirs', '1_dirs', 'a_files' или '1_files', в зависимости от установленных значений переменных 'use_a' и 'use_dirs'.

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

      a_objects := a.o b.o c.o   
      1_objects := 1.o 2.o 3.o   
    
      sources := $($(a1)_objects:.o=.c)   
в качестве значения переменной sources определяется либо 'a.c b.c c.c', либо '1.c 2.c 3.c', в зависимости от значения переменной a1.

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

      ifdef do_sort   
      func := sort   
      else   
      func := strip   
      endif   
    
      bar := a d b g q c   
   
      foo := $($(func) $(bar))   
принимается попытка присвоить переменной 'foo' либо значение 'sort a d b g q c', либо значение 'strip a d b g q c', а не передавать 'a d b g q c' в качестве аргумента либо функции sort, либо функции strip. Это ограничение в будущем может быть снято, если такое изменение покажется хорошей идеей.

Вы также можете использовать вычисляемые имена переменных в левой части присваивания значения переменной или в директиве define, как показано ниже:

      dir = foo   
      $(dir)_sources := $(wildcard $(dir)/*.c)   
      define $(dir)_print   
      lpr $($(dir)_sources)   
      endef   
В этом примере определяются переменные 'dir', 'foo_sources' и 'foo_print'.

Обратите внимание, что вложенные ссылки на переменные полностью отличаются от рекурсивно вычисляемых переменных (смотрите раздел 6.2 [Две разновидности переменных]), хотя и те, и другие сложными способами используются вместе при программировании make-файла.

6.4 Как переменные получают свои значения

Переменные могут получать значения несколькими различными способами:

6.5 Установка переменных

Чтобы установить переменную из make-файла, напишите строку, начинающуюся с имени переменной, за которым следует '=' или ':='. Все, что в данной строке следует за '=' или ':=', становится значением. Например, в данной строке:

      objects = main.o foo.o bar.o utils.o   
определяется переменная с именем objects. Пробелы вокруг имени переменной и непосредственно после символа '=' игнорируются.

Переменные, определенные при помощи символа '=', являются рекурсивно вычисляемыми переменными. Переменные, определенные с помощью ':=', являются упрощенно вычисляемыми переменными - эти определения могут содержать ссылки на переменные, которые будут вычислены, прежде чем будет сделано определение. Смотрите раздел 6.2 [Две разновидности переменных].

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

На длину значения переменной нет ограничений, за исключением количества пространства для подкачки на компьютере. Когда определение переменной длинное, неплохо бы разбить ее на несколько строк, вставляя в определении символ '\' с последующим переводом строки там, где это удобно. Это не повлияет на работу программы make, но сделает make-файл более легким для чтения.

Для большинства имен переменных считается, что соответствующая переменная имеет в качестве значения пустую строку, если вы нигде ее не устанавливали. Несколько переменных имеют встроенные первоначальные значения, которые не являются пустыми, но вы можете установить их обычными способами (смотрите раздел 10.3 [Переменные, используемые неявными правилами]). Некоторые специальные переменные в каждом правиле автоматически устанавливаются в новое значение - они называются автоматическими переменными (смотрите раздел 10.5.3 [Автоматические переменные]).

6.6 Добавление дополнительного фрагмента к пеpеменным

Часто полезно добавлять дополнительный фрагмент к значению уже определенной переменной. Это делается при помощи строки, содержащей '+=', как показано ниже:

      objects += another.o   
В этом примере берется значение переменной objects, и к нему добавляется фрагмент 'another.o' (с предшествующим пробелом). Таким образом, данный фрагмент make-файла

      objects = main.o foo.o bar.o utils.o   
      objects += another.o   
устанавливает 'main.o foo.o bar.o utils.o another.o' в качестве значения переменной objects.

Использование '+=' аналогично следующему:

      objects = main.o foo.o bar.o utils.o   
      objects := $(objects) another.o   
но отличается теми деталями, которые становятся важными при использовании более сложных значений.

Когда расматриваемая переменная ранее не была определена, '+=' действует так же, как обычный символ '=': определяется рекурсивно вычисляемую переменную. Однако, если есть предыдущее определение, тогда то, что именно делает '+=' зависит от того, какая разновидность переменной определена первоначально. Смотрите раздел 6.2 [Две разновидности переменных] для объяснения двух разновидностей переменных.

Когда вы что-либо добавляете к значению переменной при помощи '+=', программа make, по существу, действует так, как будто вы включили дополнительный текст в первоначальное определение переменной. Если вы изначально определили переменную при помощи ':=', сделав ее упрощенно вычисляемой переменной, '+=' производит добавление к этому упрощенно-вычисленному определению, и вычисляет новый фрагмент перед добавлением его к старому значению, так же, как это делается при использовании ':=' (смотрите раздел 6.5 [Установка переменных] для полного объяснения ':='). Фактически, следуюзий фрагмент make-файла:

      variable := value   
      variable += more   
в точности эквивалентен такому фрагменту:

      variable := value   
      variable := $(variable) more   
С другой стороны, когда вы используете '+=' с переменной, которую вы при помощи одиночного символа '=' изначально определили как рекурсивно-вычисляемую, программа make некоторые вещи делает немного иначе. Вспомните, что когда вы определяете рекурсивно-вычисляемую переменную, программа make не вычисляет сразу значение установленных вами ссылок на переменные и функции. Вместо этого, она она запоминает фиксированные фрагменты и хранит эти ссылки на переменные и функции с тем, чтобы вычислить их позже, когда вы обратитесь к новой пременной (смотрите раздел 6.2 [Две разновидности переменных]). Когда вы используете '+=' с рекурсивно-вычисляемой переменной, имеется невычисленный фрагмент, к которому make добавляет определенный вами новый фрагмент.

      variable = value   
      variable += more   
Приведенные выше строки make-файла, грубо говоря, эквивалентны следующим строкам:

      temp = value   
      variable = $(temp) more   
за исключением того, что, конечно, никогда не определяется переменная с именем temp. Важность использования '+=' проявляется в той ситуации, когда старое значение переменной содержит ссылки на переменные. Рассморим такой типичный пример:

      CFLAGS = $(includes) -O   
      ...   
      CFLAGS += -pg # enable profiling   
Первая строка определяет переменную CFLAGS со ссылкой на другую переменную, includes. (CFLAGS используется правилами для C-компиляции, смотрите раздел 10.2 [Перечень неявных правил].) Использование для определения '=' делает CFLAGS рекурсивно-вычисляемой переменной, а это означает, что '$(includes) -O' не вычисляется в тот момент, когда программа make обрабатывает значение определение переменной CFLAGS. Таким образом, чтобы получить эффект от использования переменной includes, не обязательно наличие у нее определенного значения на момент определения CFLAGS. Достаточно того, чтобы переменная includes была определена перед любой ссылкой на CFLAGS. Если бы мы попробовали добавить значение к CFLAGS без использования '+=', мы могли бы сделать это примерно так:

      CFLAGS := $(CFLAGS) -pg # enable profiling   
Это близко к истине, но не совсем то, чего мы хотим. При использовании ':=' CFLAGS переопределяется как упрощенно-вычисляемая переменная - это означает, что программа make вычисляет фрагмент '$(CFLAGS) -pg' перед установкой значения переменной. Если переменная includes еще неопределена, мы получим ' -O -pg', и более позднее определение переменной includes не окажет никакого воздействия. Напротив, при использовании '+=' мы устанавливаем переменную CFLAFGS в невычесленное значение '$(includes) -O -pg'. Таким образом, мы сохраняем ссылку на переменную includes, поэтому если эта переменная оказывается определенной где-нибудь дальше, ссылка вида '$(CFLAGS)' все-таки будет использовать ее значение.

6.7 Директива override

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

      override VARIABLE = VALUE   
или так:

      override VARIABLE := VALUE   
Для добавления дополнительного фрагмента к переменной, определенной в командной строке, используйте такую строку make-файла:

      override VARIABLE += MORE TEXT   
Смотрите раздел 6.6 [Добавление дополнительного фрагмента к пеpеменным].

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

Например, предположим, что вы всегда хотите, чтобы при запуске C-компилятора использовалась опция '-g', но вы хотели бы позволить позволить пользователю определять другие опции, как обычно, в аргументе командной строки.

      override CFLAGS += -g   

Вы можете также использовать директивы override с директивами define. Это делается так же, как вы и могли ожидать:

      override define foo   
      bar   
      endef   
Смотрите следующий раздел для информации о директиве define.

6.8 Определение многостроковых переменных

Еще один способ устанвки значения переменной - использовать директиву define. Эта директива имеет необычный синтаксис, который позволяет включать в значение символы перевода строки, что удобно для определения именованных последовательностей команд (смотрите раздел 5.7 [Определение именованных командных последовательностей]).

За директивой define на той же строке следует имя переменной и ничего больше. Значение, в которое устанавливается переменная, появляется на последующих строках. Конец значения обозначается строкой, содержащей только одно слово endef. За исключением этого отличия в синтаксисе, директива define работает точно так же, как и '=': она создает рекурсивно вычисляемую переменную (смотрите раздел 6.2 [Две разновидности переменных]). Имя переменной может содержать ссылки на функции и переменные, которые вычисляются в момент чтения директивы для определения того, какое реальное имя переменной следует использовать.

      define two-lines   
      echo foo   
      echo $(bar)   
      endef   
При обычном присваивании значение не может содержать символов перевода строки, в то же время символы перевода строки, которые разделяют строки в значении, определяемом директивой define, становятся частью значения переменной (за исключением последнего перевода строки, который предшествует директиве endef и не рассматривается как часть значения).

Предыдущий пример функционально эквивалентен приведенному ниже:

      two-lines = echo foo; echo $(bar)   
так как две команды, разделенные точкой с запятой, ведут себя во многом так же, как две отдельные команды командной оболочки. Однако, обратите внимание, что использование двух отдельных строк означает, что программа make будет вызывать командную оболочку дважды, запуская независимые подоболочки для каждой строки. Смотрите раздел 5.2 [Выполнение команд].

Если вы хотите, чтобы определения переменных, сделанные при помощи define, имели преимущество перед определениями переменных из командной строки, вы можете вместе с директивой define использовать директиву override, как показано ниже:

      override define two-lines   
      foo   
      $(bar)   
      endef   
Смотрите раздел 6.7 [Директива override].

6.9 Переменные из командной среды

Переменные могут приходить в программу make из командной среды, в которой make запускается. Каждая переменная командной среды, которая доступна программе make при старте, преобразуется в переменную программы make с таким же именем и значением. Но явное присваивание в make-файле или при помощи арргумента командной строки перекрывает значение из командной среды. (Если определена опция '-e', значение из командной среды перекрывает присваивания в make-файле. Смотрите раздел 9.7 [Обзор опций]. Но такая практика не рекомендуется.)

Таким образом, установив переменную CFLAGS в вашей командной среде, вы можете сделать так, чтобы во всех сеансах компиляции C-программ в большинстве make-файлов использовались выбранные вами опции компилятора. Это безопасно для переменных со стандартными или обговоренными предназначениями, поскольку вы знаете, что ни один make-файл не будет использовать их ни для чего другого. (Но это не является абсолютно надежным - некоторые make-файлы явным образом устанавливают переменную CFLAGS и, следовательно, на них не действует значение из командной среды).

Когда программа make вызывается рекурсивно, переменные, определенные в более внешних порожденных процессах make, могут быть переданы более внутренним порожденных процессах make через командную среду ( смотрите раздел 5.6 [Рекурсивное использование make]). По умолчанию, при рекурсивных вызовах передаются только переменные, которые пришли из командной среды или определены в командной строке. Для того, чтобы передать другие переменные, вы можете использовать директиву export. Смотрите раздел 5.6.2 [Связь порожденным процессом make через переменные], для выяснения всех деталей.

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

Такие проблемы были бы особенно вероятны в связи с переменной SHELL, которая обычно присутствует в командной среде для определения выбранной пользователем диалоговой командной оболочки. Было бы очень нежелательно, чтобы этот выбор воздействовал на программу make. Поэтому программа make игнорирует значение переменной SHELL из командной среды.


Вперед Назад Содержание
Вперед Назад Содержание

7. Условные части make-файла

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

7.1 Пример условной конструкции

Приведенный ниже пример условной конструкции указывает программе make использовать один набор библиотек, если значением переменной CC является 'gcc', и другой набор библиотек - в противном случае. Его работа основывается на управлении тем, какая из двух командных строк будет использована в правиле в качестве команды. В результате 'CC=gcc' в качестве аргумента программы make изменяет не только используемый компилятор, но также и компонуемые библиотеки.

      libs_for_gcc = -lgnu   
      normal_libs =   
    
      foo: $(objects)   
      ifeq ($(CC),gcc)   
      p        $(CC) -o foo $(objects) $(libs_for_gcc)   
      else   
      p        $(CC) -o foo $(objects) $(normal_libs)   
      endif   
Эта условная конструкция использует три директивы: одну директиву ifeq, одну директиву else и одну директиву endif.

Директива ifeq начинает условную конструкцию и определяет условие. Она содержит два аргумента, разделенных запятой и окруженных круглыми скобками. Для обоих частей производится подстановка значения переменной, после чего они сравниваются. Строки make-файла, следующие за директивой ifeq обрабатываются, если два аргумента идентичны, в противном случае они игнорируются.

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

Директива endif заканчивает условную конструкцию. Каждая условная конструкция должна заканчиваться директивой endif. За ней следует безусловный фрагмент make-файла.

Как показывает этот пример, условная конструкция работает на текстуальном уровне: строки условной конструкции обрабатываются или игнорируются, в соответствии с условиями, как часть make-файла. Именно поэтому более крупные синтаксические элементы make-файла, такие как правила, могут пересекаться с началом или концом условной конструкции.

Когда значением переменной CC является 'gcc', из фрагмента make-файла, приведенного в предыдущем примере, получается такой фрагмент:

      foo: $(objects)   
              $(CC) -o foo $(objects) $(libs_for_gcc)   
Когда значением переменной CC является что-либо, отличное от 'gcc', получается такой фрагмент:

      foo: $(objects)   
              $(CC) -o foo $(objects) $(normal_libs)   

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

      libs_for_gcc = -lgnu   
      normal_libs =   
    
      ifeq ($(CC),gcc)   
        libs=$(libs_for_gcc)   
      else   
        libs=$(normal_libs)   
      endif   
    
      foo: $(objects)   
              $(CC) -o foo $(objects) $(libs)   

7.2 Синтаксис условных конструкций

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

      УСЛОВНАЯ-ДИРЕКТИВА   
      ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ   
      endif   
ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ может представлять собой любые строки текста, которые будут считаться частью make-файла, если условие истинно. Если условие ложно, никакой другой фрагмент взамен не используется.

Синтаксис сложной условной конструкции следующий:

      УСЛОВНАЯ-ДИРЕКТИВА   
      ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ   
      else   
      ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ   
      endif   
Если условие истинно, используется ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае используется ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ. ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ может занимать любое количество строк текста.

Синтаксис УСЛОВНОЙ-ДИРЕКТИВЫ в простой и в сложной условной конструкции один и тот же. Есть четыре различных директивы, которые проверяют различные условия. Вот их список:

'ifeq (ARG1, ARG2)'

'ifeq 'ARG1' 'ARG2''

'ifeq "ARG1" "ARG2"'

'ifeq "ARG1" 'ARG2''

'ifeq 'ARG1' "ARG2"'

Подставляет значения для всех ссылок на переменные в переменных arg1 и arg2 и сравнивает их. Если они идентичны, обрабатывается ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае - обрабатывается ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ, если он есть

Часто вы хотите проверить, имеет ли переменная непустое значение. Когда переменная получается в результате сложных вычислений переменных и функций, те подставляемые значения, которые вы рассматриваете как простые, могут, на самом деле, содержать пробельные символы и, таким образом, не считаться пустыми. Однако, вы можете использовать функцию strip (смотрите раздел 8.2 [Функции для работы с текстом]), чтобы избежать интерпретации пробелов как непустых значений. Например, в результате вычисления данной условной директивы:

           ifeq ($(strip $(foo)),)   
           ФРАГМЕНТ-ДЛЯ-ПУСТОГО-ЗНАЧЕНИЯ   
           endif   
будет обрабатываться ФРАГМЕНТ-ДЛЯ-ПУСТОГО-ЗНАЧЕНИЯ, даже если результат вычисления $(foo) содержит пробельные символы.

ifneq (ARG1, ARG2)

ifneq 'ARG1' 'ARG2'

ifneq "ARG1" "ARG2"

ifneq "ARG1" 'ARG2'

ifneq 'ARG1' "ARG2"

Подставляет значения для всех ссылок на переменные в переменных arg1 и arg2 и сравнивает их. Если они различаются, обрабатывается ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае - обрабатывается ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ, если он есть

ifdef ИМЯ-ПЕРЕМЕННОЙ

Если переменная с указанным именем имеет непустое значение, обрабатывается ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае - обрабатывается ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ, если он есть. Переменные, которые нигде не были определены, имеют пустое значение.

Обратите внимание, что директива ifdef проверяет, имеет ли переменная значение. Она не вычисляет переменную, чтобы увидеть, является ли ее значение непустым. Следовательно, проверка с использование директивы ifdef определит выполнение условия для всех переменных, чьи определения имеют вид, отличный от foo =. Чтобы проверить на пустое значение, используйте директиву ifeq ($(foo),). Например, следующий фрагмент make-файла:

           bar =   
           foo = $(bar)   
           ifdef foo   
           frobozz = yes   
           else   
           frobozz = no   
           endif   
устанавливает 'yes' в качестве значения переменной frobozz, в то время как такой фрагмент:

           foo =   
           ifdef foo   
           frobozz = yes   
           else   
           frobozz = no   
           endif   
устанавливает 'no' в качестве значения переменной frobozz.

ifndef ИМЯ-ПЕРЕМЕННОЙ

Если переменная с указанным именем имеет пустое значение, обрабатывается ФРАГМЕНТ-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ, в противном случае - обрабатывается ФРАГМЕНТ-ДЛЯ-НЕВЫПОЛНЕННОГО-УСЛОВИЯ, если он есть.

В начале строки с условной директивой разрешается добавлять пробелы, но символ табуляции не разрешен. (Если строка начинается с символа табуляции, она будет рассматриваться как команда для правила.) Кроме этого, дополнительные пробелы или символы табуляции без последствий могут вставляться в любом месте, только не внутри имени директивы и не внутри аргумента. В конце строки может появиться символ начала комментария '#'.

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

Условные конструкции воздействуют на то, какие строки make-файла использует программа make. Если условие истинно, make считывает строки ФРАГМЕНТА-ДЛЯ-ВЫПОЛНЕННОГО-УСЛОВИЯ как часть make-файла, если же условие ложно, make полностью игнорирует эти строки. Из этого следует, что синтаксические единицы make-файла, такие как правила, могут быть безопасно разбиты на части началом или окончанием условной конструкции.

make обрабатывает условные конструкции в момент чтения make-файла. Слкдовательно, вы не можете использовать автоматические переменные в условиях условных конструкций, поскольку они не определены до момента выполнения команд (смотрите раздел 10.5.3 [Автоматические переменные]).

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

7.3 Условные конструкции, которые проверяют опции

Вы можете написать условную конструкцию, которая проверяет опцию командной строки программы make, такую как '-t', используя переменную MAKEFLAGS вместе с функцией findstring (смотрите раздел 8.2 [Функции подстановки и анализа строк]). Это полезно в тех случаях, когда программы touch недостаточно для того, чтобы файл выглядел обновленным.

Функция findstring определяет, появляется ли одна строка внутри другой в качестве подстроки. Если вы хотите проверить опцию '-t', используйте 't' в качестве первой строки и значение переменной MAKEFLAGS в качестве второй.

Здесь приведен пример того, как ввести соглашение об использовании 'ranlib -t' при окончании отметки архивного файла как обновленного:

      archive.a: ...   
      ifneq (,$(findstring t,$(MAKEFLAGS)))   
              +touch archive.a   
              +ranlib -t archive.a   
      else   
              ranlib archive.a   
      endif   
Префикс '+' помечает соответствующие командные строки как "рекурсивные" для того, чтобы они были исполнены, несмотря на использование опции -t. Смотрите раздел 5.6 [Рекурсивное использование make].


Вперед Назад Содержание
Вперед Назад Содержание

8. Функции преобразования текста

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

8.1 Синтаксис вызова функции

Вызов функции внешне напоминает ссылку на переменную. Он выглядит так:

      $(ФУНКЦИЯ АРГУМЕНТЫ)   
или так:

      ${ФУНКЦИЯ АРГУМЕНТЫ}   
Здесь ФУНКЦИЯ представляет собой имя функции, которое берется из небольшого набора имен, встроенных в программу make. Для определения новых функций возможностей нет.

АРГУМЕНТЫ представляют собой аргументы функции. Они отделяются от имени функции одним или более пробелами или символами табуляции, а в том случае, если имеется более, чем один аргумент, то они разделяются запятыми. Эти пробельные символы и запятые не являются частью значения аргумента. Ограничители, используемые вами для ограничения вызова функции, как круглые скобки, так и фигурные, могут появляться среди аргументов только с соответствующими парными символами, другие виды ограничителей могут появляться в одиночку. Если аргументы сами содержат ссылки вызовы других функций или ссылки на переменные, правильнее всего использовать один и тот же вид ограничителей для всех ссылок - то есть, пишите '$(subst a,b,$(x))', а не '$(subst a,b,${x})'. Причина в том что запись с одним видом ограничителей является более ясной, а также, при такой записи, для нахождения конца ссылки ищется только один вид ограничителей.

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

Запятые и непарные скобки, круглые или квадратные, не могут явным образом появляться в тексте, соответствующем аргументу, ведущие пробелы не могут явным образом появляться в тексте, соответствующем первому аргументу. Эти символы могут быть помещены в значение аргумента путем подстановки переменной. Сначала надо определить переменные comma и space, значениями которых являются отдельные символы запятой и пробела, а затем подставить эти переменные там, где требуются такие символы, как показано ниже:

      comma:= ,   
      empty:=   
      space:= $(empty) $(empty)   
      foo:= a b c   
      bar:= $(subst $(space),$(comma),$(foo))   
      # bar is now 'a,b,c'.   
В этом примере функция subst заменяет каждый пробел вместо запятой во всем значении переменной foo, после чего результат работы функции подставляется на место ее вызова.

8.2 Функции подстановки и анализа строк

Ниже приведены некоторые функции, которые обрабатывают строки:

'$(subst ФРАГМЕНТ,ЗАМЕНА,ТЕКСТ)'

Выполняет текстуальную замену в тексте ТЕКСТ: каждое вхождение ФРАГМЕНТА заменяется на ЗАМЕНУ. Результат подставляется на место вызова функции. Например, на место следующего вызова функции:

           $(subst ee,EE,feet on the street)   
подставляется строка 'fEEt on the strEEt'.

'$(patsubst ШАБЛОН,ЗАМЕНА,ТЕКСТ)'

Находит в ТЕКСТЕ разделенные пробельными символами слова, соответствующие ШАБЛОНУ, и заменяет их на ЗАМЕНУ. При этом шаблон может содержать символ '%', который действует как шаблон, соответствующий любому количеству любых символов внутри слова. Если в ЗАМЕНЕ также содержатся символы '%', то они заменяются текстом, соответствующим символу '%' в шаблоне.

Специальное значение символа '%' в вызове функции patsubst может быть отключено предшествующим символом '\'.Специальное назначение символа '\', который в противном случае отменял бы специальное назначение последующего символа '%', может быть отменено еще одним символом '\'. Символы '\', отменяющие специальное назначение символов '%' или других символов '\', удаляются из шаблона перед тем, как он будет сравниваться с именами файлов или в него будет подставляться основа. Символы '\', которые заведемо не влияют на трактовку символа '%', остаются нетронутыми. Например, в шаблоне 'the\%weird\\%pattern\\' фрагмент 'the%weird\' предшествует действующему символу '%', а фрагмент 'pattern\\' следует за ним. С двумя заключительными символами '\' ничего не происходит, поскольку они не могут воздействовать ни на какие символы '%'.

Пробельные символы между словами преобразуются в одиночные пробелы, ведущие и ведомые пробельные символы отбрасываются.

Например, следующий вызов функции

           $(patsubst %.c,%.o,x.c.c bar.c)   
порождает значение 'x.c.o bar.o'.

Ссылки с заменой (смотрите раздел 6.3.1 [Cсылки с заменой]) являются более простым способом получить результат, аналогичный использованию функции patsubst. Например, такая ссылка с заменой:

           $(VAR:PATTERN=REPLACEMENT)   
эквивалентна вызову функции patsubst:

           $(patsubst PATTERN,REPLACEMENT,$(VAR))   
Еще одно сокращение упрощает одно из наиболее частых использований функции patsubst: замену суффикса в конце именем файлов. Такая ссылка с заменой:

           $(VAR:SUFFIX=REPLACEMENT)   
эквивалентна вызову функции patsubst:

           $(patsubst %SUFFIX,%REPLACEMENT,$(VAR))   
Например, у вас мог бы быть список объектных файлов:

           objects = foo.o bar.o baz.o   
Чтобы получить список соответствующих исходных файлов, вы могли

бы просто написать:

           $(objects:.o=.c)   

вместо испрользования общей формы:

           $(patsubst %.o,%.c,$(objects))   
'$(strip СТРОКА)'

Удаляет ведущие и ведомые пробелы из СТРОКИ заменяет каждую внутреннюю последовательность из одного или более пробельного символа на один пробел. Таким образом, результатом вызова '$(strip a b c )' является 'a b c'.

Функция strip может быть очень полезной при использовании ее вместе с условными конструкциями. При сравнении чего-либо с пустой строкой '' с помощью директив ifeq или ifneq вы обычно хотите, чтобы строка, состоящая только из пробельных символов, была равна пустой строке (смотрите главу 7 [Условные конструкции]).

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

           .PHONY: all   
           ifneq   "$(needs_made)" ""   
           all: $(needs_made)   
           else   
           all:;<htmlurl name="@echo" url="mailto:@echo"> 'Nothing to make!'   
           endif   
Замена в директиве ссылки на переменную $(needs_made) на вызов функции $(strip $(needs_made)) ifneq сделало бы этот фрагмент более корректным.

'$(findstring ФРАГМЕНТ,СТРОКА)'

Ищет в СТРОКЕ вхождение ФРАГМЕНТА. Если вхождение есть, то результатом функции является ФРАГМЕНТ, в противном случае результатом является пустая строка. Вы можете использовать эту функцию в условной конструкции для того, чтобы проверить наличие специальной подстроки в данной строке. Таким образом, следующих вызовы функций:

           $(findstring a,a b c)   
           $(findstring a,b c)   
порождают, соответственно, значения 'a' и '' (пустую строку). Смотрите раздел 7.3 [Проверка опций] для информации опрактическом применении функции findstring.

'$(filter ШАБЛОН...,ТЕКСТ)'

Удаляет из ТЕКСТА все разделенные пробельными символами слова, которые не соответствуют ни одному из шаблонных слов, возвращая только слова, соответствующие, по крайней мере, одному из шаблонов. Шаблоны пишутся с использованием символа '%', также как и шаблоны, используемые в описанной выше функции patsubst.

Функция filter может быть использована для выделения из переменной различных типов строк (таких, как имена файлов). Например, приведенный ниже фрагмент make-файла:

           sources := foo.c bar.c baz.s ugh.h   
           foo: $(sources)   
                   cc $(filter %.c %.s,$(sources)) -o foo   
говорит о том, что файл 'foo' зависит от файлов 'foo.c', 'bar.c', 'baz.s' и 'ugh.h', но только 'foo.c', 'bar.c' и 'baz.s' должны быть определены для компилятора в командной строке.

'$(filter-out ШАБЛОН...,ТЕКСТ)'

Удаляет из ТЕКСТА все разделенные пробельными символами слова, которые соответствуют какому-нибудь из шаблонных слов, возвращая только слова, не соответствующие ни одному из шаблонов. Это является точной противоположностью функции filter.

Например, при таких определениях переменных:

           objects=main1.o foo.o main2.o bar.o   
           mains=main1.o main2.o   
приведенный ниже фрагмент make-файла приводит к генерации списка, содержащего все объектные файлы, не указанные в переменной mains

           $(filter-out $(mains),$(objects))   

'$(sort СПИСОК)'

Список в лексическом порядке слова из СПИСКА, удаляя дублирующиеся слова. Результатом является список слов, разделенных одиночными пробелами. Таким образом, при таком вызове функции:

           $(sort foo bar lose)   
получается значение 'bar foo lose'.

Кстати, поскольку функция sort удаляет дублирующиеся слова, вы можете использовать ее для этой цели, даже если вам не нужны возможности, связанные с сортировкой.

Вот реалистичный пример использования функций subst и patsubst. Предположим, что make-файл использует переменную VPATH для определения списка каталогов, в которых программа make должна искать файлы зависимости (смотрите раздел 4.3.1 [VPATH: Путь поиска для всех зависимостей]). Это пример показывает, как указать C-компилятору искать заголовочные файлы в том же списке каталогов.

Значение переменной VPATH представляет собой список каталогов, разделенных двоеточиями, например 'src:../headers'. Сначала надо использовать функцию subst для замены двоеточий на пробелы:

      $(subst :, ,$(VPATH))   
В результате получается значение 'src ../headers'. Затем следует использовать функцию patsubst для того чтобы подставить перед каждым именем каталога оицию '-I'. Получившееся значение может быть добавлено к значению переменной CFLAGS, которая автоматически передается C-компилятору, как показано ниже:

      override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))   
В итоге к имевшемуся ранее значению переменной CFLAGS добавляется фрагмент '-Isrc -I../headers'. Из-за использования директивы override, присваивание нового значения будет происходить даже в том случае, если предыдущее значение переменной CFLAGS было определено при помощи аргумента командной строки.

8.3 Функции для обработки имен файлов

Несколько дополнительных встроенных функций специально ориентированы на работу с именами файлов и списками имен файлов.

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

'$(dir ИМЕНА...)'

Выделяет часть, определяющую каталог, из каждого имени файла, указанного в списке ИМЕН. Часть имени файла, определяющая каталог, представляет собой часть имени от его начала до последнего символа '/' (включительно). Если в имени файла не содержится символа '/', частью, определяющей каталог, является './'. Например, при таком вызове функции:

           $(dir src/foo.c hacks)   
в качестве результата получается 'src/ ./'.

'$(notdir ИМЕНА...)'

Выделяет из каждого имени файла, указанного в списке ИМЕН, то, что не входит в часть, определяющую каталог,. Если имя файла не содержит ни одного символа '/', то оно остается неизмененным. В противном случае, из имени файла удаляется все то, что в нем расположено до последнего символа '/'.

Имя файла, заканчивающееся символом '/' преобразуется в пустую строку. Это является удачным, поскольку означает, что результат не всегда содержит такое же количество разделенных пробельными символами имен файлов, как и аргумент, но мы не видим другой подходящей альтернативы. Например, при таком вызове функции:

           $(notdir src/foo.c hacks)   
в качестве результата получается 'foo.c hacks'.

'$(suffix ИМЕНА...)'

Выделяет суффикс каждого имени файла из списка ИМЕН. Если имя файла содержит точку, то суффиксом является часть имени от его последней точки до конца. В противном случае, суффиксом является пустая строка. Часто это означает, что результат функции будет пустым при непустом аргументе, а при аргументе, содержащем несколько имен файлов, результат может содержать их в меньшем количестве:

Например, при таком вызове функции:

           $(suffix src/foo.c hacks)   
в качестве результата получается '.c'.

'$(basename ИМЕНА...)'

Выделяет из каждого имени файла из списка ИМЕН базовое имя - все то, что не относится к суффиксу. Если имя файла содержит точку, то базовым именем является часть имени от его начала последней точки (исключительно). В противном случае, базовым именем является все имя файла. Например, при таком вызове функции:

           $(basename src/foo.c hacks)   
в качестве результата получается 'src/foo hacks'.

'$(addsuffix СУФФИКС,ИМЕНА...)'

Аргумент ИМЕНА рассматривается как последовательность имен, разделенных пробельными символами, а СУФФИКС используется как одно целое. Значение аргумента СУФФИКС добавляется в конец каждого отдельного имени и получившиеся удлиненные имена сцепляются, с одиночными пробелами между собой. Например, при таком вызове функции:

           $(addsuffix .c,foo bar)   

в качестве результата получается 'foo.c bar.c'.

'$(addprefix ПРЕФИКС,ИМЕНА...)'

Аргумент ИМЕНА рассматривается как последовательность имен, разделенных пробельными символами, а ПРЕФИКС используется как одно целое. Значение аргумента ПРЕФИКС двставляется в начало каждого отдельного имени и получившиеся удлиненные имена сцепляются, с одиночными пробелами между собой. Например, при таком вызове функции:

           $(addprefix src/,foo bar)   
в качестве результата получается 'src/foo src/bar'.

'$(join СПИСОК1,СПИСОК2)'

Сцепляет слова из двух аргументов: два первых слова (по одному из каждого аргумента), в результате сцепления, образуют первое слово результата, два вторых слова образуют второе слово результата, и так далее. Таким образом, n-е слово результата образуется из n-х слов каждого аргумента. Если в одном из аргументов слов больше, чем в другом, избыточные слова копируются в результат неизмененными.

Например, при вызове '$(join a b,.c .o)' в качестве результата получается 'a.c b.o'.

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

Эта функция может слить результаты функций dir and notdir, порождая первоначальный список файлов, переданный этим двум функциям.

'$(word N,ТЕКСТ)'

Возвращает N-е слово ТЕКСТА. Допустимые значения переменной N начинаются с 1. Если N больше, чем количество слов в ТЕКСТЕ, результатом является пустое значение. Например, при таком вызове:

           $(word 2, foo bar baz)   
результатом будет 'bar'.

'$(words ТЕКСТ)'

Возвращает количество слов в ТЕКСТЕ. Таким образом, последнее слово текста может быть получено при помощи вызова '$(word $(words TEXT),TEXT)'.

'$(firstword ИМЕНА...)'

Аргумент ИМЕНА рассматривается как последовательность имен, разделенных пробельными символами. Значением является первое имя в последовательности. Оставшаяся часть имени игнорируется.

Например, при таком вызове функции:

           $(suffix src/foo.c hacks)   
в качестве результата получается 'foo'. Хотя вызов $(firstword TEXT) аналогичен вызову $(word 1,TEXT), функция firstword остается в употреблении из-за ее простоты.

'$(wildcard ШАБЛОН)'

Аргумент ШАБЛОН является шаблоном имени файла, обычно содержащим шаблонные символы (как шаблонах имени файла, используемых в командной оболочке). Результатом функции wildcard является разделенный пробелами список имен существующих файлов, удовлетворяющих шаблону. Смотрите раздел 4.2 [Использование шаблонных символов в именах файлов].

8.4 8.4 Функция foreach

Функция foreach сильно отличается о других функций. При ее использовании определенная часть текста используется повторно, при этом каждый раз над ней выполняются различные подстановки. Это похоже на команду for в командной оболочке sh и на команду csh в командной C-оболочке csh.

Синтакисис функции foreach слудующий:

      $(foreach ПЕРЕМЕННАЯ,СПИСОК,ТЕКСТ)   
Первые два аргумента, ПЕРЕМЕННАЯ и СПИСОК, вычисляются до того, как что-либо еще будет сделано; обратите внимание, что последний аргумент, ТЕКСТ, не вычисляется в это время. Затем для каждого слова из вычисленного значения аргумента СПИСОК, переменная с именем, полученным из вычисленного значения аргумента ПЕРЕМЕННАЯ, получает в качестве значения это слово, и аргумент ТЕКСТ вычисляется. Предполагается, что ТЕКСТ содержит ссылки на эту переменную, поэтому результат ее вычисления будет каждый раз различным.

В итоге аргумент ТЕКСТ вычисляется столько раз, сколько разделенных пробельными симвролами слов есть в СПИСКЕ. Результаты множественных вычислений аргумента ТЕКСТ сцепляются, с пробелами между ними, порождая результат функции foreach.

В приведенном ниже простом примере в качестве значения переменной 'files' устанавливается список всех файлов в каталогах, перечисленных списке, представленном переменной 'dirs':

      dirs := a b c d   
      files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))   
В данном случае значением аргумента является '$(wildcard $(dir)/*)'. При первой итерации в качестве значения dir берется 'a', что приводит к такому же результату, как и вызов '$(wildcard a/*)', при второй итерации получается результат, аналогичный вызову '$(wildcard b/*)', а при третьей - вызову '$(wildcard c/*)'.

Этот пример дает такой же результат (за исключением установки переменной dirs), как и следующий пример:

      files := $(wildcard a/* b/* c/* d/*)   

Когда аргумент ТЕКСТ сложен, вы можете улучшить читабельность, дав ему имя при помощи дополнительной переменной:

      find_files = $(wildcard $(dir)/*)   
      dirs := a b c d   
      files := $(foreach dir,$(dirs),$(find_files))   
В этом примере мы для этого используем переменную find_files. Мы используем просто символ '=' для того, чтобы определить рекурсивно-вычисляемую переменную, и поэтому ее значение, на самом деле, содержит вызов функции, который повторно вычисляется под управлением функции foreach - для упрощенно-вычисляемой переменной это бы не сработало, так как функция wildcard была бы вызвана только один раз, во время определения переменной find_files.

Функция foreach не оказывает необратимого эффекта на переменную, соответствующую аргументу ПЕРЕМЕННАЯ - ее значение и разновидность после вызова функции foreach остаются такими же, как и были ранее. Другие значения, которые берутся из СПИСКА, находятся в действии только временно, в период выполнения функции foreach. Переменная, соответствующая аргументу ПЕРЕМЕННАЯ, в период выполнения функции foreach является упрощенно вычисляемой переменной. Если переменная, соответствующая аргументу ПЕРЕМЕННАЯ, была неопределенной перед вызовом функции foreach, то она остается неопределенной и после вызова. Смотрите раздел 6.2 [Две разновидности переменных].

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

      files := $(foreach Esta escrito en espanol!,b c ch,$(find_files))   
могло быть полезным, если бы в значении переменной find_files была ссылка на переменную с именем 'Esta escrito en espanol!', но наиболее вероятно, что это является ошибкой.

8.5 Функция origin

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

Функция origin имеет такой синтаксис:

      $(origin ПЕРЕМЕННАЯ)   
Обратите внимание на то, что аргумент ПЕРЕМЕННАЯ - это имя переменной, на которую делается запрос, а не ссылка на эту переменную. Следовательно, обычно при написании аргумента вы не будете использовать символ '$' или круглые скобки. (Однако, вы можете использовать в имени ссылку на переменную, если хотите, чтобы имя не было фиксированным.)

Результатом этой функции является строка, дающая вам информацию о том, как была определена переменная, определяемая аргументом ПЕРЕМЕННАЯ:

'undefined'

если эта переменная нигде не была определена.

'default'

Если эта переменная имеет определение, действующее по умолчанию, что обычно имеет место для переменной CC и подобных ей. Смотрите раздел 10.3 [Переменные, используемые неявными правилами]. Обратите внимание, что если вы переопределили переменную, имеющую значение по умолчанию, функция origin даст вам информацию о происхождении, соответствующую более позднему определению.

'environment'

Если эта переменная была определена как переменная командной среды, и при этом не указана опция '-e' (смотрите раздел 9.7 [Обзор опций]).

'environment override'

Если эта переменная была определена как переменная командной среды, и при этом указана опция '-e' (смотрите раздел 9.7 [Обзор опций]).

'file'

Если эта переменная была определена в make-файле

'command line'

Если эта переменная была определена в командной строке

'override'

Если эта переменная была определена в make-файле при помощи директивы override (смотрите раздел 6.7 [Директива override]).

'automatic'

Если эта переменная является автоматической переменной, определяемой для выполнения команд в каждом правиле (смотрите раздел 10.5.3 [Автоматические переменные]).

Эта информация полезна в первую очередь (не считая вашего любопытства) для определения, хотите ли вы доверять значению переменной. Например, предположим, что у вас есть make-файл 'foo', в котором происходит включение другого make-файла - 'bar'. Вы хотите, чтобы при использовании команды 'make -f bar' переменная bletch была определена в файле 'bar', даже если в командной среде содержится определение переменной bletch. Однако, если в файле 'foo' перед включением файла 'bar' определена если переменная bletch, вы не хотите перекрывать это определение. Это могло бы быть реализовано с использованием в файле 'foo' директивы override, что давало бы этому определению преимущество перед более поздним определением в фале 'bar', но, к сожалению, директива override перекрыла бы также любые определения, данные в командной строке. Таким образом, файл 'bar' мог бы содержать такой фрагмент:

      ifdef bletch   
        ifeq "$(origin bletch)" "environment"   
          bletch = barf, gag, etc.   
        endif   
      endif   
Если бы переменная bletch была определена в командной среде, это вызвало бы ее переопределение.

Если вы хотите перекрыть предыдущее определение переменной bletch, если она определена в командной среде, даже при использовании опции '-e', вы могли бы вместо этого написать:

      ifneq "$(findstring environment,$(origin bletch))" ""   
      bletch = barf, gag, etc.   
      endif   
В данном случае переопределение имеет местов том случае, если при вызове '$(origin bletch)' возвращается значение 'environment' или 'environment override'. Смотрите раздел 8.2 [Функции подстановки и анализа строк].

8.6 Функция shell

Функция shell отличается от любой другой функции, кроме функции wildcard (смотрите раздекл 4.2.3 [Функция wildcard]), тем, что она общается с внешним, по отношению к программе make, миром.

Функция shell выполняет те же действия, которые выполняют обратные апострофы ('`') в большинстве командных оболочек: она выполняет подстановку результатов команд. Это означает, что она принимает аргумент, являющийся командой командной оболочки, а ее результатом является выход этой команды. Единственной работой, выполняемой программой make над результатом перед подстановкой его в окружающий текст, является преобразование символов перевода строки в пробелы.

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

Ниже приведены некоторые примеры использования функции shell. В первом случае:

      contents := $(shell cat foo)   
в качестве значения переменной contents устанавливается содержимое файла 'foo', с пробелом (а не символом перевода строки) в качестве разделителей строк файла. А во втором случае:

      files := $(shell echo *.c)   
в качестве значения переменной contents устанавливается результат поиска файлов текущего каталога, соответствующих шаблону '*.c'. Если программа make не использует очень необычную команду оболочки, такой вызов дает такой же результат, что и вызов '$(wildcard *.c)'.


Вперед Назад Содержание
Вперед Назад Содержание

9. Как запускать make

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

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

Передавая программе make аргументы при ее запуске, вы можете сделать все это, а также много другого.

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

0

Возвращаемым результатом является нуль, если программа make выполнилась успешно

2

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

1

Возвращаемым результатом является единица, если вы используете опцию '-q' и программа make определяет, что какая-то цель не является, на момент запуска программы make, обновленной. Смотрите раздел 9.3 [Вместо исполнения команд].

9.1 Аргументы для определения make-файла

Для определения имени make-файла служит опция '-f' или '--file' (работает также опция '--makefile'). Например, фрагмент командной строки '-f altmake' указывает на использование в качестве make-файла файла с именем 'altmake'.

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

Если вы не используете опцию '-f' или '--file', то в качестве имен по умолчанию пробуются имена 'GNUmakefile', 'makefile' и 'Makefile', именно в таком порядке, и в роли make-файла используется первый из этих трех, который существует или может быть порожден (смотрите главу 3 [Написание make-файлов]).

9.2 Аргументы для определения главных целей

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

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

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

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

Одно из использований определения главной цели возможно в том случае, если вы хотите откомпилировать только часть программы или только одну из нескольких программ. Определите в качестве главной цели каждый файл, который вы хотите заново породить. Например, рассмотрим каталог, содержащий несколько программ, с make-файлом, который начинается примерно так:

      .PHONY: all   
      all: size nm ld ar as   
Если вы работаете над программой size, то вы могли бы захотеть написать в качестве команды 'make size', и при этом были бы перекомпилированы только файлы этой программы.

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

Определение главной цели также может использоваться при запуске команд, связанных с целями-именами действий (смотрите раздел 4.4 [Цели-имена действий]) или пустыми целями (смотрите раздел 4.6 [Пустые целевые файлы для фиксации событий]). Многие make-файлы содержат цель-имя действия и именем 'clean', которая удаляет все, за исключением исходных файлов. Естественно, это делается только в том случае, если вы явно требуете этого при помощи 'make clean'. Ниже приведен список типичных имен целей-имен действий и пустых целей. Смотрите раздел 14.3 [Стандартные цели], для детального списка всех стандартных имен целей, которые используются программными пакетами GNU.

'all'

Порождает все цели верхнего уровня, которые упомянуты в make-файле

'clean'

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

'mostlyclean'

Аналогично цели 'clean', но может воздержаться от удаления некоторых файлов, перекомпилировать которые обычно не хочется. Например, в GCC цель 'mostlyclean' не удаляет файл 'libgcc.a', поскольку ее перекомпиляция требуется редко и занимает много времени.

'distclean'

'realclean'

'clobber'

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

'install'

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

'print'

Печатает список измененных исходных файлов.

'tar'

Создает из исходных файлов tar-файл.

'shar'

Создает из исходных файлов архив командной оболочки (shar-файл).

'dist'

Создает из исходных файлов распространяемый файл. Это может быть tar-файл или shar-файл, или же сжатая версия одного из них, или даже что-нибудь еще, не упомянутое здесь.

'TAGS'

Обновляет таблицу тэгов программы, получаемой при помощи данного make-файла.

'check'

'test'

Выполняет самотестирование программы, получаемой при помощи данного make-файла.

9.3 Вместо исполнения команд

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

'-n'

'--just-print'

'--dry-run'

'--recon'

"Нет операций". Действия программы make состоят в выводе на экран тех команд, которые использовались бы для обновления целей, но без реального их выполнения.

'-t'

'--touch'

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

'-q'

'--question'

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

'-W FILE'

'--what-if=FILE'

'--assume-new=FILE'

'--new-file=FILE'

"А что, если". За каждой опцией '-W' следует имя файла. В качестве времени изменения данных файлов программой make запоминается текущее время, хотя реальные времена модификации остаются прежними. Вы можете использовать опцию '-W' вместе с опцией '-n' для того, чтобы увидеть что произошло бы, если вам потребовалось изменить определенные файлы.

При указанной опции '-n', программа make печатает команды, которые обычно она бы выполняла, но без их выполнения.

При указанной опции '-t', программа make игнорирует команды в правилах и использует (точнее, создает эффект использования) команду touch для каждой цели, которую нужно заново порождать. При этом также печатается команда touch, если не используется опция '-s' или цель .SILENT. Для ускорения работы, программа make, в действительности, не вызывает программу touch. Она напрямую выполняет ее работу.

При указанной опции '-q', программа make ничего не печатает и не выполняет никаких команд, но возвращаемый ею результат является нулем, если, и только если, рассматриваемые ею цели уже являются обновленными. Если результатом является единица, то это значит, что необходимо выполнить какое-либо обновление. Если программа make обнаруживает ошибку, то результатом является двойка, поэтому вы можете отличить ошибку от необновленной цели.

Является ошибкой использование более, чем одной из этих трех опций в одном вызове программы make.

Опции '-n', '-t', и '-q' не воздействуют на командные строки, которые начинаются с символа '+' или содержат в качестве подстроки '$(MAKE)' или '${MAKE}'. Обратите внимание, что только строка, начинающаяся с символа '+' или содержащая подстроку '$(MAKE)' или '${MAKE}' выполняется, невзирая на эти опции. Другие строки в том же правиле не выполняются, если они также не начинаются с символа '+' и не содержат в качестве подстроки '$(MAKE)' или '${MAKE}'. (Смотрите раздел 5.6.1 [Как pаботает пеpеменная make].)

Опция '-W' обеспечивает две возможности:

Обратите внимание, что опции '-p' and '-v' позволяют вам получить другую информацию о программе make и о используемых make-файлах (смотрите раздел 9.7 [Обзор опций]).

9.4 Предотвращение перекомпиляции некоторых файлов

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

Если перед изменением заголовочного файла вы предвидите эту проблему, то вы можете использовать опцию '-t'. Эта опция указывает программе make не выполнять команды из правил, а вместо этого пометить цель как обновленную путем изменения времени ее последней модификации. Вам следует придерживаться такого порядка действий:

  1. Используйте команду make для перекомпиляции исходных файлов, которые на самом деле требуют перекомпиляции.
  2. Сделайте изменения в исходных файлах.
  3. Используйте команду 'make -t' для отметки всех объектных файлов как обновленных. Когда вы в следующий раз запустите программу make, изменения в заголовочных файлах не вызовут никакой перекомпиляции.
Если вы уже изменили заголовочный файл в тот момент, когда некоторые файлы требуют перекомпиляции, делать это слишком поздно. Вместо этого, вы можете использовать опцию '-o <имя файла>', которая отмечает указанный файл как "старый" (смотрите раздел 9.7 [Обзор опций]). Это означает, что сам этот файл не будет заново порожен и ничего больше не будет заново порождено по причине изменения этого файла. Следуйте такому порядку действий:
  1. Перекомпилируйте исходные файлы, которые нуждаются в компиляции по причинам, не зависящим от определенного заголовочного файла, при помощи команды 'make -o <имя заголовочного файла>'. Если речь идет о нескольких заголовочных файлах, используйте отдельную опцию '-o' для каждого заголовочного файла.
  2. Измените время обновления всех объектных файлов при помощи команды 'make -t'.

9.5 Перекрывающиеся переменные

Аргумент, который содержит символ '=', определяет значение переменной: аргумент 'v=x' устанавливает x в качестве значения переменной v. Если вы определяете значение таким образом, то в make-файле все обычные присваивания значения этой же переменной игнорируются - мы говорим, что они перекрываются аргументом командной строки.

Наиболее типичным использованием этой возможности является передача дополнительных опций компиляторам. Например, в грамотно написанном make-файле в каждую команду, которая запускает C-компилятор, включается переменная CFLAGS, поэтому файл 'foo.c' должен компилироваться примерно так:

      cc -c $(CFLAGS) foo.c   
Таким образом, в какое значение вы ни устанавливаете переменную CFLAGS, это воздействует на каждый сеанс компиляции. make-файл, возможно, определяет обычное значение для переменной CFLAGS, например так:

      CFLAGS=-g   
Каждый раз, когда вы запускаете программу make, вы, если хотите, можете перекрыть это значение. Например, если вы напишете в командной строке 'make CFLAGS='-g -O'', каждый раз C-компиляция будет выполняться при помощи командной строки 'cc -c -g -O'. (Это иллюстрирует то, как вы можете использовать в командной оболочке апострофы для включения в значение переменной, при ее перекрытии, пробелов и других специальных символов.)

Переменная CFLAGS - это только одна их многих стандартных переменных, которые существуют только для того, чтобы вы могли изменять их таким образом. Смотрите раздел 10.3 [Переменные, используемые неявными правилами], где приведен полный их список.

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

Когда вы перекрываете переменную при помощи аргумента командной строки, вы можете определить либо рекурсивно вычисляемую переменную, либо упрощенно вычисляемую переменную. В примерах, показанных выше, создается рекурсивно вычисляемая переменная; для создания упрощенно вычисляемой переменной, пишите ':=' вместо '='. Но если вы не хотите включать в определяемое вами значение ссылку на переменную или вызов функции, то становится безразличным, какого вида переменную вы создаете.

Если один способ, при помощи которого make-файл может изменить переменную, которую вы перекрыли. Он заключается в использовании директивы override, которая представляет собой строку, которая выглядит примерно так: 'override VARIABLE = VALUE' (смотрите раздел 6.7 [Директива override]).

9.6 Проверка компиляции программ

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

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

В таких случаях вам следует использовать опцию '-k' или '--keep-going'. Она указывает программе make продолжать работу с другими зависимостями обновляемых целей, при необходимости заново порождая эти зависимости, перед прекращением работы возвратом ненулевого результата. Например, в случае ошибки при компиляции одного объектного файла, программа make, запущенная при помощи командной строки 'make -k', продолжит компиляцию других объектных файлов, хотя уже и известно, что их компоновка будет невозможна. Помимо продолжения работы после после неудачной команды командной оболочки, программа make, запущенная при помощи командной строки 'make -k', будет продолжать работу как можно дольше после того, как она выяснит, что не знает, как породить целевой файл или файл зависимости. Такая ситуация всегда будет вызывать сообщение об ошибке, но без опции '-k' это является фатальной ошибкой (смотрите раздел 9.7 [Обзор опций]).

Обычное поведение програмы make предполагает, что вы стремитесь получить обновленные главные цели - как только программа make выясняет, что это невозможно, она также может сразу сообщить о неудаче в своей работе. Опция '-k' указывает на то, что на самом деле программа make используется для проверки как можно большего количества изменений, сделанных в программе, возможно, для поиска нескольких независимых проблем для того, чтобы вы могли исправить их перед следующей попыткой компиляции. Именно поэтому M-x compile, команда редактора Emacs, по умолчанию передает программе make опцию '-k'.

9.7 Обзор опций

Вот список всех опций, которые понимает программа make:

'-b'

'-m'

Эти опции включены для совместимости с другими версиями программы make и они игнорируются.

'-C <каталог>'

'--directory=<каталог>'

Перед чтением make-файлов переходит в каталог, определяемый аргументом <каталог>. Если определены несколько опций '-C', то каждая из них интерпретируется относительно предыдущей: фрагмент командной строки '-C / -C etc' эквивалентен такому фрагменту: '-C /etc'. Это обычно используется при рекурсивных вызовах программы make. (смотрите раздел 5.6 [Рекурсивное использование программы make]).

'-d'

'--debug'

Помимо обычной работы, выводит отладочную информацию. Отладочная

информация говорит о том, какие файлы рассматриваются на предмет

порождения их заново, времена изменения каких файлов

сравниваются и с какими результатами, какие файлы на самом деле

нуждаются в порождении их заново, какие неявные правила

принимаются в расчет и какие из них применяются - все, что имеет

отношение к тому, как программа make решает, что делать.

'-e'

'--environment-overrides'

Дает переменным, взятым из командной среды, приоритет перед переменными из make-файлов. Смотрите раздел 6.9 [Переменные из командной среды].

'-f <имя файла>'

'--file=<имя файла>'

'--makefile=<имя файла>'

Читает в качестве make-файла файл с именем, определяемым аргументом <имя файла>. Смотрите главу 3 [Написание make-файлов].

'-h'

'--help'

Напоминает вам об опциях, которые понимает программа make, после чего заканчивает работу.

'-i'

'--ignore-errors'

Игнорирует все ошибки в командах, выполняемых для порождения файлов заново. Смотрите раздел 5.4 [Ошибки в командах].

'-I <каталог>'

'--include-dir=<каталог>'

Назначает каталог, определяемый аргументом <каталог> для поиска включаемых make-файлов. Смотрите раздел 3.3 [Включение других make-файлов]. Если если используется несколько опций '-I' для определения нескольких каталогов, поиск по каталогам происходит в том порядке, в котором они перечислены.

'-j [<задания>]'

'--jobs=[<задания>]'

Определяет количество заданий (команд), которые будут выполняться одновременно. При отсутствии аргумента, программа make запускает одновременно столько заданий, сколько возможно. Если определена более, чем одна опция '-j', то действует та, которая указана последней в командной строке. Смотрите раздел 5.3 [Параллельное выполнение], для дополнительной информации о том, как выполняются команды.

'-k'

'--keep-going'

Продолжает работу после ошибки как можно дольше. В то время как порождение цели закончилось неудачно, и цели, зависящие от нее, не могут быть заново порождены, другие зависимости этих целей все равно могут быть обработаны. Смотрите раздел 9.6 [Проверка компиляции программ].

'-l [<загрузка>]'

'--load-average[=<загрузка>]'

'--max-load[=<загрузка>]'

Определяет, что ни одно новое задание (команда) не должно стартовать, если есть другие запущенные задания и средняя загрузка не меньше, чем значение, определяемое аргументом <загрузка> (число с плавающей точкой). Отсутствие аргумента отменяет действие предыдущего предела загрузки.

'-n'

'--just-print'

'--dry-run'

'--recon'

Печатает команды, который должны выполняться, но не выполняет их. Смотрите раздел 9.3 [Вместо исполнения команд].

'-o <имя файла>'

'--old-file=<имя файла>'

'--assume-old=<имя файла>'

Не порождает заново файл с именем, определяемым аргументом <имя файла>, даже если он более старый, чем его зависимости, и не порождает заново ничего, что заново порождалось бы в случае изменений в этом файле. По существу, файл обрабатывается как очень старый и его правила игнорируются. Смотрите раздел 9.4 [Предотвращение перекомпиляции некоторых файлов].

'-p'

'--print-data-base'

Выводится на экран базу данных (правила и значения переменных), которая получается в результате чтения make-файлов, а затем выполняется как обычно или каким-либо другим образом, если это определено. При использовании этой опции также выводится на экран информация о версии, которая дается с помощью опции '-v' (смотрите ниже). Чтобы вывести на экран базу данных, не пытаясь породить заново никаких файлов, используйте команду 'make -p -f /dev/null'.

'-q'

'--question'

"Режим запроса". Не выполняет никаких команд и ничего не печатает - просто возвращает результат, который является нулем, если указанные цели уже обновлены, единицей, если требуется какое-либо новое порождение или двойкой, если обнаруживается ошибка. Смотрите раздел 9.3 [Вместо исполнения команд].

'-r'

'--no-builtin-rules'

Отменяет использование встроенных неявных правил (смотрите главу 10 [Использование неявных правил]). Вы можете при этом определить ваши собственные неявные правила путем написания шаблонных правил (смотрите раздел 10.5 [Определение и переопределение шаблонных правил]). Опция '-r' также очищает список суффиксов, по умолчанию используемый для суффиксных правил (смотрите раздел 10.7 [Устаревшие суффиксные правила]). Но вы можете при этом, с помощью правила для цели .SUFFIXES, определить ваши собственные суффиксы и затем определить ваши собственные суффиксные правила.

'-s'

'--silent'

'--quiet'

Работа без сообщений - не выводит на экран команды в момент их исполнения.

'-S'

'--no-keep-going'

'--stop'

Отменяет действие опции '-k'. Эта опция не нужна никогда, за исключением рекурсивного использования программы make, когда опция '-k' может быть унаследована от процесса make верхнего уровня через переменную MAKEFLAGS (смотрите раздел 5.6 [Рекурсивное использование программы make]), а также установки вами в вашей командной среде опции '-k' в переменную MAKEFLAGS.

'-t'

'--touch'

Изменение времени обновления файлов (пометка их как обновленных без реального их изменения) вместо запуска соответствующих им команд. Это используется в целях создания иммитации того, что команды выполнены, для того, чтобы обмануть будущие вызовы программы make. Смотрите раздел 9.3 [Вместо исполнения команд].

'-v'

'--version'

Выводит на экран версию программы make, а также ее copyright, список авторов и замечание об отсутствии гарантии - после этого работа завершается.

'-w'

'--print-directory'

Выводит на экран сообщение, содержащее имя рабочего каталога как перед, так и после выполнения make-файла. Это может быть полезным для отслеживания ошибок из сложным образом вложенных рекурсивных команд make. Смотритие раздел 5.6 [Рекурсивное использование программы make]. (На практике вам редко придется определять эту опцию, так как программа make делает это за вас - смотрите раздел 5.6.4 [Опция '--print-directory']).

'--no-print-directory'

Отменяет вывод на экран имени рабочего каталога, осуществляемый с помощью опции '-w'. Этот способ полезен тогда, когда опция '-w' устанавливается автоматически, но вы не хотите видеть лишних сообщений. Смотрите раздел 5.6.4 [Опция '--print-directory'].

'-W <имя файла>'

'--what-if=<имя файла>'

'--new-file=<имя файла>'

'--assume-new=<имя файла>'

Делает вид, что цель, определяемая аргументом <имя файла>, только что была изменена. При использовании вместе с опцией '-n', эта опция показывает вам, что бы произошло, если бы вам потребовалось изменить этот файл. Без опции '-n', эта опция почти аналогична запуску команды touch для данного файла перед запуском программы make, за исключением того, что время изменения изменяется только в представлении программы make. Смотрите раздел 9.3 [Вместо исполнения команд].

'--warn-undefined-variables'

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


Вперед Назад Содержание
Вперед Назад Содержание

10. Использование неявных правил

Очень часто используются определенные стандартные способы порождения заново целевых файлов. Например, одним из типичных способов порождения объектного файла является порождение его из исходного C-файла с использованием C-компилятора, cc.

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

Цепочка неявных правил может применяться последовательно - например, программа make заново породит файл с именем, оканчивающемся на '.o' из файла с именем, оканчивающемся на '.y' через файл с именем, оканчивающемся на '.c'. Смотрите раздел 10.4 [Цепочки неявных правил].

Встроенные неявные правила используют в своих командах несколько переменных, так что путем изменения значений переменных вы можете изменять способ, в соответствии с которым работает неявное правило. Например, переменная CFLAGS управляет опциями, передаваемыми C-компилятору неявными правилами для C-компиляции. Смотрите раздел 10.3 [Переменные, используемые неявными правилами].

Вы можете определить ваши собственные неявные правила с помощью написания шаблонных правил. Смотрите раздел 10.5 [Определение и переопределение шаблонных правил].

Суффиксные правила представляют собой более ограниченный способ определения неявных правил. Шаблонные правила являются более общими и ясными, но суффиксные правила оставлены для совместимости. Смотрите раздел 10.7 [Устаревшие суффиксные правила].

10.1 Использование неявных правил

Чтобы дать возможность программе make найти общий метод для обновления целевого файла, все, что вам нужно сделать - это воздержаться от самостоятельного определения команд. Либо напишите правило, не содержащее командных строк, либо вообще не пишите правило. Тогда программа make, основываясь том, какой тип исходного файла существует или может быть порожден, определит, какое неявное правило использовать.

Например, предположим, что make-файл выглядит примерно так:

      foo : foo.o bar.o   
              cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)   
Поскольку вы упоминаете файл 'foo.o', но не даете для него правила, программа make автоматически будет искать неявное правило, которое определяет, как его обновлять. Это происходит независимо от того, существует или нет в данный момент файл 'foo.o'.

Если неявное правило найдено, из него могут быть получены как команды, так и одна или несколько зависимостей (исходных файлов). Вам бы стоило написать для цели 'foo.o' правило без командных строк, если бы вам нужно было определить дополнительные зависимости, например, заголовочные файлы, которые не могут быть получены из неявного правила.

Каждое неявное правило имеет шаблон цели и шаблоны зависимостей. Может быть много неявных правил с одним и тем же шаблоном цели. Например, многочисленные правила порождают '.o'-файлы: одно из '.c'-файла при помощи C-компилятора, другое из '.p'-файла при помощи компилятора с языка Паскаль и т.д.. Правилом, применяемым в конкретной ситуации, является то правило, чьи зависимости существуют или могут быть порождены. Таким образом, если у вас есть файл 'foo.c', программа make запустит C-компилятор, в противном случае, если у вас есть файл 'foo.p', программа make запустит компилятор с языка Паскаль и т.д..

Конечно, когда вы пишете make-файл, вы знаете, какое неявное правило вы хотите, чтобы использовала программа make, и вы будете уверены, что она выберет именно это неявное правило, если будете знать, какие файлы зависимостей предполагаются существующими. Смотрите раздел 10.2 [Перечень неявных правил], для ознакомления с перечнем всех предопределенных неявных правил.

Выше мы сказали, что неявное правило применяется, если требуемые зависимости "существуют или могут быть порождены". Файл "может быть порожден", если он явно упоминается в make-файле в качестве цели или зависимости, или же если рекурсивно может быть найдено неявное правило, определяющее, как его породить. Когда неявная зависимость является результатом другого неявного правила, мы говорим, что происходит образование цепочки. Смотрите раздел 10.4 [Цепочки неявных правил].

Вообще говоря, программа make ищет неявное правило для каждой цели и для каждого правила с двойным двоеточием, которые не имеют команд. Файл, который упоминается только в качестве зависимости, рассматривается как цель, чье правило ничего не определяет, поэтому для него происходит поиск неявного правила. Смотрите раздел 10.8 [Алгоритм поиска неявного правила], в котором приводятся подробности организации поиска.

Обратите внимание, что явные зависимости не оказывают влияния на поиск неявного правила. Например, рассмотрим такое явное правило:

      foo.o: foo.p   
Зависимость от файла 'foo.p' не обязательно означает, что программа make будет заново порождать 'foo.o' в соответствии с неявным правилом для порождения объектного файла, '.o'-файла, из исходного файла, написанного на языке Паскаль, '.p'-файла. Например, если существует также файл 'foo.c', вместо этого будет использовано неявное правило для порождения объектного файла из исходного C-файла, поскольку в списке предопределенных неявных правил (смотрите раздел 10.2 [Перечень неявных правил]) оно появляется перед правилом для языка Паскаль.

Если вы не хотите, чтобы неявное правило было использовано для цели, которая не имеет команд, вы можете установить для этой цели пустую команду, написав точку с запятой (смотрите раздел 5.8 [Определение пустых команд]).

10.2 Перечень неявных правил

Вот перечень предопределенных неявных правил, которые всегда доступны, если make-файл явным образом не перекрывает и не отменяет их. Смотрите раздел 10.5.6 [Отмена неявных правих], где приведена информация об отмене или перекрытии неявных правил. Опция '-r' или '--no-builtin-rules' отменяет все предопределенные правила.

Не все из этих правил всегда будут определены, даже при отсутствии опции '-r'. Многие из предопределенных неявных правил реализуются в программе make как суффиксные правила, поэтому какие из них будут определены, зависит от списка суффиксов (списка зависимостей специальной цели .SUFFIXES). По умолчанию список суффиксов такой : .out, .a, .ln, .o, .c, .cc, .C, .p, .f, .F, .r, .y, .l, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch, .web, .sh, .elc, .el. Все неявные правила из описанных ниже, чьи зависимости имеют один из этих суффиксов, являются на самом деле суффиксными правилами. Если вы изменяете список суффиксов, то действовать будут только те предопределенные суффиксные правила, имена которых состтоят из одного или двух суффиксов, которые указаны в определенном вами списке - действие правила, чьи суффиксы отсутствуют в списке, отменяется. Смотрите раздел 10.7 [Устаревшие суффиксные правила], где где во всех деталях описаны суффиксные правила.

Компиляция C-программ

'n.o' автоматически порождается из 'n.c' при помощи команды в форме '$(CC) -c $(CPPFLAGS) $(CFLAGS)'.

Компиляция программ на языке C++

'n.o' автоматически порождается из 'n.cc' или 'n.C' при помощи команды в форме '$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)'. Мы рекомендуем вам использовать для исходных файлов, написанных на языке C++, вместо суффикса '.C' суффикс '.cc'.

Компиляция программ на языке Паскаль

'n.o' автоматически порождается из 'n.c' при помощи команды '$(PC) -c $(PFLAGS)'.

Компиляция программ на языках Фортран и Ратфор

'n.o' автоматически порождается из 'n.r', 'n.F' or 'n.f' путем запуска компилятора с языка Фортран. Точный вид у используемой команды следующий:

         '.f'  '$(FC) -c $(FFLAGS)'.   
         '.F'  '$(FC) -c $(FFLAGS) $(CPPFLAGS)'.   
         '.r'  '$(FC) -c $(FFLAGS) $(RFLAGS)'.   
Обработка программ на языках Фортран и Ратфор при помощи препроцессора

'n.f' автоматически порождается из 'n.r' or 'n.F'. Это правило просто запускает препроцессор для преобразования программы на языке Ратфор, представляющей собой подлежащую обработке препроцессором программу на языке Фортран, в программу на языке Фортран в чистом виде. Точный вид у используемой команды следующий:

     '.F'  '$(FC) -F $(CPPFLAGS) $(FFLAGS)'.   
     '.r'  '$(FC) -F $(FFLAGS) $(RFLAGS)'.   
Компиляция программ на языке Модула-2

'n.sym' порождается из 'n.def' при помощи команд в форме '$(M2C) $(M2FLAGS) $(DEFFLAGS)'. 'n.o' порождается 'n.mod', форма команды такая: '$(M2C) $(M2FLAGS) $(MODFLAGS)'.

Ассемблирование и обработка препроцессором программ на языке Ассемблера

'n.o' автоматически порождается из 'n.s' путем запуска ассемблера, программы as. Точный вид команды такой: '$(AS) $(ASFLAGS)'.

'n.s' автоматически порождается из 'n.S' путем запуска препроцессора языка C, программы cpp. Точный вид команды такой: '$(CPP) $(CPPFLAGS)'.

Компоновка одиночного объектного файла

'n' автоматически порождается из 'n.o' путем запуска компоновщика (обычно он называется ld) через C-компилятор. Точный вид у используемой команды такой: '$(CC) $(LDFLAGS) N.o $(LOADLIBES)'.

Это правило правильно работает для простой программы только с одним исходным файлом. Оно также будет правильно работать, если есть несколько объектных файлов (предположительно, получаемых из каких-то дополнительных исходных файлов), один из которых имеет имя, соответствующее имени исполняемого файла. Таким образом, следующее правило:

           x: y.o z.o   
если существуют все из файлов 'x.c', 'y.c' и 'z.c' приведет к исполнению такой последовательности команд:

           cc -c x.c -o x.o   
           cc -c y.c -o y.o   
           cc -c z.c -o z.o   
           cc x.o y.o z.o -o x   
           rm -f x.o   
           rm -f y.o   
           rm -f z.o   
В более сложных случаях, например, при отсутствии объектного файла, имя которого получается из имени исполняемого файла, вы должны написать явную команду для компоновки.

Файл любого вида, для которого предусмотрено автоматическое порождение объектного файла с именем, оканчивающимся на '.o', будет скомпонован с использованием компилятора ('$(CC)', '$(FC)' или '$(PC)', C-компилятор '$(CC)' используется для ассемблерования '.s'-файлов) без опции -c. Это может быть сделано с использованием объектного '.o'-файла в качестве промежуточного, но быстрее сделать компиляцию и компоновку за один шаг, поэтому именно так и делается.

Получение C-программ при помощи программы Yacc

'n.c' автоматически порождается из 'n.y' путем запуска программы Yacc при помощи команды '$(YACC) $(YFLAGS)'.

Получение C-программ при помощи программы Lex

'n.c' автоматически порождается из 'n.l' путем запуска программы Lex. При этом используется такая команда: '$(LEX) $(LFLAGS)'.

Получение программ на языке Ратфор при помощи программы Lex

'n.r' автоматически порождается из 'n.l' путем запуска программы Lex. При этом используется такая команда: '$(LEX) $(LFLAGS)'.

Соглашение об использовании одного и того же суффикса '.l' для всех Lex-файлов, порождают ли они код на языке C или на языке Ратфор делает для программы make невозможным автоматическое определение, какой из двух языков вы используете в каждом конкретном случае. Если программа make вызывается для порождения заново объектного файла из '.l'-файла, она должна выбрать, какой компилятор использовать. Она выберет C-компилятор, поскольку он более популярен. Если вы используете язык Ратфор, сделайте так, чтобы программа make знала об этом, упомянув в make-файле 'n.r'. Или же, если вы используете только Ратфор, без С-файлов, удалите '.c' из списка суффиксов неявных правил, как показано ниже:

           .SUFFIXES:   
           .SUFFIXES: .o .r .f .l ...   
Порождение lint-библиотек из программ на C, Lex и Yacc

'n.ln' порождается из 'n.c' путем запуска программы lint. Точный вид команды такой : '$(LINT) $(LINTFLAGS) $(CPPFLAGS) -i'. Такая же команда используется для работы с C-кодом, полученным из 'n.y' или 'n.l'.

TeX-файлы и Web-файлы

'n.dvi' порождается из 'n.tex' при помощи команды '$(TEX)'. 'n.tex' порождается из 'n.web' при помощи '$(WEAVE)' или из 'n.w' (и из 'n.ch', если он существует или может быть порожден) при помощи '$(CWEAVE)'. 'n.p' порождается из 'n.web' при помощи '$(TANGLE)', а 'n.c' порождается из 'n.w' (и из 'n.ch', если он существует или может быть порожден) при помощи '$(CTANGLE)'.

Texinfo-файлы и Info-файлы

'n.dvi' порождается из 'n.texinfo', 'n.texi' или 'n.txinfo' при помощи команды '$(TEXI2DVI) $(TEXI2DVI_FLAGS)'. 'n.info' порождается из 'n.texinfo', 'n.texi' или 'n.txinfo' при помощи команды '$(MAKEINFO) $(MAKEINFO_FLAGS)'.

RCS-файлы

Любой файл 'n' извлекается, если это необходимо, из RCS-файла с именем либо 'n,v' or 'RCS/n,v'. Точный вид используемой команды такой: '$(CO) $(COFLAGS)'. Если файл 'n' уже существует, то он не будет извлекаться из RCS-файла, даже если RCS-файл является более новым. Правила для RCS-файлов являются терминальными (смотрите раздел 10.5.5 [Шаблонные правила с произвольным соответствием]), поэтому RCS-файлы не могут быть сгенерированы из какого-нибудь еще источника - они должны реально существовать.

SCCS

Любой файл 'n' извлекается, если это необходимо, из SCCS-файла с именем либо 's.n' or 'SCCS/s.n'. Точный вид используемой команды такой: '$(GET) $(GFLAGS)'. Правила для SCCS-файлов являются терминальными (смотрите раздел 10.5.5 [Шаблонные правила с произвольным соответствием]), поэтому SCCS-файлы не могут быть сгенерированы из какого-нибудь еще источника - они должны реально существовать.

Для улучшения использования SCCS, файл 'n' копируется из 'n.sh', и затем делается исполняемым (для всех). Это предназначено для командных файлов, с которыми работает программа SCCS. Так как программа RSC сохраняет права на исполнение файла, вам не требуется использовать эту особенность при работе с RSC.

Мы рекомендуем вам избегать избегать использования програмы SCCS. Программа RCS прочно удерживает ведущее положение и, кроме того, является свободной. Выбирая свободное программное обеспечение вместо аналогичного (или худшего) программного обеспечения, являющегося чьей-либо собственностью, вы поддерживаете развитие свободного программного обеспечения.

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

Однако, команды во встроенных неявных правилах используют, на самом деле, такие переменные, как COMPILE.c, LINK.p и PREPROCESS.S, чьи значения содержат приведенные выше команды.

Программа make следует соглашению, согласно которому правило для компиляции исходного '.x'-файла использует переменную COMPILE.x. Аналогично, правило для порождения исполняемого файла из '.x'-файла использует переменную LINK.x, а правило для обработки '.x'-файла препроцессором использует переменную PREPROCESS.x.

Каждое правило, которое порождает объектный файл, использует переменную OUTPUT_OPTION. Программа в make определяет эту переменную либо как содержащую значение '-o $@ ', либо как пустую, в зависимости от требуемой в период компиляции опции. Опция '-o' нужна вам для того, чтобы гарантировать, что выход идет в правильный файл, когда исходный файл находится в другом каталоге, как это бывает при использовании переменной VPATH (смотрите раздел 4.3 [Поиск по каталогам]). Однако, компиляторы на некоторых системах не воспринимают опцию '-o' для объектных файлов. Если вы используете такую систему и используете переменную VPATH, в некоторых сеансах компиляции выход будет помещен в не туда, куда надо. Возможный обход этой проблемы заключается в присваивании переменной OUTPUT_OPTION значения '; mv $*.o $@ '.

10.3 Переменные, используемые неявными правилами

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

Например, команда, используемая для компиляции исходного C-файла в действительности выглядит так: '$(CC) -c $(CFLAGS) $(CPPFLAGS)'. По умолчанию значение перененной CC является 'cc', значениями остальных используемых здесь переменных является пустое значение, в результате чего получается команда 'cc -c'. С помощью переопределения переменной CC в значение 'ncc' вы могли бы сделать так, чтобы для всех C-компиляций, выполняемых в результате работы неявных правил, мспользовался компилятор 'ncc'. С помощью переопределения переменной CFLAGS в значение '-g', вы могли бы передать в каждом сеансе компиляции опцию '-g'. Все неявные правила, выполняющие C-компиляцию, используют ссылку на переменную '$(CC)' для определения имени программы- компилятора, и все они среди аргументов , передаваемых компилятору, содержат ссылку на переменную '$(CFLAGS)'.

Переменные, используемые в неявных правилах, разделяются на два класса: переменные, являющиеся именами программ (такие, как CC) и переменные, содержащие аргументы для программы (такие, как CFLAGS). ("Имя программы" может также содержать некоторые аргументы командной строки, но оно должно начинаться с имени реальной исполняемой программы.) Если значение переменной содержит более, чем один аргумент, разделяйте их при помощи пробелов.

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

AR

Поддерживающая архивы программа, по умолчанию 'ar'.

AS

Программа для выполнения ассемблирования, по умолчанию 'as'.

CC

Программа для компиляции C-программ, по умолчанию 'cc'.

CXX

Программа для компиляции программ на языке C++, по умолчанию 'g++'.

CO

Программа для извлечения файлов из RCS, по умолчанию 'co'.

CPP

Программа для запуска C-препроцессора, с выдачей результатов на стандартный выход, по умолчанию '$(CC) -E'.

FC

Программа для компиляции или обработки препроцессором программ на языке Фортран или Ратфор, по умолчанию 'f77'.

GET

Программа для извлечения файлов из SCCS, по умолчанию 'get'.

LEX

Программа, используемая для преобразования Lex-грамматик в программы на языке C или Ратфор, по умолчанию 'lex'.

PC

Программа для компиляции программ на языке Паскаль, по умолчанию 'pc'.

YACC

Программа, используемая для преобразования Yacc-грамматик в C-программы, по умолчанию 'yacc'.

YACCR

Программа, используемая для преобразования Yacc-грамматик в программы на языке Ратфор, по умолчанию 'yacc -r'.

MAKEINFO

Программа для проеобразования исходного Texinfo-файла в Info-файл, по умолчанию 'makeinfo'.

TEX

Программа для создания dvi-файлов из исходных Тех-файлов, по умолчанию 'tex'.

TEXI2DVI

Программа для создания dvi-файлов из исходных Texinfo-файлов, по умолчанию 'texi2dvi'.

WEAVE

Программа для перевода из Web-формата в TeX-формат, по умолчанию 'weave'.

CWEAVE

Программа для перевода из C-Web-формата в TeX-формат, по умолчанию 'cweave'.

TANGLE

Программа для перевода из Web-формата в программу на языке Паскаль, по умолчанию 'tangle'.

CTANGLE

Программа для перевода из Web-формата в C-программу, по умолчанию 'tangle'.

RM

Команда для удаления файла, по умолчанию 'rm -f'.

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

ARFLAGS

Опции, передаваемые поддердивающей архивы программе, по умолчанию 'rv'.

ASFLAGS

Дополнительные опции, передаваемые ассемблеру ( когда он явно вызывается для файла, имя которого оканчивается на '.s' или '.S').

CFLAGS

Дополнительные опции, передаваемые C-компилятору.

CXXFLAGS

Дополнительные опции, передаваемые компилятору с языка C++.

COFLAGS

Дополнительные опции, передаваемые программе co, входящей в систему RCS.

CPPFLAGS

Дополнительные опции, передаваемые C-препроцессору и программам, которые его используют (компиляторам с языков C и Фортран).

FFLAGS

Дополниттельные опции, передаваемые компилятору с языка Фортран.

GFLAGS

Дополнительные опции, передаваемые программе get, входящей в систему SCCS.

LDFLAGS

Дополнительные параметры, передаваемые компиляторам, когда преполагается вызов из них компоновщика, 'ld'.

LFLAGS

Дополнительные опции, передаваемые программе Lex.

PFLAGS

Дополнительные опции, передаваемые компилятору с языка Паскаль.

RFLAGS

Дополнительные опции, передаваемые компилятору с языка Фортран для использования с программами на языке Ратфор.

YFLAGS

Дополнительные опции, передаваемые программе Yacc.

10.4 Цепочки неявных правил

Иногда файл может быть порожден с помощью последовательности неявных правил. Например, файл 'n.o' мог бы быть порожден из 'n.y' запуском сначала программы Yacc, а затем cc. Такая последовательность называется цепочкой.

Если файл 'n.c' существует или упоминается в make-файле, то не требуется никакого специального поиска: программа make узнает, что объектный файл может быть порожден при помощи C-компиляции из 'n.c', затем, при определении того, как породить файл 'n.c', используется правило для запуска программы Yacc. В конечном счете, как 'n.c', так и 'n.o' становятся обновленными.

Однако, даже если файл 'n.c' не существует и не упоминается в make-файле, программа make способна разглядеть в нем отсутствующую связь между файлами 'N.o' и 'N.y'! В этом случае 'n.c' называется "промежуточным файлом". Как только программа make решила использовать промежуточный файл, он вводится в базу данных, как если бы он был упомянут в make-файле, вместе с неявным правилом, которое указывает, как его создавать.

Порождение заново промежуточных файлов происходит с использованием соответствующих им правил точно также как и всех других файлов. Различие заключается в том, что при завершении программы make промежуточный файл удаляется. Следовательно, промежуточный файл, который не существовал перед началом работы программы make, также не существует и после окончания ее работы. Об удалении вам сообщается при помощи вывода на экран команды 'rm -f', которая показывает, что делает программа make. (Вы можете указать шаблон цели неявного правила (например, '%.o') в качестве зависимости специальной цели '.PRECIOUS', чтобы предохранить от удаления промежуточные файлы, порождаемые неявными правилами с шаблонами цели, соответствующими указанному шаблону; смотрите раздел 5.5 [Прерывания].)

Цепочка может включать в себя более, чем два неявных правила. Например, в возможно порождение файла 'foo' из файла 'RCS/foo.y,v' посредством запуска программ RCS, Yacc и cc. В таком случае файлы 'foo.y' и 'foo.c', как один, так и другой, являются промежуточными файлами, которые в конечном счете удаляются.

Никакое отдельное неявное правило не может появляться в цепочке неоднократно. Это означает, что программа make даже не станет рассматривать такую нелепость, как порождение файла 'foo' из файла 'foo.o.o' с помощью выполнения компоновщика дважды. Это ограничение несет с собой дополнительную пользу, заключающуюся в предотвращении возникновения какого-либо бесконечного цикла во время поиска цепочки неявных правил.

Существуют некоторые специальные неявные правила, предназначенные для оптимизации работы в некоторых ситуациях, которые в противном случае обрабатывались бы с помощью цепочек правил. Например, порождение файла 'foo' из файла 'foo.c' могло бы обрабатываться с помощью компиляции и компоновки, выполняющихся в рамках отдельных связанных в цепочку правил, с использованием 'foo.c' в качестве промежуточного файла. Но на самом деле суть происходящего заключается в том, что специальное правило для этого случая выполняет компиляцию и компоновку при помощи одной команды cc. Использование оптимизированного правила дает преимущество перед использованием пошаговой цепочки поскольку нем ускоряется выполнение правил.

10.5 Определение и переопределение шаблонных правил

Вы определяете неявное правило с помощью записи шаблонного правила. Шаблонное правило похоже на обычное правило, за исключением того, что его цель содержит символ '%' (ровно один). Цель рассматривается как шаблон для сопоставления с ним имен файлов - символу '%' может соответствовать любая непустая подстрока, в то время как любому другому символу соответствует только он сам. Зависимости также используют символ '%', чтобы показать как их имена соотносятся с именем цели.

Таким образом, шаблонное правило '%.o : %.c' указывает программе make, как на породить любой файл с именем вида 'stem.o' из другого файла, с именем вида 'stem.c'.

Обратите внимание, что в шаблонных правилах подстановка значения, соответствующего символу '%' происходит после подстановки значений всех переменных и функций, что имеет место при чтении make-файла. Смотрите главу 8 [Функции преобразования текста].

Введение в шаблонные правила

Шаблонное правило содержит в цели символ '%' (ровно один), в остальном он выглядит точно также, как и обычное правило. Цель представляет собой шаблон, для сопоставления с именами файлов, символ '%' сопоставляется с любой непустой подстрокой, в то время как любые другие символы сопоставляются только сами себе.

Например, если рассматривать в качестве шаблона '%.c', то с ним сопоставляется любое имя файла, которое заканчивается в '.c'. Если рассматривать в качестве шаблона 's.%.c', то с ним сопоставляется любое имя файла, которое начинается на 's.', заканчивается в '.c' и занимает, по меньшей иере, пять символов в длину. (В подстроке должен быть, по крайней мере, один символом, для того, чтобы ее можно было сопоставить символу '%'.) Подстрока, которая сопоставляется символу '%', называется основой.

Символ '%' в зависимости шаблонного правила употребляется для обозначения той же самой основы, которая была сопоставлена символу '%' в цели. Для применения шаблонного правила, его шаблону цели должно быть сопоставлено обрабатываемое имя файла, в результате чего его шаблоны зависимостей должны превратиться в имена файлов, которые существуют или могут быть порождены. Эти файлы становятся зависимостями цели.

Таким образом, правило в такого вида:

      %.o : %.c ; КОМАНДА...   
определяет, как породить файл 'n.o' с использованием другого файла, 'n.c', в качестве его зависимости, в предположении, что 'n.c' существует или может быть порожден.

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

Там может также быть зависимостями, которые не используют '%' - такая зависимость присоединяет к каждому файлу, делаемому этим правилом образца. Такие неизменяемые зависимости время от времени являются полезными.

Шаблонному правилу необязательно иметь какие-либо зависимости, которые содержат символ '%', более того, фактически, необязательно иметь какие-либо зависимости вообще. Такое правило, по сути, является общим шаблоном. Оно обеспечивает способ для порождения любого файла, который сопоставляется шаблону цели. Смотрите раздел 10.6 [Определение правил последней возможности, используемых по умолчанию].

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

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

Примеры шаблонных правил

Вот некоторые примеры шаблонных правил, на самом деле являющихся предопределенными программой make. Сначала рассмотрим правило, которое компилирует '.c'-файлы в '.o'-файлы:

      %.o : %.c   
              $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@         
Приведенный фрагмент make-файла определяет правило, которое может породить любой файл 'x.o' из файла 'x.c'. Команда использует автоматические переменные '$@ ' и '$<', которые на место которых каждый раз при применении правила подставляются, соответственно, имена целевого и исходного файлов.

Вот второе встроенное правило:

      % :: RCS/%,v   
              $(СО) $(СОФЛАГИ) $<   
Здесь определяется правило, которое может породить произвольный файл 'x' из соответствующего файла 'x,v' в подкаталоге 'RCS'. Поскольку целью является '%', это правило применится к любому файлу, при условии, что соответствующий файл зависимости существует. Двойное двоеточие делает правило терминальным, и это означает, что его зависимость не может быть промежуточным файлом (смотрите раздел 10.5.5 [Шаблонные правила с произвольным соответствием]).

Следующее шаблонное правило имеет две цели:

      %.tab.c %.tab.h: %.y   
              bison -d $<   
Это указывает программе make на то, что команда 'bison -d X.y' будет порождать как файл 'x.tab.c' так и файл 'x.tab.h'. Если файл 'foo' зависит от файлов 'parse.tab.o' и 'scan.o', а файл 'scan.o' зависит от файла 'parse.tab.h', то при изменении файла 'parse.y' изменяется, команда 'bison -d parse.y' будет выполнена только один раз, в результате чего будут обновлены зависимости, как файла 'parse.tab.o', так и файла 'scan.o'. (Предполагается, файл 'parse.tab.o' будет перекомпилироваться из файла 'parse.tab', а файл'scan.o' - из 'scan.c', в то время как файл 'foo' компонуется из файлов 'parse.tab.o', 'scan.o', и других его зависимостей, и после этого он будет всегда счастливо выполняться.)

Автоматические переменные

Предположим, что вы записываете шаблонное правило для скомпиляции '.c'-файла в '.o'-файл: как вы напишите команду 'cc', чтобы она работала с правильным именем исходного файла? Вы не можете записать имя в команде, поскольку это имя разное при каждом использовании неявного правила.

То, что вам следует делать - это использовать специальную возможность программы make, автоматические переменные. Эти переменные имеют значения, заново вычисленные для каждого выполняемого правила на основе цели и зависимостей правила. В данном примере, вы бы использовали переменную '$@ ' для имени объектного файла и переменную '$<' для имени исходного файла.

Вот список автоматических переменных:

`$@'

Имя файла цели правила. Если целью является элемент архива, то '$@' - имя файла архива. В шаблонном правиле с несколькими целями (смотрите раздел 10.5.1 [Введение в шаблонные правила]), '$@' - имя той цели, которая вызвала выполнение команд правила.

`$%'

Имя элемента цели, в том случае, когда цель - элемент архива. Смотрите главу 11 [Элементы архива в качестве целей]. Например, если целью является - 'foo.a(bar.o)', то значение переменной '$%' - 'bar.o', а переменной '$@ ' - 'foo.a'. Переменная '$%' имеет пустое значение, когда цель не -элемент архива.

`$<' Имя первой зависимости. Если цель получила свои команды из

неявного правила, то это будет первая зависимость, добавленная неявным правилом (смотрите главу 10 [Использование неявных правил].).

`$?' Имена всех зависимостей, которые являются более новыми, чем

цель, с пробелами между ними. Для зависимостей, которые являются элементами архива, используются только имя элемента (смотрите главу 11 [Архивы].).

`$^' Имена всех зависимостей, с пробелами между ими. Для

зависимостей, которые являются элементами архива, используются только имя элемента (смотрите главу 11 [Архивы].). Цель имеет только одну зависимость для каждого файла, от которого он зависит от, независимо от того, сколько раз каждый файл указан в качестве зависимости. Таким образом, если вы для цели неоднократно укажете одну и ту же зависимость, значение переменной '$^' будет содержать только одну копию ее имени.

`$+' Эта переменная аналогична переменной '$^', только зависимости,

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

`$*' Основа с которой сопоставляется неявное правило (смотрите раздел

10.5.4 [Как определяется соответствие шаблону]). Если целью является файл 'dir/a.foo.b', а шаблон цели - 'a.%.b', то основой будет 'dir/foo'. Основа полезна для создания имен файлов, связанных с правилом.

В статическом шаблонном правиле основа представляет собой часть имени файла, которая сопоставляется символу '%' в шаблоне цели.

В явном правиле основы нет, поэтому в этом случае переменная '$*' не может иметь определенного значения. Вместо этого, если имя цели оканчивается распознаваемым суффиксом (смотрите раздел 10.7 [Устаревшие суффиксные правила]), то в качестве значения переменной '$*' устанавливается имя цели без суффикса. Например, если имя цели - 'foo.c', то в качестве значения переменной '$*' устанавливается 'foo, так как '.c' - суффикс. GNU-версия программы make делать эту причудливую вещь только для совместимости с другими реализациями программы make. Вам, вообще говоря, следует избегать использования переменной '$*', за исключением неявных правил или статических шаблоных правил.

Если имя цели в явном правиле не оканчивается распознаваемым суффиксом, то для этого правила в качестве значения переменной '$*' устанавливается пустая строка.

Переменная '$?' полезна даже в явных правилах, когда вы хотите работать только с зависимостями, которые были изменены. Например, предположим, что архив с именем 'lib' предназначен для хранения копий нескольких объектных файлов. Приведенное ниже правило копирует в архив только измененные объектные файлы:

      lib: foo.o bar.o lose.o win.o ar   
              r lib $?   
Из переменных, перечисленных выше, четыре имеют значения, являющиеся одиночными именами файлов, а две имеют значения, которые представляют собой списки имен файлов. Эти шесть переменных имеют возможности получить а качестве значения только имя каталога из полного имени файла или только само имя файла в пределах каталога. Вариант имени переменной определяется путем добавления, соответственно, 'D' или 'F'. Эти варианты в GNU-версии программы make являются полуустаревшими, поскольку для получения аналогичного эффекта могут использоваться функции dir и notdir (смотрите раздел 8.3 [Функции для обработки имен файлов]). Тем не менее, обратите внимание, что при использовании всех вариантов с буквой 'D', конечный символ '/', который всегда появляется в качестве результата функции dir , опускается. Ниже приводится список вариантов:
'$(@D)'

Часть имени файла цели, определяющая каталог, с удаленным конечным символом '/'. Если значением переменной '$@' является 'dir/foo.o', то значением переменной '$(@D)' является 'dir'. Этим значением является '.', если значение переменной '$@' не содержит символа '/'.

'$(@F)'

Часть имени файла цели, определяющая файл внутри каталога. Если значением переменной '$@' является 'dir/foo.o', то значением переменной '$(@F)' является 'foo.c'. Переменная '$(@F)' эквивалентна вызову функции '$(@)'.

'$(*D)'

'$(*F)'

Часть основы, определяющая, соответственно, каталог и файл внутри каталога - 'dir' и 'foo' в этом примере.

'$(%D)'

'$(%F)'

Часть имени целевого элемента архива, определяющая, соответственно, каталог и файл внутри каталога. Это имеет смысл только для целей, являющихся элементами архива, и имеющих форму 'АРХИВ(ЭЛЕМЕНТ)', и полезно только когда ЭЛЕМЕНТ может содержать имя каталога. (Смотрите раздел 11.1 [Элементы архива в качестве целей].)

'$(<D)'

'$(<F)'

Часть имени первой зависимости, определяющая, соответственно, каталог и файл внутри каталога.

'$(^D)'

'$(^F)'

Списки частей имен всех зависимостей, определяющих, соответственно, каталоги и файлы внутри каталогов.

'$(?D)'

'$(?F)'

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

Обратите внимание, что мы, когда говорим об этих автоматических переменных, используем специальные стилистические соглашения. Мы пишем "значение переменной '$<'", а не "переменная '<'", как мы написали бы для обычных переменных, таких, как objects и CFLAGS. Мы думаем, в данном случае это соглашение выглядит более естественным. Не стоит полагать, что это имеет глубокое значение - ссылка '$<' ссылается на переменную с именем '<', точно так же, как ссылка '$(CFLAGS)' ссылается на переменную с именем 'CFLAGS'. Вы могли бы точно так же использовать запись '$(<)' вместо `$<'.

Как определяется соответствие шаблону

Шаблон цели состоит из символа '%', заключенного между префиксом и суффиксом, один из которых или оба сразу могут быть пустыми. Имя файла сопоставимо с шаблоном только в том случае, если оно начинается с указанного префикса и заканчивается указанным суффиксом, без перекрытия. Фрагмент текста, расположенный между префиксом и суффиксом, называется основой. Таким образом, если образцу '%.o' сопоставляется имя файла 'test.o', то основой является 'test'. Зависимости шаблонного правила преобразуются в реальные имена файлов путем замены символа '%' на основу. Таким образом, если в этом же примере одна из зависимостей записана в виде '%.c', она преобразуется в 'test.c'.

Когда шаблон цели не содержит символа '/' (а обычно он его не содержит), из имени файла убирется часть, определяющая имена каталогов, прежде, чем это имя будет сравниваться с префиксом и суффиксом цели. После сравнения имени файла с шаблоном цели, имена каталогов, вместе с символом '/', которым они заканчиваются, добавляются к именам файлов зависимостей, сгенерированных из шаблонов зависимости шаблонного правила и к имени целевого файла. Директории игнорируются только для того, чтобы обнаружить неявное правило, которое надо использовать, а не при применении этого правила. Таким образом, шаблону 'e%t' сопоставляется имя файла 'src/eat', с основой 'src/a'. Когда зависимости преобразуются в имена файлов, часть основы, определябщая катологи, добавляется в их начало, в то время как оставшаяся часть основы подставляется на место символа '%'. Основа 'src/a' в применении к шаблону зависимости 'c%r' дает имя файла 'src/car'.

Шаблонные правила с произвольным соответствием

Когда целью шаблонного правила является просто символ '%', то с ним сопоставляется произволное имя файла. Мы вызываем такие правила правилами с произвольным соответствием. Они очень полезны, но их обработка может занять у программы make много времени, поскольку она должна обработать каждое такое правило для каждого имени файла, указанного или как цель, или как зависимость.

Допустим, в make-файле упоминается файл 'foo.c'. Для обработки этой цели, программа make должна рассмотреть получение его при помощи компоновки объектного файла 'foo.c.o', или же, при помощи C-компиляции и компоновки, выполняемых за один шаг, из файла 'foo.c.c', или же, при помощи компиляции и компоновки программы на языке Паскаль, из файла 'foo.c.p', а также много других возможностей.

Мы знаем, что эти возможности являются нелепыми, поскольку 'foo.c' представляет собой не исполняемый, исходный C-файл. Если бы программа make рассматривала эти возможности, она в конце концов отвергла бы их, поскольку такие файлы, как 'foo.c.o' и 'foo.c.p' не существовали бы. Но эти возможности настолько многочисленны, что программа make работала бы очень медленно, если бы ей требовалось их рассматривать.

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

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

Например, встроенные неявные правила для извлечения исходных файллв из RCS-файлов и SCCS-файлов являются терминальными - в результате, если файл 'foo.c,v' не существует, программа make даже не рассмотрит попытку породить его, как промежуточный файл, из файла 'foo.c,v.o' или из файла 'RCS/SCCS/s.foo.c,v'. RCS-файлы и SCCS-файлы обычно являются окончательными исходными файлами, которые не должны быть заново порожденными из любых других файлов, следовательно, программа make может сберечь время, не занимаясь поисками пути для того, чтобы заново породить их.

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

Например, имя файла 'foo.c' сопоставляется с целью шаблонного правила '%.c : %.y' (правило для выполнения программы Yacc). Независимо от того, применимо ли на самом деле это правило (что имеет место только в том случае, когда есть файл 'foo.y'), того факта, что имеется соответствие с его целью, достаточно для того, чтобы предотвратить рассмотрение любых нетерминальных правил с произвольным соответствием для файла 'foo.c'. Таким образом, программа make даже не рассмотрит попытку породить файл 'foo.c', как исполняемый файл, из файлов 'foo.c.o', 'foo.c.c', 'foo.c.p', и т.п..

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

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

%.p:

существует для того, чтобы гарантировать, что исходные файлы на языке Паскаль, как, например, 'foo.p', сопоставляются с определенным шаблоном цели и, тем самым, предотвратить трату времени на поиск файла 'foo.p.o' или файла 'foo.p.c'.

Шаблонные правила-заглушки, такие как правило для '%.p' порождаются для всех суффиксов, указанных как имеющие силу для использования в суффиксных правилах (смотрите раздел 10.7 [Устаревшие суффиксные правила]).

Отмена действия неявных правил

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

Вы можете отменить действие встроенного неявного правила, определив шаблонное правило с той же самой целью, но без команд. Например, следующий фрагмент make-файла отменит правило, которое запускает ассемблер:

%.o : %.s

10.6 Определение правил последней возможности, используемых по умолчанию

Вы можете определить неявное правило последней возможности с помощью написания терминального шаблонного правила с произвольным соответствием без зависимостей (смотрите раздел 10.5.5 [Шаблонные правила с произвольным соответствием]). Оно во всем аналогично любому другому шаблонному правилу, единственное, что специфично для него - это то, что с ним будет сопоставляться любая цель. Таким образом, команды такого правила используются для всех целей и зависимостей, которые не имеют своих собственных команд и к которым неприменимо ни одно другое неявное правило.

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

      %::   
              touch $@         
что привело бы к тому, что все требуемые (как зависимости) файлы были созданы автоматически.

Кроме того, вы можете определить команды, которые будут использованы для целей, у которых совсем нет правил, даже тех, которые не определяют команды. Это делается при помощи правила для цели .DEFAULT. Команды этого правила используются для всех зависимостей, которые не появляются в роли целей ни в одном явном правиле, и для которых неприменимо ни одно неявное правило. Естественно, правила для цели .DEFAULT не будет, если вы не его не напишете.

Если вы используете .DEFAULT без команд и зависимостей, как показано ниже:

      .DEFAULT:   
то команды, ранее запомненные как соответствующие цели .DEFAULT , очищаются. После этого программа make действует так, как будто вы совсем никогда не определяли правило для цели .DEFAULT.

Если вы не хотите, чтобы цель получала команды из шаблонного правила с произвольным соответствием и из правила для цели .DEFAULT, но при этом вы не хотите, чтобы для этой цели запускалась какая-либо команда, вы можете определить для нее пустую команду (смотрите раздел 5.8 [Определение пустых команд]).

Вы можете использовать правило последней возможности для перекрытия части другого make-файла. Смотрите раздел 3.6 [Перекрытие части другого make-файла].

10.7 Устаревшие суффиксные правила

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

Правило двойного суффикса определяется парой суффиксов: суффикс цели и суффикс исходного файла. Этому правилу соответствует любой файл, имя которого заканчивается на суффикс цели. Соответствующая неявная зависимость строится путем замены в имени файла суффикса цели на суффикс исходного файла. Двухсуффиксное правило, суффикс цели и суффикс исходного файла которого представляют собой, соответственно, '.o' и '.c', эквивалентно шаблонному правилу '%.o : %.c'.

Правило одиночного суффикса определяется одиночным суффиксом, который представляет собой суффикс исходного файла. Этому правилу соответствует любое имя файла, а соответствующее имя неявной зависимости создается путем добавления суффикс исходного файла. Правило одиночного суффикса, исходным суффиксом которого является '.c', эквивалентно шаблонному правилу '% : %.c'.

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

Например, как '.c', так и '.o' по умолчанию находятся в списке известных суффиксов. Следовательно, если Вв определяете правило, целью которого является '.c.o', то программа make принимает его как правило двойного суффикса с суффиксом исходного файла '.c' и суффиксом цели '.o'. Ниже приведен устаревший способ для опредения правило для компиляции исходного C-файла:

      .c.o:   
              $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@       $<   
Суффиксные правила не могут иметь никаких собственных зависимостей. Если у них есть хоть одна зависимость, они обрабатываются как обычные файлы со странными именами, а не как суффиксные правила. Таким образом, приведенное ниже правило правило:

      .c.o: foo.h $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@       $<   
говорит о том, как породить файл '.c.o' из файла зависимости 'foo.h', что совсем не похоже на шаблонное правило:

      %.o: %.c foo.h $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@       $<   
которое, говорит о том, как порождать '.o'-файлы из '.c'-файлов, при этом порождения любых '.o'-файлов с использованием этого шаблонного правила также зависят от 'foo.h'.

Суффиксные правила без команд также не имеют смысла. Они не отменяют действия предыдущих правил, что делают шаблонные правила без команд (смотрите раздел 10.5.6 [Отмена действия неявных правил]). Они просто вводят в базу данных в качестве цели суффикс или пару конкатенированных суффиксов.

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

      .SUFFIXES: .hack .win   
где в конец списка суффиксов добавляются '.hack' и '.win'.

Если вы хотите убрать известные по умолчанию суффиксы, а не просто добатить к ним новые, напишите для цели .SUFFIXES правило без зависимостей. Это специально обрабатывается как удаление всех существующих зависимостей цели .SUFFIXES. После этого вы можете написать еще одно правило для добавления тех суффиксов, которые вы хотите добавить. Например,

      .SUFFIXES:                 # Удаляет суффиксы по умолчанию   
      .SUFFIXES: .c .o .h        # Определяет новый список суффиксов   
Опция '-r' или '--no-builtin-rules' опустошвет список суффиксов по умолчанию.

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

10.8 Алгоритм поиска неявного правила

Здесь приведена последовательность действий, которую использует программа make при поиске неявного правила для цели t. Эта последовательность действий вступает в действие для каждого правила с двойным двоеточием, у которого нет команд, для каждой цели из обычных правил, ни одно из которых не имеет команд и для каждой зависимости, которая не является целью никакого правила. Кроме того, программа make рекурсивно следует этой последовательности действий при обработке зависимостей, которые происходят из неявных правил, в ходе поиска цепочки правил.

Суффиксные правила не упоминаются в этом алгоритме, поскольку суффиксные правила преобразуются в эквивалентные шаблонные правила, как только программа make считывает их.

Для цели, являющейся элементом архива и представленной в форме 'АРХИВ(ЭЛЕМЕНТ)', данный алгоритм выполняется дважды, сначала с использованием полного имени цели t, а затем с использованием на месте цели t '(ЭЛЕМЕНТА)', если в первом проходе не было найдено ни одного правила.

  1. Цель t делится на часть, определяющую каталог, называемую d, и остаток, называемый n. Например, если t - это 'src/foo.o', то d - это 'src/', а n - это 'foo.o'.
  2. Создается список всех шаблонных правил, с одной из целей которых сопоставимо t или n. Если шаблон цели содержит символ '/', то он проверяется на соответствие с t, в противном случае - с n.
  3. Если хотя бы одно из правил в этом списке не является правилом с произвольным соответствием, то все нетерминальные правила с произвольным соответствием удаляются из списка.
  4. Все правила без команд удаляются из списка.
  5. Для каждого шаблонного правила из списка:
    1. Ищется основа s, которая представляет собой непустую часть t или n, которую можно сопоставить с символом '%' в шаблоне цели.
    2. Вычисляются имена зависимостей путем подстановки основы s на место символа '%'; если шаблон цели не содержит символа '/', в начало каждого имени зависимости добавляется d.
    3. Проверяется, существуют ли все зависимости или должны ли они существовать. (Если имя файла упоминается в make-файле в качестве цели или в качестве явной зависимости, то мы говорим, что он должен существовать.)

      Если все зависимости существуют или должны существовать, или же зависимостей нет, то это правило применяется.

  6. Если до сих пор не было найдено ни одного шаблонного правила, то производится более сильная попытка поиска. Для каждого шаблонного правила из списка:
  7. Если ни одно неявное правило не применимо, то применяется правило для цели .DEFAULT, если оно есть. В этом случае, цели t передаются те же самые команды, которые есть у цели .DEFAULT. В противном случае, команд для цели t нет.

Как только находится применимое правило, для каждого шаблона цели, отличного от шаблона, которому соответствует t или n, каждое вхождение в шаблон символа '%' заменяется на основу s, и полученное имя файла запоминается до тех пор, пока не будут выполняться команды для порождения заново целевого файла t. После того, как эти команды выполнятся, каждый из тех запомненных имен файлов вводится в базу данных и помечается как обновленный и имеющий такое же время обновления, как и файл t.

Когда для обновления цели t выполняются команды шаблонного правила, автоматические переменные устанавливаются в соответствие с целью и зависимостями. Смотрите раздел 10.5.3 [Автоматические переменные].


Вперед Назад Содержание
Вперед Назад Содержание

11. Использование make для обновления архивных файлов

Архивные файлы представляют собой файлы, содержащие именованные подфайлы, называемые элементами; они обрабатываются с помощью программы ar и основное их использование - в качестве библиотек подпрограмм для компоновки.

11.1 Элементы архивов в качестве целей

Отдельный элемент архивированного файла может использоваться р программе make в качестве цели или зависимости. Вы указываете элемент с именем ЭЛЕМЕНТ в архивном файле с именем АРХИВ следующим образом:

      АРХИВ(ЭЛЕМЕНТ)   
Эта структура доступна только в целях и зависимостях, но не в командах! Большинство программ, которые вы можете использовать в командах не поддерживают этот синтаксис и не могут работать непосредственно с элементами архивов. Только программа ar и другие программы, специально созданные для работы с архивами, могут это сделать. Следовательно, корректные команды для обновления цели, являющейся элементом архива, вероятно, должны использовать программу ar. Например, приведенное ниже правило указывает создать в архиве 'foolib' элемент 'hack.o' путем копирования файла 'hack.o':

      foolib(hack.o) : hack.o ar   
              cr foolib hack.o   
Фактически, почти все цели, являющиеся элементами архивов, обновляются только таким способом и существует неявное правило, которое делает это за вас. Примечание: программе ar требуется опция 'c', если архивный файл еще не существует.

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

      foolib(hack.o kludge.o)   
эквивалентен такому фрагменту:

      foolib(hack.o) foolib(kludge.o)   
Вы можете также при ссылке на элемент архива использовать шаблоны в стиле командной оболочки. Смотрите раздел 4.2 [Использование шаблонных символов в именах файлов]. Например, 'foolib(*.o)' преобразуется в список всех существующих элементов архива 'foolib', имена которых заканчиваются на '.o', возможно, это будет такой список: 'foolib(hack.o) foolib(kludge.o)'.

11.2 Неявные правила для целей, являющихся элементами архивов

Напомним, что цель, представленная в виде 'a(m)', означает элемент архивного файла a с именем m.

Когда программа make ищет неявное правило для такой цели, в качестве специальной возможности, он рассматривает неявные правила, с которыми сопоставляется '(m)', наравне с теми правилами, с которыми сопоставляется настоящая цель 'a()'.

Это приводит к сопоставлению с одним специальным правилом, целью которого является '(%)'. Это правило обновляет цель 'a()' с помощью копирования в архив файла m. Например, он обновит цель 'foo.a(bar.o)', являющуюся элементом архива с помощью копирования в архив 'foo.a', в качестве элемента с именем 'bar.o', файла 'bar.o'.

Когда это правило, объединяется в цепочку с другими, это приводит к очень мощному результату. Так, команды 'make "foo.a(bar.o)"' (кавычки необходимы для того, чтобы защитить символы '(' и ')' от специальной интерпретации со стороны командной оболочки), при наличии файла 'bar.c', достаточно для того, чтобы, даже без make-файла, привести к выполнению следующих команд:

      cc -c bar.c -o bar.o ar   
      r foo.a bar.o rm -f   
      bar.o   
В данном случае программа make увидела в файле 'bar.o' промежуточный файл. Смотрите раздел 10.4 [Цепочки неявных правил].

Неявные правила, как, например, рассмотренное, пишутся с использованием автоматической переменной '$%'. Смотрите раздел 10.5.3 [Автоматические Переменные].

В архиве имя элемента архива не может содержать имени каталога, но в make-файле может быть полезным сделать вид, что оно может это делать. Если вы указываете элемент 'foo.a(dir/file.o)' , являющийся элементом архива, то программа make выполнит автоматическое обновление с помощью такой команды:

      ar r foo.a dir/file.o   
действия которой состоят в копировании файла 'dir/file.o' элемент архива с именем 'file.o'. При таком использовании, могут быть полезными автоматические переменные '%D' и 'F'.

Обновление символьных каталогов архивов

Архивный файл, используемый в качестве библиотеки, обычно содержит специальный элемент с именем '__.SYMDEF', который содержит каталог внешних имен символов, определенных всеми другими элементами архива. После того, как вы обновите любые другие элементы архива, вам потребуется обновить '__.SYMDEF', для того, чтобы он содержал корректную суммарную информацию о других элементах архива. Это делается посредством запуска программы ranlib:

      ranlib АРХИВНЫЙ_ФАЙЛ   
Обычно вам следует установить эту команду в правило для архивного файла и сделать все элементы архивного файла зависимостями этого правила. Например,

      libfoo.a: libfoo.a(x.o) libfoo.a(y.o)...   
              ranlib libfoo.a   
Действие этого правила заключается в обновлении элементов архива 'x.o', 'y.o', и т.п., и последующем обновлении элемента '__.SYMDEF', являющегося символьным каталогом, посредством запуска программы ranlib. Правила для обновления элементов здесь не показаны - вероятнее всего, вы можете опустить их и использовать неявное правило, которое копирует файлы в архив, как описано в предыдущем разделе.

Это не является необходимым при использовании GNU-версии программы ar, которая обновляет элемент '__.SYMDEF' автоматически.

11.3 Опасности при использовании архивов

Важно быть внимательным при использовании параллельного выполнения (опция -j, смотрите раздел 5.3 [Параллельное выполнение]) и архивов. Если одновременно запускаются несколько команд ar, работающие с одним и тем же архивным файлом, они не будут знать друг о друге и могут повредить файл.

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

11.4 Суффиксные правила для архивных файлов

Вы можете написать суффиксное правило специального вида, которое бы имело дело с архивными файлами. Смотрите раздел 10.7 [Суффиксные правила], где в полной мере объясняются суффиксные правила. Архивные суффиксные правила являются устаревшими GNU-версии программы make, поскольку шаблонные правила для архивов представляют собой более общий механизм (смотрите раздел 11.2 [Обновление архивов]). Тем не менее, они сохранены для совместимости с другими версиями программы make.

Для того, чтобы написать суффиксное правило для архивов, вы просто пишете суффиксное правило с использованием суффикса цели '.a' (обычный суффикс для архивных файлов). Например, ниже привкдкно устаревшее суффиксное правило для обновления библиотечного архива из исходных C-файлов:

      .c.a:   
              $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o $(AR)   
              r $@ $*.o $(RM) $*.o   
Этот фрагмент make-файла работает точно так же, как если бы вы написали такое шаблонное правило:

      (%.o): %.c $(CC)   
              $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o $(AR) r   
              $@       $*.o $(RM) $*.o   
Фактически, здесь просто показано то, что делает программа make, когда она видит суффиксное правило с '.a' в качестве суффикса цели. Любое правило двойного суффикса '.x.a' преобразуется в шаблонное правило с шаблоном цели '(%.o)' и шаблоном зависимости '%.x'.

Поскольку вы могли бы захотеть использовать '.a' в качестве для какого-нибудь другого типа файла, программа make также преобразует архивные суффиксные правила в шаблонные правила и обычным способом (смотрите раздел 10.7 [Суффиксные правила]). Таким образом, правило двойного суффикса '.x.a' порождает два шаблонных правила: '(%.o): %.x' и '%.a: %.x'.


Вперед Назад Содержание
Вперед Назад Содержание

12. Особенности GNU-версии программы make

Здесь приведен обзор особонностей GNU-версии программы make, которые отличают ее от других версий, а также заимствованы из других версий программы make. Мы берем за основу особенности программы make в системах 4.2 BSD. Если вы заинтересованы в написании переносимых make-файлов, то вам следует использовать только возможности программы make, не перечисленные здесь и в главе 13 [Недостающие возможности].

Многие особенности происходят из версии программы make для системы System V.

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

Оставшиеся возможности - новые изобретения GNU-версии программы make:


Вперед Назад Содержание
Вперед Назад Содержание

13. Несовместимость и недостающие возможности

Программы make на различных других системах поддерживают некоторые возможности, которые не реализованы в GNU-версии программы make. Стандарт POSIX.2 (стандарт IEEE 1003.2-1992), который специфицирует программу make, не требует ни одной из этих возможностей.


Вперед Назад Содержание
Вперед Назад Содержание

14. Соглашения о make-файлах

Эта глава описывает соглашения по написанию make-файлов для GNU-программ.

14.1 Общие соглашения о make-файлах

Каждый make-файл должен содержать такую строку:

      SHELL = /bin/sh   
во избежании проблем при работе на тех системах, где переменная SHELL могла бы быть унаследована из среды. (Это никогда не является проблемой при работе с GNU-версией программы make.)

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

      .SUFFIXES:   
      .SUFFIXES: .c .o   
Первая строка очищает список суффиксов, вторая представляет все суффиксы, которые могут быть предметом неявных правил в этом make-файле.

При выполнении команд не закладывайтесь на то, что символ '.' находится в пути. Когда во время работы программы make вам требуется запускать программы, которые являются частью вашего пакета, убедитесь, пожалуйста, что используется './', если построение программы происходит в рамках части программы make или '$(srcdir)/', если файл является неизменяемой частью исходного кода. Если нет ни одного из этих префиксов, то используется текущий путь поиска.

Различие между './' и '$(srcdir)/' важно при использовании опции '--srcdir', установленной в значение 'configure'. Правило в такой форме:

      foo.1 : foo.man sedscript sed   
      p        -e sedscript foo.man   
      p        > foo.1   
не сможет быть выполнено, когда текущий каталог не является исходным каталогом, поскольку файлов 'foo.man' и 'sedscript' нет в текущем каталоге.

При использовании GNU-версии программы make полагаться на переменную VPATH для поиска исходного файла можно в том случае, когда есть один файл зависимости, поскольку автоматическая переменная программы make '$<' будет представлять исходный файл, где бы она ни находилась. (Многие версии программы make устанавливать переменную '$<' только в неявных правилах.) Цель make-файла, представленная в такой форме:

      foo.o : bar.c   
      p         $(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o   
должно вместо этого быть записана в таком виде:

      foo.o : bar.c   
              $(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@         
для того, чтобы позволить переменной VPATH корректно работать. Когда цель имеет несколько зависимостей, явное использование ссылки на переменную '$(srcdir)'представляет собой самый легкий способ, заставляющий правило работать правильно. Например, лучше всего, чтобы приведенное выше правило для файла 'foo.1' было написано в таком виде:

      foo.1 : foo.man sedscript sed   
              -e $(srcdir)/sedscript   
              $(srcdir)/foo.man >   
              $@         

14.2 Использование утилит в Makefile.

Команды, которые пишутся в Makefile (как, впрочем, и в любых других shell-скриптах вроде configure), должны работать в sh, а не в csh. Не следует использовать каких-либо специальных особенностей ksh или bash.

Скрипт configure и правила Makefile для построения и установки программы не должны использовать никаких утилит кроме следующих:

    cat cmp cp echo egrep expr grep   
    ln mkdir mv pwd rm rmdir sed test touch   
Следует использовать только общепринятые опции для этих программ. К примеру, не следует использовать 'mkdir -p', поскольку эта опция хоть и удобна, но большинство систем не поддерживают ее.

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

    ar bison cc flex install ld lex   
    make makeinfo ranlib texi2dvi yacc   
Когда Вы используете ranlib, Вы должны проверять его существование в системе, и использовать его только в том случае, если он присутствует. Это необходимо для того, чтобы можно было выполнять построение на системах, не имеющих ranlib.

Если Вы используете символические ссылки, Вы должны поддержать возможность использования Вашего пакета в системах, которые не поддерживают символических ссылок.

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

14.3 Стандартные цели в Make

Все программы в GNU должны иметь следующие цели в своих Makefile'ах.

'all'

Компиляция всей программой. Эта цель должна быть целью по умолчанию. Эта цель не должна перестраивать никакие файлы документации; info-файлы должны включаться в поставку, DVI файлы должны формироваться только по явному запросу.

'install'

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

Команды должны создать все каталоги, в которых файлы будут установлены, если эти каталоги уже не существуют. Сюда входят каталоги, указанные как значения переменных prefix и exec_prefix, так же, как и все их требуемые подкаталоги. Другой способ выполнить это подразумевает использование цели installdirs, описанной ниже.

Используйте символ '-' перед любой командой для установки файлов с man-страницами для того, чтобы игнорировались все ошибки. Это нужно для того, чтобы можно было устанавливать программу на систему, в которой не установлена Unix-система man-документов.

Для установки info-файлов необходимо скопировать их в $(infodir) с $(INSTALL_DATA) (см. Переменные для исполнения команд), и затем выполнить программу install-info (если она имеется). install-info - это скрипт, который выполняет редактирование файла 'dir' системы Info для того, чтобы добавить или обновить элемент меню для данного Info-файла; этот скрипт является частью пакета Texinfo. Далее приводится пример правила для установки Info-файла:

 $(infodir)/foo.info: foo.info   
 # There may be a newer info file in . than in srcdir   
      -if test -f foo.info; then d=.; \   
       else d=$(srcdir); i;   
      $(INSTALL_DATA) $$d/foo.info $@      ; \   
 # Run install-info only if it exists.   
 # Use 'if' instead of just prepending '-' to the   
 # line so we notice real errors from install-info.   
 # We use '$(SHELL) -c' because some shells do   
 # fail gracefuly when there is an unknown command.   
      if $(SHELL) -c 'install-info --version' \   
         >/dev/null 2>&1; then \   
       install-info --infodir=$(infodir) $$d/foo.info; \   
      else true; fi   
'uninstall'

Выполняется удаление всех установленных файлов, созданных при исполнении цели 'install' (но не тех файлов, которые создаются при исполнении цели 'all').

'clean'

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

'distclean'

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

'mostyclean'

Работает так же, как и clean, но оставляет неудаленными некоторые файлы, которые обычно нежелательно перекомпилировать. Например, цель 'mostyclean' для GCC не удаляет файл 'libgcc.a', поскольку его перекомпиляция редко когда бывает нужна, и к тому же занимает много времени.

'realclean'

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

Имеется одно исключение: 'make realclean' не должен удалять 'configure', даже если 'configure' может быть построен используя правило в Makefile. Более того, 'make realclean' не должен удалять ничего из того, чье существование требуется для выполнения 'configure' и начального исполнения программы.

'TAGS'

Обновляет таблицу тегов для программы.

'info'

Выполняется построение всех требуемых info-файлов. Лучший всего написать правила по следующему образцу:

 info: foo.info   
    
 foo.info: foo.texi chap1.texi chap2.texi   
      $(MAKEINFO) $(srcdir)/foo.texi   
Вы должны определить в Makefile переменную MAKEINFO. Она должна запускать программу makeinfo, которая входит в поставку пакета Texinfo.

'dvi'

Выполняется построение DVI-файлов для всей TeXinfo-документации. Пример правил:

 dvi: foo.dvi   
    
 foo.dvi: foo.texi chap1.texi chap2.texi   
      $(TEXI2DVI) $(srcdir)/foo.texi   
Вы должны определить переменную TEXI2DVI в Makefile. Она должна запускать программу texi2dvi, которая является частью поставки пакета Texinfo. Можно указать просто зависимости, тогда GNU Make сам предоставит эту команду.

'dist'

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

Например, поставка дистрибутивного архива для GCC версии 1.40 должна распаковываться в каталог с именем 'gcc-1.40'.

Простейший способ выполнить это состоит в создании названного таким образом каталога, и использовании ln или cp для установки соответствующих файлов в него. После чего необходимо выполнить tar для этого подкаталога.

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

'check'

Выполняет самотестирование (если предусмотрено). Пользователь должен построить программу перед запуском тестов, но не должен устанавливать программу; Вы должны написать тесты таким образом, чтобы они работали когда программа построена, но не установлена.

Следующие цели в тех программах, в которых они нужны, должны иметь следующие стандартные имена.

'installcheck'

Выполняет проверку правильности установки (если соответствующие тесты предусмотрены). Пользователь должен построить и установить программу перед запуском этих тестов. Вы не должны считать, что $(bindir) входит в путь поиска программ.

'installdirs'

Полезно добавить цель с именем 'installdirs' для создания структуры каталогов, в которых будут установлены файлы. Имеется скрипт, названный 'mkinstalldirs', который подходит для этой цели. Он находится в пакете Texinfo. Вы можете написать правило по следующему образцу:

 # Make sure all installation directories (e.g. $(bindir))   
 # actually exists by making them if necessary.   
 installdirs: mkinstalldirs   
      $(srcdir)/mkinstalldirs $(bindir) $(datadir) \   
                              $(libdir) $(infodir) \   
                              $(mandir)   

14.4 Переменные для указания команд.

Makefile должен предоставлять переменные для того, чтобы можно было перекрыть некоторые команды, опции и т.д.

В частности, Вы должны запускать большинство утилит через переменные. Так, если Вы используете Bison, введите переменную с именем BISON, чье значение по умолчанию установлено как 'BISON=bison', и ссылайтесь на нее $(BISON) везде, где Вам нужно использовать Bison.

Утилиты управления файлами (такие, как ln, rm, mv и т.д.) не должны выполняться через переменные, поскольку пользователям нет необходимости заменять их другими программами.

Каждой переменной с именем программы должна соответствовать переменная с опциями, которые должны передаваться этой программе. Следует добавлять 'FLAGS' к имени переменной для программы, чтобы получить имя переменной для опций - например, BISONFLAGS. (Имя CFLAGS является исключением из этого правила, но мы сохраняем его, поскольку оно общепринято.) Используйте CPPFLAGS в любой команде компиляции, которая запускает препроцессор, и LDFLAGS в любой команде компиляции, которая выполняет редактирование связей, так же, как и при явном использовании ld.

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

 CFLAGS = -g   
 ALL_CFLAGS = -I. $(CFLAGS)   
 .c.o:   
      $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<   
Не следует включать опцию -g в CFLAGS, поскольку она не требуется для правильной компиляции. Вы можете рассматривать это умолчание как рекоменуемое. Если пакет установлен так, что он компилируется с использованием GCC по умолчанию, то вы можете включить '-O' в умалчиваемое значение переменной CFLAGS.

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

Каждый Makefile должен определять переменную INSTALL, которая обозначает бызовою команду для установки файла в системе.

Каждый Makefile должен также определять переменные INSTALL_PROGRAM и INSTALL_DATA. (Умолчание для этих переменных должно быть $(INSTALL).) В дальнейшем, эти переменные должны использоваться для установки соответственно исполнимых и неисполнимых файлов. Используйте эти переменные как в примере:

 $(INSTALL_PROGRAM) foo $(bindir)/foo   
 $(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a   
Следует всегда указывать в качестве второго аргумента имя файла (не имя каталога). Надо использовать отдельную команду для каждого устанавливаемого файла.

14.5 Переменные для каталогов

Каталоги для установки должны всегда именоваться посредством переменных, поскольку это упрощает установку программы в нестандартное место. Стандартные имена для таких переменных следующие:

'prefix'

Префикс, используемый для построения умолчательных значений для переменных, перечисленных ниже. Значение по умолчанию для переменной prefix должно быть '/usr/local' (по крайней мере сейчас).

'exec_prefix'

Префикс, используемый при построении значений по умолчанию для некоторых переменных, перечисленных ниже. Значение по умолчанию для переменной exec_prefix должно быть $(prefix).

Как правило, $(prefix) используется для каталогов, которые содержат машиннозависимые файлы (такие, как исполнимые файлы и библиотеки процедур), в то время как $(prefix) используется для остальных каталогов.

'bindir'

Каталог для установки исполнимых программ, которые могут быть запущены пользователем. Обычно, это '/usr/local/bin', но должно быть записано как '$(exec_prefix)/bin'

'libdir'

Каталог для установки исполняемых файлов, которые будут запускаться другими программами, а не пользователем. Объектные файлы и библиотеки объектного кода должны так же попадать в этот каталог. Идея состоит в том, что этот каталог используется для файлов, которые зависят от конкретной архитектуры машины, но не должны находится в пути для команд. Значение для libdir обычно '/usr/local/lib', но должно быть записано как '$(exec_prefix)/lib'.

'datadir'

Каталог для установки файлов с неизменяемыми данными, которые используются программами во время их работы. Этот каталог используется для файлов, которые не зависят от используемого типа машины. Значение этой переменной обычно '/usr/local/lib', но должно быть записано как '$(prefix)/lib'.

'statedir'

Каталог для установки файлов с данными, которые программы могут изменять в процессе своей работы. Эти файлы должны быть независимыми от типа используемой машины, и должны допускать разделение их между машинами при сетевой установке. Значение этой переменной обычно '/usr/local/lib', но должно быть записано как '$(prefix)/lib'

'includedir'

Каталог для установки заголовочных файлов (header-файлов), которые могут быть включены другими пользовательскими программами с помощью директивы препроцессора '#include'. Значение этой переменной обычно '/usr/local/include', но должно быть записано как '$prefix/include'.

Большинство компиляторов отличных от GCC не выполняют поиск заголовочных файлов в '/usr/local/include', поэтому установка заголовочных файлов в этот каталог целесообразна только для GCC. Иногда это не представляет из себя проблему, так как некоторые библиотеки предназначены для использования исключительно с GCC. Но имеются так же и библиотеки, предназначенные для работы и с другими компиляторами. Они должны устанавливать свои включаемые файлы в два места, одно из которых определено переменной includedir, а другое - oldincludedir.

'oldincludedir'

Каталог для установки заголовочных файлов для использования с компиляторами, отличными от GCC. Значение этой переменной обычно '/usr/include'.

Команды Makefile должны проверить, не пусто ли значение переменной oldincludedir. Если оно пусто, они не должны пытаться использовать ее и выполнять повторную установку включаемых файлов.

Пакет не должен замещать существующие заголовочные файлы в этом каталоге, в случае, если заголовочный файл пришел не из того же пакета. Так, если Ваш пакет Foo предоставляет заголовочный файл 'foo.h', то он должне установить заголовочный файл в каталог, заданный oldincludedir, если (1) foo.h не существует, или (2) foo.h существует и пришел из пакета Foo.

Для того, чтобы проверить, что foo.h пришел из пакета Foo, поместите специальную строку в этот файл - часть комментария - и проверьте наличие этой строки с помощью команды grep.

'mandir'

Каталог для установки man-страниц (если они есть) для этого пакета. Переменная должна включать суффикс для соответсвующей секции руководства - обычно '1' для утилит. Обычно значение этой переменной '/usr/local/man/man1', но должно быть записано как '$(prefix)/man/man1'

'man1dir'

Каталог для установки в раздел 1 man-страниц.

'man2dir'

Каталог для установки в раздел 2 man-страниц.

Используйте переменные такого рода вместо 'mandir', если пакет должен устанавливать man-страницы более чем в один раздел.

'manext'

Расширение для имени файла для устанавливаемых man-страниц. Переменная должна содержать точку, за которой следует соответствующая цифра, обычно '.1'.

'man1ext'

Расширение имени файла для установки в раздел 1 man-страниц.

'man2ext'

Расширение имени файла для установки в раздел 2 man-страниц.

Используйте переменные такого рода вместо 'manext', если пакет должен устанавливать man-страницы более чем в один раздел.

'infodir'

Переменная должна содержать имя каталога для установки info-файлов для данного пакета. По умолчанию, ее значение должно быть '/usr/local/info', но должно быть записано как '$(prefix)/info'.

'srcdir'

В этой переменной должно находится имя каталога, содержащего компилируемые исходные тексты. Значение этой переменной обычно вставляется скриптом configure.

Пример:

 # Common prefix for installation directories.   
 # NOTE: This directory must exist when you start the install.   
 prefix = /usr/local   
 exec_prefix = $(prefix)   
 # Where to put the executable for the command 'gcc'.   
 bindir = $(exec_prefix)/bin   
 # Where to put the directories used by the compiler.   
 libdir = $(exec_prefix)/lib   
 # Where to put the Info files.   
 infodir = $(prefix)/info   
Если Ваша программа устанавливает большое количество файлов в один из стандартных каталогов, указанных пользователем, целесообразно сгруппировать их в один подкаталог, относящийся к этой программе. Если Вы делаете это, Вы должны создать такие подкаталоги в правиле для цели install.

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


Вперед Назад Содержание
Назад Содержание

15. Приложение. Комплексный пример Make-файла.

В этом приложении приводится текст Make-файла для программы tar. Это сравнительно сложный Make-файл.

Целью по умолчанию в этом Make-файле является 'all', поскольку это первая цель. Интересной особенностью этого Make-файла является то, что файл 'testpad.h' генерируется автоматически с помощью программы 'testpad', которая в свою очередь получается компиляцией файла 'testpad.c'.

Если Вы наберете 'make' или 'make all', то make создаст исполнимый модуль 'tar', демон 'rmt', который предоставляет доступ к накопителям на магнитной ленте, расположенным на других машинах, и info-файл 'tar.info'.

Если Вы наберете 'make install', то make не только создаст 'tar', 'rmt' и 'tar.info', но и установит их.

Если Вы наберете 'make clean', то make удалит все '.o'-файлы, а так же файлы 'tar', 'rmt', 'testpad', testpad.h' и 'core'.

Если Вы наберете 'make distclean', то make удалит не только файлы, которые удаляются при исполнении цели 'clean', но также и файлы 'TAGS', 'Makefile' и 'config.status'. (Хоть это и неочевидно, файлы 'Makefile' и 'config.status' генерируются пользователем с помощью программы 'configure', которая входит в состав поставки пакета 'tar', но не показана здесь.)

Если Вы наберете 'make realclean', то make удалит файлы, удаляемые при исполнении цели 'distclean', и info-файлы, которые строятся из исходного файла 'tar.texinfo'.

Наконец, цели 'shar' и 'dist' строят дистрибутив, используемый для распространения.

      # Generated automatically from Makefile.in by configure.   
      # Un*x Makefile for GNU tar program.   
      # Copyright (C) 1991 Free Software Foundation, Inc.   
         
      # This program is free software; you can redistribute   
      # it and/or modify it under the terms of the GNU   
      # General Public License ...   
      ...   
      ...   
         
      SHELL = /bin/sh   
         
      #### Start of system configuration section. ####   
         
      srcdir = .   
         
      # If you use gcc, you should either run the   
      # fixincludes script that comes with it or else use   
      # gcc with the -traditional option.  Otherwise ioctl   
      # calls will be compiled incorrectly on some systems.   
      CC = gcc -O   
      YACC = bison -y   
      INSTALL = /usr/local/bin/install -c   
      INSTALLDATA = /usr/local/bin/install -c -m 644   
         
      # Things you might add to DEFS:   
      # -DSTDC_HEADERS        If you have ANSI C headers and   
      #                       libraries.   
      # -DPOSIX               If you have POSIX.1 headers and   
      #                       libraries.   
      # -DBSD42               If you have sys/dir.h (unless   
      #                       you use -DPOSIX), sys/file.h,   
      #                       and st_blocks in `struct stat'.   
      # -DUSG                 If you have System V/ANSI C   
      #                       string and memory functions   
      #                       and headers, sys/sysmacros.h,   
      #                       fcntl.h, getcwd, no valloc,   
      #                       and ndir.h (unless   
      #                       you use -DDIRENT).   
      # -DNO_MEMORY_H         If USG or STDC_HEADERS but do not   
      #                       include memory.h.   
      # -DDIRENT              If USG and you have dirent.h   
      #                       instead of ndir.h.   
      # -DSIGTYPE=int         If your signal handlers   
      #                       return int, not void.   
      # -DNO_MTIO             If you lack sys/mtio.h   
      #                       (magtape ioctls).   
      # -DNO_REMOTE           If you do not have a remote shell   
      #                       or rexec.   
      # -DUSE_REXEC           To use rexec for remote tape   
      #                       operations instead of   
      #                       forking rsh or remsh.   
      # -DVPRINTF_MISSING     If you lack vprintf function   
      #                       (but have _doprnt).   
      # -DDOPRNT_MISSING      If you lack _doprnt function.   
      #                       Also need to define   
      #                       -DVPRINTF_MISSING.   
      # -DFTIME_MISSING       If you lack ftime system call.   
      # -DSTRSTR_MISSING      If you lack strstr function.   
      # -DVALLOC_MISSING      If you lack valloc function.   
      # -DMKDIR_MISSING       If you lack mkdir and   
      #                       rmdir system calls.   
      # -DRENAME_MISSING      If you lack rename system call.   
      # -DFTRUNCATE_MISSING   If you lack ftruncate   
      #                       system call.   
      # -DV7                  On Version 7 Unix (not   
      #                       tested in a long time).   
      # -DEMUL_OPEN3          If you lack a 3-argument version   
      #                       of open, and want to emulate it   
      #                       with system calls you do have.   
      # -DNO_OPEN3            If you lack the 3-argument open   
      #                       and want to disable the tar -k   
      #                       option instead of emulating open.   
      # -DXENIX               If you have sys/inode.h   
      #                       and need it 94 to be included.   
         
      DEFS =  -DSIGTYPE=int -DDIRENT -DSTRSTR_MISSING \   
              -DVPRINTF_MISSING -DBSD42   
      # Set this to rtapelib.o unless you defined NO_REMOTE,   
      # in which case make it empty.   
      RTAPELIB = rtapelib.o   
      LIBS =   
      DEF_AR_FILE = /dev/rmt8   
      DEFBLOCKING = 20   
         
      CDEBUG = -g   
      CFLAGS = $(CDEBUG) -I. -I$(srcdir) $(DEFS) \   
              -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" \   
              -DDEFBLOCKING=$(DEFBLOCKING)   
      LDFLAGS = -g   
         
      prefix = /usr/local   
      # Prefix for each installed program,   
      # normally empty or `g'.   
      binprefix =   
         
      # The directory to install tar in.   
      bindir = $(prefix)/bin   
         
      # The directory to install the info files in.   
      infodir = $(prefix)/info   
         
      #### End of system configuration section. ####   
         
      SRC1 =  tar.c create.c extract.c buffer.c \   
              getoldopt.c update.c gnu.c mangle.c   
      SRC2 =  version.c list.c names.c diffarch.c \   
              port.c wildmat.c getopt.c   
      SRC3 =  getopt1.c regex.c getdate.y   
      SRCS =  $(SRC1) $(SRC2) $(SRC3)   
      OBJ1 =  tar.o create.o extract.o buffer.o \   
              getoldopt.o update.o gnu.o mangle.o   
      OBJ2 =  version.o list.o names.o diffarch.o \   
              port.o wildmat.o getopt.o   
      OBJ3 =  getopt1.o regex.o getdate.o $(RTAPELIB)   
      OBJS =  $(OBJ1) $(OBJ2) $(OBJ3)   
      AUX =   README COPYING ChangeLog Makefile.in  \   
              makefile.pc configure configure.in \   
              tar.texinfo tar.info* texinfo.tex \   
              tar.h port.h open3.h getopt.h regex.h \   
              rmt.h rmt.c rtapelib.c alloca.c \   
              msd_dir.h msd_dir.c tcexparg.c \   
              level-0 level-1 backup-specs testpad.c   
         
      all:    tar rmt tar.info   
         
      tar:    $(OBJS)   
              $(CC) $(LDFLAGS) -o $@       $(OBJS) $(LIBS)   
         
      rmt:    rmt.c   
              $(CC) $(CFLAGS) $(LDFLAGS) -o $@       rmt.c   
         
      tar.info: tar.texinfo   
              makeinfo tar.texinfo   
         
      install: all   
              $(INSTALL) tar $(bindir)/$(binprefix)tar   
              -test ! -f rmt || $(INSTALL) rmt /etc/rmt   
              $(INSTALLDATA) $(srcdir)/tar.info* $(infodir)   
         
      $(OBJS): tar.h port.h testpad.h   
      regex.o buffer.o tar.o: regex.h   
      # getdate.y has 8 shift/reduce conflicts.   
         
      testpad.h: testpad   
              ./testpad   
         
      testpad: testpad.o   
              $(CC) -o $@       testpad.o   
         
      TAGS:   $(SRCS)   
              etags $(SRCS)   
         
      clean:   
              rm -f *.o tar rmt testpad testpad.h core   
         
      distclean: clean   
              rm -f TAGS Makefile config.status   
         
      realclean: distclean   
              rm -f tar.info*   
         
      shar: $(SRCS) $(AUX)   
              shar $(SRCS) $(AUX) | compress \   
                > tar-`sed -e '/version_string/!d' \   
                           -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \   
                           -e q   
                           version.c`.shar.Z   
         
      dist: $(SRCS) $(AUX)   
              echo tar-`sed \   
                   -e '/version_string/!d' \   
                   -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \   
                   -e q   
                   version.c` > .fname   
              -rm -rf `cat .fname`   
              mkdir `cat .fname`   
              ln $(SRCS) $(AUX) `cat .fname`   
              -rm -rf `cat .fname` .fname   
              tar chZf `cat .fname`.tar.Z `cat .fname`   
         
      tar.zoo: $(SRCS) $(AUX)   
              -rm -rf tmp.dir   
              -mkdir tmp.dir   
              -rm tar.zoo   
              for X in $(SRCS) $(AUX) ; do \   
                  echo $$X ; \   
                  sed 's/$$/^M/' $$X \   
                  > tmp.dir/$$X ; done   
              cd tmp.dir ; zoo aM ../tar.zoo *   
              -rm -rf tmp.dir   


Вперед Назад Содержание
GNU Make

Программа управления компиляцией

GNU make Версия 3.79

Апрель 2000

Richard M. Stallman и Roland McGrath, перевод (C) Владимир Игнатов, 2000

Версия перевода 0.1

Английский оригинал этого текста находится здесь.

Оригинал перевода находится на моей домашней страничке.


Оглавление


Назначение программы make

Утилита make автоматически определяет какие части большой программы должны быть перекомпилированы, и выполняет необходимые для этого действия. В данном руководстве описывается программа GNU make, авторами которой являются Richard Stallman и Roland McGrath. Начиная с версии 3.76, разработку программы ведет Paul D. Smith.

GNU make удовлетворяет требованиям раздела 6.2 стандарта IEEE Standard 1003.2-1992 (POSIX.2).

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

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

После того, как нужный make-файл создан, простой команды :

make

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

При вызове make, в командной строке могут быть заданы параметры, указывающие, какие файлы следует перекомпилировать и каким образом это делать. Смотрите раздел Запуск make.

Как читать данное руководство

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

Если вы знакомы с другими версиями программы make, обратите внимание на раздел Возможности GNU make, в котором описан широкий набор возможностей, имеющихся в утилите GNU make, а также раздел Несовместимость и нереализованные функции, в котором описаны несколько вещей, которые имеются в других реализациях, но отсутствуют в GNU make

Для быстрого получения справки, смотрите разделы Обзор опций и Справочник, а также раздел Имена специальных целей.

Ошибки и проблемы

Если у вас возникли проблемы с использованием GNU make или вам кажется, что вы обнаружили ошибку в ее работе, пожалуйста, сообщите об этом разработчикам. Мы не может обещать невозможного, однако постараемся исправить положение.

Прежде, чем сообщать об ошибке, убедитесь в том что это - действительно ошибка. Еще раз внимательно перечитайте документацию. Если у вас что-то не получается - посмотрите, действительно ли в документации говорится о том, что это можно сделать. Если из документации непонятно - допустимы ли ваши действия или нет, сообщите нам об этом. Это означает ошибку в документации!

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

Если вы действительно обнаружили проблему, пожалуйста, сообщите нам об этом по следующему адресу:

    bug-make@gnu.org

Пожалуйста, укажите номер версии вашей программы make. Вы можете получить эту информацию, набрав в командной строке`make --version'. Не забудьте также указать тип вашей машины и операционной системы. По возможности, укажите содержимое файла `config.h', который получается в результате работы процесса конфигурирования на вашей машине.

Знакомство с make-файлами (makefiles)

Для работы с утилитой make, вам понадобится так называемый make-файл (makefile), который будет содержать описание требуемых действий. Как правило, make-файл описывает, каким образом нужно компилировать и компоновать программу.

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

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

Как выглядят правила (rules)

Простой make-файл состоит из "правил" (rules) следующего вида:

цель ... : пререквизит ...
        команда
        ...
        ...

Обычно, цель (target) представляет собой имя файла, который генерируется в процессе работы утилиты make. Примером могут служить объектные и исполняемый файлы собираемой программы. Цель также может быть именем некоторого действия, которое нужно выполнить (например,`clean' - очистить). Подробнее это обсуждает в разделе Абстрактные цели ).

Пререквизит (prerequisite) - это файл, который используется как исходдные данные для порождения цели. Очень часто цель зависит сразу от нескольких файлов.

Команда - это действие, выполняемое утилитой make. В правиле может содержаться несколько команд - каждая на свое собственной строке. Важное замечание: строки, содержащие команды обязательно должны начинаться с символа табуляции! Это - "грабли", на которые наступают многие начинающие пользователи.

Обычно, команды находятся в правилах с пререквизитами и служат для создания файла-цели, если какой-нибудь из пререквизитов был модефицирован. Однако, правило, имеющее команды, не обязательно должно иметь пререквизиты. Например, правило с целью `clean' ("очистка"), содержащее команды удаления, может не иметь пререквизитов.

Правило (rule) описывает, когда и каким образом следует обновлять файлы, указанные в нем в качестве цели. Для создания или обновления цели, make исполняет указанные в правиле команды, используя пререквизиты в качестве исходных данных. Правило также может описывать каким образом должно выполняться некоторое действие. Подробно это обсуждается в разделе Составление правил.

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

Пример простого make-файла

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

В данном примере, заголовочный файл `defs.h' включается во все файлы с исходным текстом. Заголовочный файл `command.h' включается только в те исходные файлы, которые относятся к командам редактирования, а файл `buffer.h' - только в "низкоуровневые" файлы, непосредственно оперирующие буфером редактирования.

edit : main.o kbd.o command.o display.o \
       insert.o search.o files.o utils.o
        cc -o edit main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o

main.o : main.c defs.h
        cc -c main.c
kbd.o : kbd.c defs.h command.h
        cc -c kbd.c
command.o : command.c defs.h command.h
        cc -c command.c
display.o : display.c defs.h buffer.h
        cc -c display.c
insert.o : insert.c defs.h buffer.h
        cc -c insert.c
search.o : search.c defs.h buffer.h
        cc -c search.c
files.o : files.c defs.h buffer.h command.h
        cc -c files.c
utils.o : utils.c defs.h
        cc -c utils.c
clean :
        rm edit main.o kbd.o command.o display.o \
           insert.o search.o files.o utils.o

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

Для того, чтобы с помощью этого make-файла создать исполняемый файл `edit', наберите:

make

Для того, чтобы удалить исполняемый и объектные файлы из директории проекта, наберите:

make clean

В приведенном примере, целями, в частности, являются объектные файлы `main.o'и `kbd.o', а также исполняемый файл `edit'. К пререквизитам относятся такие файлы, как`main.c'и `defs.h'. Каждый объектный файл, фактически, является одновременно и целью и пререквизитом. Примерами команд могут служить`cc -c main.c' и `cc -c kbd.c'.

В случае, если цель является файлом, этот файл должен быть перекомпилирован или перекомпонован всякий раз, когда был изменен какой-либо из его пререквизитов. Кроме того, любые пререквизиты, которые сами генерируются автоматически, должны быть обновлены первыми. В нашем примере, исполняемый файл `edit' зависит от восьми объектных файлов; объектный файл `main.o' зависит от исходного файла `main.c' и заголовочного файла `defs.h'.

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

Цель `clean' является не файлом, а именем действия. Поскольку, при обычной сборке программы это действие не требуется, цель`clean' не является пререквизитом какого-либо из правил. Следовательно, make не будет "трогать" это правило, пока вы специально об этом не попросите. Заметьте, что это правило не только не является пререквизитом, но и само не содержит каких-либо пререквизитов. Таким образом, единственное предназначение данного правила - выполнение указанных в нем команд. Цели, которые являются не файлами, а именами действий называются абстрактными целями (phony targets). Абстрактные цели подробно рассматриваются в разделе Абстрактные цели. В разделе Ошибки при выполнении команд описано, как заставить make игнорировать ошибки, которые могут возникнуть при выполнении команды rm и любых других команд.

Как make обрабатывает make-файл

По умолчанию, make начинает свою работу с первой встреченной цели (кроме целей, чье имя начинается с символа `.'). Эта цель будет являться главной целью по умолчанию (default goal). Главная цель (goal) - это цель, которую стремится достичь make в качестве результата своей работы. В разделе Аргументы для задания главной цели обсуждается, каким образом можно явно задать главную цель.

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

Таким образом, когда вы даете команду:

make

make читает make-файл из текущей директории и начинает его обработку с первого встреченного правила. В нашем примере это правило обеспечивает перекомпоновку исполняемого файла `edit'. Однако, прежде чем make сможет полностью обработать это правило, ей нужно обработать правила для всех файлов, от которых зависит `edit'. В данном случае - от всех объектных файлов программы. Каждый из этих объектных файлов обрабатывается согласно своему собственному правилу. Эти правила говорят, что каждый файл с расширением`.o' (объектный файл) получается в результате компиляции соответствующего ему исходного файла. Такая компиляция должна быть выполнена, если исходный файл или какой-либо из заголовочных файлов, перечисленных в качестве пререквизитов, являются "более новыми", чем объектный файл, либо объектного файла вообще не существует.

Другие правила обрабатывается потому, что их цели прямо или косвенно являются пререквизитами для главной цели. Если какое-либо правило никоим образом не "связано" с главной целью (то есть ни прямо, ни косвенно не являются его пререквизитом), то это правило не обрабатывается. Чтобы задействовать такие правила, придется явно указать make на необходимость их обработки (подобным, например, образом: make clean).

Перед перекомпиляцией объектного файла, make рассматривает необходимость обновления его пререквизитов, в данном случае - файла с исходным текстом и заголовочных файлов. В нашем make-файле не содержится никаких инструкций по обновлению этих файлов - файлы с расширениями `.c' и `.h' не являются целями каких-либо правил. Таким образом, утилита make не предпринимает никаких действий с этими файлами. Однако, make могла бы автоматически обновлять и исходные тексты, если бы они, например, генерировались с помощью программ, подобных Bison или Yacc, и для них были бы определены соответствующие правила.

После перекомпиляции объектных файлов, которые нуждаются в этом, make принимает решение - нужно ли перекомпоновывать файл `edit'. Это нужно делать, если файла `edit' не существует или какой-нибудь из объектных файлов по сравнению с ним является более "свежим". Если какой-либо из объектных файлов только что был откомпилирован заново, то он будет "моложе", чем файл `edit'. Соответственно, файл `edit' будет перекомпонован.

Так, если мы модефицируем файл `insert.c' и запустим make, этот файл будет скомпилирован заново для обновления объектного файла `insert.o', и, затем, файл `edit' будет перекомпонован. Если мы изменим файл `command.h' и запустим make, то будут перекомпилированы объектные файлы `kbd.o', `command.o' и `files.o', а затем исполняемый файл `edit' будет скомпонован заново.

Упрощение make-файла с помощью переменных

В приведенном выше примере, в правиле для `edit' нам дважды пришлось перечислять список объектных файлов программы:

edit : main.o kbd.o command.o display.o \
              insert.o search.o files.o utils.o
        cc -o edit main.o kbd.o command.o display.o \
                   insert.o search.o files.o utils.o

Подобное дублирование чревато ошибками. При добавлении в проект нового объектного файла, можно добавить его в один список и забыть про другой. Мы можем устранить подобный риск, и, одновременно, упростить make-файл, используя переменные. Переменные (variables) позволяют, один раз определив текстовую строку, затем использовать ее многократно в нужных местах. Переменные подробно обсуждаются в разделе Использование переменных).

Обычной практикой при построении make-файлов является использование переменной с именем objects, OBJECTS, objs, OBJS, obj, или OBJ, которая содержит список всех объектных файлов программы. Мы могли бы определить подобную переменную с именем objects таким образом:

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

Далее, всякий раз, когда нам нужен будет список объектных файлов, мы можем использовать значение этой переменной с помощью записи`$(objects)' (смотрите раздел Использование переменных).

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

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)
main.o : main.c defs.h
        cc -c main.c
kbd.o : kbd.c defs.h command.h
        cc -c kbd.c
command.o : command.c defs.h command.h
        cc -c command.c
display.o : display.c defs.h buffer.h
        cc -c display.c
insert.o : insert.c defs.h buffer.h
        cc -c insert.c
search.o : search.c defs.h buffer.h
        cc -c search.c
files.o : files.c defs.h buffer.h command.h
        cc -c files.c
utils.o : utils.c defs.h
        cc -c utils.c
clean :
        rm edit $(objects)

Неявные правила упрощают make-файл

На самом деле, нет необходимости явного указания команд компиляции отдельно для каждого из исходных файлов. Утилита make сама может "догадаться" об использовании нужных команд, поскольку у нее имеется, так называемое, неявное правило (implicit rule) для обновления файлов с расширением `.o' из файлов с расширеним `.c', с помощью команды `cc -c'. Например, она бы использовала команду `cc -c main.c -o main.o' для преобразования файла `main.c' в файл `main.o'. Таким образом, можно убрать явное указание команд компиляции из правил, описывающих построение объектных файлов. Смотрите раздел Использование неявных правил.

Когда файл с расширением `.c' автоматически используется подобным образом, он также автоматически добавляется в список пререквизитов "своего" объектного файла. Таким образом, мы вполне можем убрать файлы с расширением `.c' из списков пререквизитов объектных файлов.

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

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)

main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean
clean :
        -rm edit $(objects)

Примерно так и выглядят make-файлы в реальной практике. Для правила с`clean' здесь использована более сложная запись, которую мы обсудим позже (смотрите разделы Абстрактные цели, и Ошибки при исполнении команд).

Из-за своего удобства, неявные правила широко используются и играют важную роль в работе make.

Другой стиль написания make-файлов

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

objects = main.o kbd.o command.o display.o \
          insert.o search.o files.o utils.o

edit : $(objects)
        cc -o edit $(objects)

$(objects) : defs.h
kbd.o command.o files.o : command.h
display.o insert.o search.o files.o : buffer.h

Здесь, заголовочный файл `defs.h' объявляется пререквизитом для всех объектных файлов программы. Файлы `command.h' и `buffer.h' являются пререквизитами для перечисленных объектных файлов.

Какой стиль построения make-файлов предпочесть - является делом вкуса. Альтернативный стиль более компактен, однако он нравится не всем - многие считают более "естественным" располагать информацию о каждой цели в одном месте, а не "распылять" ее по make-файлу.

Правило для очистки каталога

Компиляция программы - не единственная вещь, для которой вы, возможно, захотите написать правила. Часто, в make-файле указывается, каким образом можно выполнить некоторые другие действия, не относящиеся к компиляции программы. Таким действием, например, может быть удаление все объектных и исполняемых файлов программы для очистки каталога.

Вот как можно было бы написать правило для очистки каталога в нашем проекте текстового редактора:

clean:
        rm edit $(objects)

На практике, скорее всего, мы бы записали это правило чуть более сложным способом, предполагающим возможность непредвиденных ситуаций:

.PHONY : clean
clean :
        -rm edit $(objects)

Такая запись предотвратит возможную путаницу если, вдруг, в каталоге будет находится файл с именем `clean', а также позволит make продолжить работу, даже если команда rm завершится с ошибкой (смотрите раздел Абстрактные цели, а также раздел Ошибки при исполнении команд.)

Подобное правило не следует помещать в начало make-файла, поскольку мы не хотим, чтобы оно запускалось "по умолчанию"! В нашем примере, мы помещаем данное правило в конец make-файла, чтобы главной целью по умолчанию оставалась сборка файла edit.

Поскольку clean не является пререквизитом цели edit, это правило не будеть выполняться, если вызывать `make' без аргументов. Для запуска данного правила, нужно будет набрать `make clean'. Смотрите раздел Запуск make.

Создание make-файлов

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

Из чего состоят make-файлы

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

Имена make-файлов

По умолчанию, когда make ищет make-файл для обработки, она поочередно пробует найти файлы со следующими именами (в указанном порядке): `GNUmakefile', `makefile' и `Makefile'.

Обычно, вам имеет смысл давать своему make-файлу имя `makefile', либо `Makefile'. Мы рекомендуем использовать имя `Makefile', потому что при выводе содержимого каталога, файл с таким именем будет находится в начале списка, наряду с такими важными файлами как `README'. Первое из проверяемых имен - `GNUmakefile' - не может быть рекомендовано для большинсства make-файлов. Это имя можно использовать, если ваш make-файл специфичен для GNU make и не будет обрабатываться другими версиями make. Другие версии программы make ищут make-файлы с именами `makefile' и `Makefile', но не `GNUmakefile'.

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

Если вы хотите использовать "нестандартное" имя для вашего make-файла, вы можете указать его в командной строке, используя опции`-f' или `--file'. Аргументы`-f имя_файла' или `--file=имя_файла', указывают программе make на необходимость использования файла с именем имя_файла в качестве make-файла. Вы можете задать обработку сразу нескольких make-файлов, перечислив их в командной строке с помощь нескольких опций`-f' или `--file'. Все указанные таким образом make-файлы логически "объединяются" в том порядке, как они были заданы в командной строке. При наличии в командной строке опций`-f' или `--file', автоматического поиска make-файлов с именами `GNUmakefile', `makefile' и `Makefile', не производится.

Подключение других make-файлов

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

include имена_файлов...

Имена файлов могут представлять собой шаблоны имен, допустимые в интерпретаторе командной строки.

В начале строки могут находится дополнительные пробелы - все они будут игнорированы. Наличие символа табуляции в начале строки недопустимо, поскольку такие строки make считает командами. Между словом include и началом списка файлов, а также между именами файлов необходим пробел. Лишние пробелы между именами, а также пробелы после конца директивы, игнорируются. В конце строки с директивой может находится комментарий, начинающийся, как обычно, с символа `#'. Если имена файлов содержат ссылки на переменные или функции, то эти ссылки "раскрываются" (вместо них подставляются вычисленные значения). Смотрите раздел Использование переменных.

Если, например, у вас есть три файла с расширением `.mk' - `a.mk', `b.mk', и `c.mk', а переменная $(bar) ссылается на строку bish bash, то следующая запись

include foo *.mk $(bar)

будет эквивалентна

include foo a.mk b.mk c.mk bish bash

Когда make обрабатывает директиву include, она приостанавливает чтение текущего make-файла и поочередно читает каждый файл из списка, указанного в директиве. Когда весь список будет прочитан, make возвращается к обработке make-файла, в котором была встречена директива include.

Директива include может оказаться полезной если, предположим, у нас имеется несколько программ, собираемых при помощи отдельных make-файлов, которым требуется наличие некоторого "общего" набора определений переменных (смотрите раздел Установка значения переменной) или шаблонных правил (смотрите раздел Определение и переопределение шаблонных правил).

Другой случай, когда директива include может быть использована - это автоматическая генерация пререквизиттов для исходных файлов. Автоматически сгенерированные пререквизиты могут быть помещены в отдельный файл, который, затем, будет включаться в основной make-файл программы. Подобная практика, в целом, выглядит более привлекательной, чем "беспорядочное" добавление новых пререквизитов в конец главного make-файла, которое традиционно практикуется при работе с другими версиями make. Смотрите раздел Автоматическая генерация списка пререквизитов.

Если указанное в директиве имя начинается не с символа '/' и файл с таким именем отсутствует в текущей директории, производится его поиск еще в нескольких каталогах. Сначала поиск производится во всех каталогах, которые были указаны в командной строке с помощью опций `-I' и `--include-dir'(смотрите раздел Обзор опций). Затем, поиск производится поочередно в следующих директориях (если, конечно, они существуют): `prefix/include' (обычно `/usr/local/include' (1)) `/usr/gnu/include', `/usr/local/include', `/usr/include'.

Если поиск включаемого make-файла завершился неудачно, make выдает предупреждающее сообщение, которое, однако не является фатальной ошибкой, поскольку обработка make-файла, содержащего директиву include, еще продолжается. После того, как все включаемые файлы будут прочитаны, make попытается создать или обновить те из них, которые не существуют или устарели. Смотрите раздел Автоматическое обновление make-файлов. Только после неудачной попытки найти способ создания отсутствующих make-файлов, ситуация будет квалифицирована как фатальная ошибка и make завершит работу.

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

-include имена_файлов...

Эта директива работает аналогично директиве include, за исключением того, что отсутствие включаемых make-файлов имена_файлов не вызывает ошибки (даже не выдается каких-либо предупреждающих сообщений). Для совместимости с другими версиями make, директива -include имеет второе, дополнительное имя sinclude.

Переменная MAKEFILES

Если среди переменных среды (environment variables) имеется переменная с именем MAKEFILES, то ее содержимое интерпретируется как список имен (разделенных пробелами) дополнительных make-файлов, которые должны быть прочитаны перед тем, как начнут обрабатываться "основные" make-файлы. Этот механизм работает во многом аналогично директиве include. Аналогичным образом производится и поиск этих дополнительных make-файлов в разных каталогах (смотрите раздел Подключение других make-файлов). При этом, главная цель не может браться из этих файлов, а отсутствие какого-либо из них не рассматривается как ошибка.

Одно из основных применений переменной MAKEFILES - это организация "связи" между рекурсивными вызовами make (смотрите раздел Рекурсивный вызов make). Обычно, нежелательно устанавливать переменную MAKEFILES перед первым вызовом make (на самом "высоком" уровне), чтобы не создавать причудливую "смесь" из основного make-файла и файлов, перечисленных в MAKEFILES. Однако, если вы запускаете make без указания конкретного make-файла, дополнительные make-файлы, перечисленные в MAKEFILES могут сделать что-нибудь полезное в помощь встроенным в make неявным правилам, например, задать нужные пути поиска (смотрите раздел Поиск пререквизитов по каталогам).

Некоторые пользователя соблазняются возможностью автоматически устанавливать переменную MAKEFILES при входе в систему, и пишут свои make-файлы в рассчете на это. Делать этого категорически не рекомендуется, поскольку такие make-файлы не будут работать при попытке их использования другими пользователями. Гораздо лучше, явно подключать нужные make-файлы с помощью обычной директивы include. Смотрите раздел Подключение других make-файлов .

Автоматическое обновление make-файлов

Иногда make-файлы могут быть получены из других файлов, таких как файлы RCS или SCCS. Если make-файл может быть получен из других файлов, скорее всего, вы захотите, чтобы make всегда работала с самой "свежей" версией этого файла.

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

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

Если в make-файле для обновления файла имеется правило с двойным двоеточием (double-colon rule), не имеющее пререквизитов, то этот файл всегда будет обновляться (смотрите раздел Правила с двойным двоеточием). В случае, если бы целью такого правила являлся make-файл, мог бы возникнуть бесконечный цикл: make-файл все время бы обновлялся, что, в свою очередь, заставляло бы make заново перечитывать все make-файлы и так далее, до бесконечности. Поэтому, во избежание зацикливания, make не пытается обновить make-файлы, которые являются целями правил с двойным двоеточием без пререквизитов.

В том случае, если при запуске make, ей не были указаны make-файлы для обработки (с помощью опций `-f' и `--file'), то утилита попытается найти подходящий make-файл, поочередно пробую принятые по умолчанию имена make-файлов (смотрите раздел Имена make-файлов). В отличие от make-файлов, указываемых с помощью опций `-f' и `--file', make не может быть уверена, что эти файлы вообще существуют. Однако, если make-файл с именем, принятым по умолчанию, в данный момент не существует, но может быть построен с использованием каких-либо известных make правил, то вы, скорее всего захотите, чтобы эти правила были выполнены и нужный make-файл был создан.

Поэтому, если ни один из make-файлов с принятыми по умолчанию именами не существует, make предпринимает попытку создать их (в том же самом порядке, каком происходил их поиск). Смотрите раздел Имена make-файлов . Эти попытки продолжаются до тех пор, пока какой-либо из make-файлов не будет создан, либо make "перепробует" все имена make-файлов, принятых по умолчанию. Заметьте, что невозможность найти или построить make-файл не является ошибкой, поскольку наличие make-файла не является обязательным условием работы make.

При использовании опций `-t' или `--touch' (смотрите раздел Вместо исполнения команд), вряд ли вы захотите оказаться в ситуации, когда для определения того, какие цели нужно пометить как обновленные, будет использована устаревшая версия make-файла. Поэтому, опция `-t' не оказывает влияния на процедуру обновления make-файлов - они обновляются даже тогда, когда она указана. Аналогично, опции `-q' (или `--question') и`-n' (или `--just-print') не отменяют процедуру обновления файлов; в противном случае, использование устаревшей версии make-файла могло бы вызвать некорректную работу этих опций. Таким образом, при обработке `make -f mfile -n foo', файл `mfile' будет обновлен, затем он будет перечитан заново, и, после этого, будут напечатаны команды, обновляющие цель `foo' и ее пререквизиты. Эти команды будут соответствовать работе с обновленной версией `mfile'.

Однако, в определенных ситуациях, вам может понадобиться избежать обновления make-файлов. Вы может сделать это, указав в командной строке эти файлы в качестве целей и, одновременно, указать их (с помощью опций `-f' и `--file') в качестве make-файлов. Когда make-файл явно указан в командной строке в качестве цели, опция `-t' и аналогичные опции, могут быть к нему применены.

Таким образом, при обработке `make -f mfile -n mfile foo' будет прочитан make-файл `mfile', затем будут напечатаны команды, требуемые для его обновления (без их реального исполнения), и, затем, будут напечатаны команды, необходимые для обновления `foo' (также без их выполнения). Команды для обновления `foo' будут соответствовать нынешнему состоянию `mfile'.

"Перекрытие" (overriding) части make-файла

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

Во "внешнем" make-файле (make-файле, который включает в себя другие make-файлы) вы можете задать шаблонное правило с произвольным соответствием (match-anything pattern rule), которое будет указывать, что цели, не описанные в данном make-файле, следут поискать в другом make-файле. Смотрите раздел Определение и переопределение шаблонных правил, где подробно описаны шаблонные правила.

Например, если у нас имеется make-файл с именем `Makefile', который описывает цель `foo' (и другие цели), то мы можем написать make-файл с именем `GNUmakefile', который будет содержать следующие строки:

foo:
        frobnicate > foo

%: force
        @$(MAKE) -f Makefile $@
force: ;

В таком случае, при выполнении команды `make foo', make считает файл `GNUmakefile', и увидит, что для достижения цели `foo', должна быть выполнена команда`frobnicate > foo'. При выполнении команды `make bar', make увидит, что цель `bar' не описана в make-файле `GNUmakefile', и, поэтому, использует команду из шаблонного правила:`make -f Makefile bar'. Если `Makefile' содержит правило для цели `bar', то эта цель будет обновлена. Аналогично make поступит и с любыми другими целями, не описанными в `GNUmakefile'

В данном примере, шаблонное правило содержит лишь`%', поэтому любая цель подходит под такой шаблон. Пререквизит `force' указан лишь для того, чтобы команды из данного правила выполнялись всегда - даже в том случае, если целевой файл уже существует. Правило, описывающее цель `force', содержит пустую команду для того, чтобы make не пыталась использовать неявное правило для обновления этой цели (иначе возник бы бесконечный цикл, поскольку для обновления `force', make попыталась бы использовать то же самое шаблонное правило).

Как make читает make-файл

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

Понимание такой двухпроходной схемы является важным, поскольку она оказывает непосредственное влияние на ход вычисления переменных и функций; непонимание, зачастую, является источником недоразумений при написании make-файлов. Здесь мы опишем, как происходит "пофазная" обработка различных конструкций. Мы будем говорить, что расширение (expansion) является немедленным (immediate), если оно производится во время первой фазы работы: это означает, make будет вычислять переменные и функции в момент считывания и "разбора" make-файла. Мы будем говорить, что расширение является отложенным (deferred), если оно не происходит "немедленно". Расширение отложенной конструкции не происходит до тех пор, пока эта конструкция не встретится позже, уже в "немедленном" контексте, либо она будет расширена на втором проходе.

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

Присваивание значения переменным

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

немедленно = отложенно
немедленно ?= отложенно
немедленно := немедленно
немедленно += отложенно или немедленно

define немедленно
  отложенно
endef

В операторе добавления, `+=', правая часть обрабатывается "немедленно", если переменная была ранее определена как упрощенно вычисляемая (с помощью `:=') и "отложенно" в противном случае.

Условные конструкции

Все условные конструкции (во всех формах - ifdef, ifeq, ifndef и ifneq) целиком и полностью обрабатываются "немедленно".

Определения правил

Правила всегда обрабатываются одинаковым образом, независимо от их формы:

немедленно : немедленно ; отложенно
    отложенно

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

Составление правил (rules)

Правила (rules) содержатся в make-файле и описывают, когда и каким образом должны быть обновлены или созданы некоторые файлы, называемые целями (targets). Чаще всего, каждое правило содержит только одну цель. В правиле перечисляются файлы, которые являются пререквизитами (prerequisites) для этой цели и команды, которые должны быть выполнены для создания или обновления цели.

Порядок следования правил внутри make-файле не имеет значения. Исключение составляет лишь выбор главной цели по умолчанию (default goal) - цели, к которой стремиться make, если вы не задали ее явно. По умолчанию, главной целью становиться цель из первого правила в первом обрабатываемом make-файле. Если это правило содержит несколько целей, то только первая из них становится главной целью. Здесь есть два исключения. Во-первых, главными целями, выбираемыми по умолчанию, не могут стать цели, имя которых начинается с точки (если только они не содержат по крайней мере одного символа `/'). И, во-вторых, из процесса выбора главной цели исключаются шаблонные правила (смотрите раздел Определение и переопределение шаблонных правил).

Поэтому, мы обычно пишем make-файлы таким образом, чтобы первое правило описывало процесс сборки готовой программы, или всех программ, описываемых в этом make-файле (часто, для этого используется цель с именем`all'). Смотрите раздел Аргументы для задания главной цели.

Синтаксис правил

В общем виде, правило выглядит так:

цели : пререквизиты
        команда
        ...

или так:

цели : пререквизиты ; команда
        команда
        ...

Цели (targets) - это имена файлов, разделенные пробелами. В именах целей могут быть использованы шаблонные символы (смотрите раздел Использование шаблонных символов в именах файлов). Для файлов, содержащихся в архиве, может быть использована специальная форма записи: `a(m)', где a - это имя архивного файла, а m - имя содержащегося в нем файла (смотрите раздел Использование элементов архива в качестве целей). Обычно, в правиле содержится только одна цель, однако, иногда имеет смысл задать несколько целей в одном правиле (смотрите раздел Правила с несколькими целями).

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

Поскольку знак доллара используется для ссылки на переменные, для использования его в правилах, нужно писать `$$'(смотрите раздел Использование переменных). Длинные строки make-файла могут быть разделены на части с помощью символа '\', находящегося в конце строки. Это может повысить удобочитаемость make-файла, но "технической" необходимости в этом нет - make никак не ограничивает длину строк make-файла.

Правило содержит информацию о двух вещах: когда следует считать, что цель "устарела", и каким образом она может быть обновлена при возникновении такой необходимости.

Критерий "устаревания" вычисляется по отношению к пререквизитам, которые представляют из себя имена файлов, разделенные пробелами. В именах пререквизитов могут использоваться шаблонные символы. Пререквизиты также могут быть файлами, находящимися в архивах (смотрите раздел Использование make для обновления архивов). Цель считается "устаревшей", если такого файла не существует, либо он "старше", чем какой-либо из пререквизитов (проверяется время последней модефикации файла). Смысл здесь в том, что, поскольку целевой файл строится на основе информации из файлов-пререквизитов, то изменение хотя бы одного из них может привести к тому, что содержимое целевого файла уже не будет "правильным".

Команды указывают на то, каким образом следует обновлять цель. Это - просто строки (с некоторыми дополнительными возможностями), исполняемые интерпретатором командной строки (обычно `sh'). Смотрите раздел Написание команд.

Использование шаблонных символов (wildcard characters) в именах файлов

При использованием шаблонных символов (wildcard characters), с помощью одного имени можно задать целую группу файлов. В make шаблонными символами являются`*', `?' и `[...]' (как в оболочке Bourne). Например, шаблон `*.c' будет соответствовать всем файлам с суффиксом `.c', находящимся в текущей директории.

Символ `~' в начале имени файла, также имеет специальное значение. Одиночный символ `~' или сочетание `~/' означает ваш домашний каталог. Например, выражение `~/bin' будет означать `/home/you/bin'. Если сразу за символом`~' следует некоторое имя, такая строка будет представлять собой домашнюю директорию пользователя с этим именем. Например, строка `~john/bin' будет означать `/home/john/bin'. В системах, где пользователи не имеют своего домашнего каталога (таких как MS-DOS или MS-Windows), такое поведение может эмулироваться с помощью установки переменной окружения HOME.

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

Специальное значение шаблонных символов может быть "отключено" с помощью предшествующего им символа '\'. Таким образом, строка `foo\*bar' будет ссылаться на довольно странное имя, состоящее из семи символов - начального `foo', звездочки и `bar'.

Примеры шаблонных имен

Шаблонные имена могут быть использованы в командах, которые содержатся в правилах. Такие имена будут "раскрыты" интерпретатором командной строки. Вот пример правила для удаления всех объектных файлов из текущей директории:

clean:
        rm -f *.o

Шаблоны также могут быть полезны в качестве пререквизитов правил. В следующем примере, команда `make print' вызовет печать всех файлов с исходными текстами (файлов с расширением `.c'), которые были модефицированы с тех пор, как вы последний раз распечатывали их подобным образом:

print: *.c
        lpr -p $?
        touch print

В данном правиле, цель `print' является пустой целью (empty target file); смотрите раздел Использование пустых целей для фиксации событий. Автоматичесая переменная `$?' используется для печати только тех пререквизитов, которые были изменены (смотрите раздел Автоматические переменные.)

При задании переменной, раскрытия шаблонов не производится. Например, если вы запишите:

objects = *.o

то значением переменной objects будет строка `*.o'. Однако, если вы используете значение переменной objects в цели, в пререквизите или в команде, то в момент использования шаблона, будет произведено его расширение. Чтобы присвоить переменной objects значение, полученное после расширения шаблона, используйте функцию wildcard:

objects := $(wildcard *.o)

Смотрите раздел Функция wildcard.

Проблемы при использовании шаблонных имен

Вот простой пример "неправильного" использования шаблонного имени, результат которого совершенно отличен от ожидаемого. Предположим, составляя make-файл, вы хотели сказать, что исполняемый файл `foo' собирается из всех объектных файлов, находящихся в текущем каталоге, и записали это следующим образом:

objects = *.o

foo : $(objects)
        cc -o foo $(CFLAGS) $(objects)

При такой записи, переменная objects получит значение `*.o'. Расширение шаблона `*.o' будет произведено только при обработке правила с `foo', и пререквизитами этой цели станут все существующие в данный момент файлы `.o'. При необходимости, эти объектные файлы будут перекомпилированы.

Но что будет, если вы удалите все файлы с расширением `.o'? Когда шаблону не соответствует ни один файл, этот шаблон остается в "первоначальном" виде. И, таким образом, получится что цель `foo' будет зависеть от файла со странным именем `*.o'. Поскольку, такого файла на самом деле не существует, make аварийно завершит работу, выдав сообщение, что она не знает как построить файл `*.o'. Пожалуй, это совсем не то, чего вы хотели добиться!

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

В операционных системах фирмы Microsoft для разделения имен директорий используется символ '\':

  c:\foo\bar\baz.c

Приведенное выше имя эквивалентно имени `c:/foo/bar/baz.c' в стиле Unix (здесь `c:' - это, так называемое, имя диска). Когда программа make работает в таких операционных системах, она допускает использование обоих символов ('/' и '\') в именах файлов. Поддержка символа '\' не распространяется, однако, на шаблонные имена, где этот символ имеет специальное значение. В таких случаях, вы должны использовать имена в стиле Unix (с символом '/' в качестве "разделителя").

Функция wildcard

Шаблонные имена автоматически "расширяются" при обработке правил, где они использованы. В других случаях, например, при присваивании переменной нового значения, или в аргументах функций, такого расширения не производится. Для "принудительного" расширения шаблонных имен в любых нужных местах, предназначена функция wildcard, которая выглядит следующим образом:

$(wildcard шаблон...)

Подобная строка, будучи использована в любом месте make-файла, будет заменена списком существующих в данный момент файлов, которые удовлетворяет указанному шаблону (шаблонам). Имена файлов отделяются друг от друга пробелами. В том случае, если не будет найдено файлов, удовлетворяющих заданному шаблону, функция возвращает пустую строку. Заметьте, что такое поведение функции wildcard отличается от поведения обычных шаблонов в правилах, которые, в таких случаях, остаются в исходном виде, а не игнорируются (смотрите раздел Проблемы при использовании шаблонных имен).

Одно из возможных применений фукнции wildcard - это получение списка исходных файлов, находящихся в текущем каталоге, например:

$(wildcard *.c)

Затем, мы может превратить список исходных файлов в список объектных файлов, заменив их расширение с `.c' на `.o', например:

$(patsubst %.c,%.o,$(wildcard *.c))

(Здесь, для замены текста, мы использовали функцию patsubst. Смотрите раздел Функции анализа и подстановки строк.)

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

objects := $(patsubst %.c,%.o,$(wildcard *.c))

foo : $(objects)
        cc -o foo $(objects)

В этом make-файле для компиляции исходных текстов используются неявные правила компиляции программ на языке Си, поэтому нет необходимости в явном описании правил компиляции. Смотрите раздел Две разновидности переменных, где описывается оператор `:=', который является вариантом "стандартного" оператора`='.

Поиск пререквизитов по каталогам

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

Переменная VPATH: список каталогов для поиска пререквизитов

Значение переменной VPATH указывает утилите make список директорий, где следует производить поиск файлов. Чаще всего, этот путь представляет собой список каталогов с файлами, которые являются пререквизитами каких-либо правил и находятся не в текущем каталоге. Однако, содержимое переменной VPATH используется для поиска любых файлов (а не только пререквизитов), в том числе и файлов, которые являются целями каких-либо правил.

Таким образом, если файл, который является целью или пререквизитом, не найден в текущем каталоге, make предпримет попытку найти его в каталогах, перечисленных в VPATH. Если в одном из этих каталогов файл будет найден, он может стать пререквизитом (смотрите ниже). Учитывая это, правила могут составляться таким образом, что имена пререквизитов указываются так, как если бы они находились в текущем каталоге. Смотрите раздел Написание команд с учетом поиска по каталогам.

Имена перечисленных в VPATH каталогов, отделяются друг от друга пробелами или двоеточиями. При поиске, make перебирает каталоги в том порядке, как они перечислены в переменной VPATH. В операционных системах MS-DOS и MS-Windows для разделения имен директорий вместо символа двоеточия, должен использоваться символ точки с запятой (поскольку символ ':' может быть частью названия каталога, находясь после имени диска).

Например, следующая запись:

VPATH = src:../headers

указывает, что путь поиска состоит из двух каталогов, `src' и `../headers'. Поиск в этих каталогах производится в указанном порядке.

При таком значении переменной VPATH, следующее правило,

foo.o : foo.c

будет интерпретировано так, как будто он записано следующим образом:

foo.o : src/foo.c

если предположить, что файл `foo.c' находится не в текущей директории, а в каталоге `src'.

Директива vpath

Средством, аналогичным переменной VPATH, но только более "избирательным", является директива vpath (обратите внимание на нижний регистр букв). Эта директива позволяет задать пути поиска для некоторой группы файлов, а именно, файлов, чье имя подходит под определенный шаблон. Таким образом, вы можете задать некоторый список каталогов поиска для одной группы файлов, и совсем другой список - для других файлов.

Имеется три формы записи директивы vpath:

vpath шаблон каталоги
Задать путь поиска каталоги для файлов, чье имя удовлетворяет шаблону шаблон. Путь поиска каталоги - это список имен директорий, разделенных двоеточиями (точкой запятой в MS-DOS или MS-Windows) или пробелами, подобно списку поиска переменной VPATH.
vpath шаблон
Очистить ("забыть") пути поиска для шаблона шаблон.
vpath
Очистить ("забыть") все пути поиска, ранее определенные с помощью директивы vpath

В директиве vpath, шаблон представляет собой строку, содержащую символ `%'. Имя искомого файла должно соответствовать этой шаблонной строке, причем символ `%', как и в шаблонных правилах (смотрите раздел Определение и переопределение шаблонных правил), может соответствовать любой последовательности символов (в том числе и пустой). Например, шаблону %.h удовлетворяют имена файлов, имеющие расширение .h. (Если шаблон не содержит символа `%', он должен в точности совпадать с именем искомого файла, а необходимость в этом возникает достаточно редко.)

Специальное значение символа `%' в шаблоне директивы vpath может быть отменено с помощью предшествующего ему символа`\'. Специальное значение символа `\', предшествующего символу `%' может быть, в свою очередь, отменено добавлением еще одного символа `\' (строка "\\%" будет интерпретироваться как два символа. Первый из них - символ `\', второй - символ `%', который будет интерпретироваться как шаблонный). Символы `\', имеющие специальное значение, удаляются из шаблона перед тем, как он будет сравниваться с именами файлов. Символы `\' не имеющие специального значения, остаются в шаблоне.

Если искомого пререквизита нет в текущей директории, а его имя удовлетворяет шаблону, указанному в директиве vpath, предпринимается попытка найти его в каталогах, список которых указан в этой директиве. Поиск проходит аналогично поиску в каталогах, перечисленных в переменной VPATH, и предшествует ему.

Например, запись

vpath %.h ../headers

инструктирует make, производить поиск пререквизитов с расширением `.h' в каталоге `../headers', если они не могут быть найдены в текущей директории.

Если имя искомого пререквизита подходит сразу под несколько шаблонов, указанных в директивах vpath, make обрабатывает эти директивы поочередно, друг за другом, производя поиск во всех каталогах, перечисленных в каждой из них. Отдельные директивы vpath обрабатываются в том порядке, как они расположены в make-файле; несколько директив с одинаковым шаблоном никак не влияют друг на друга.

Например, в случае:

vpath %.c foo
vpath %   blish
vpath %.c bar

поиск файла с раширением `.c' будет происходить в каталоге `foo', затем `blish', и, наконец `bar', а в случае

vpath %.c foo:bar
vpath %   blish

поиск такого файла будет производиться в каталоге `foo', затем `bar', и затем `blish'.

Процедура поиска по каталогам

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

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

  1. Если целевой файл не может быть найден в директории, которая указана в make-файле, проводится его поиск по каталогам.
  2. Если поиск завершился успешно, найденный путь запоминается и искомый целевой файл временно помечается как найденная цель.
  3. Используя этот же метод, проверяются все пререквизиты данной цели.
  4. После обработки всех пререквизитов, для цели, возможно потребуется ее обновление:
    1. Если цель не нуждается в обновлении, директория, найденная в процессе поиска по каталогам, используется для всех пререквизитов этой цели. Иначе говоря, если цель не нуждается в обновлении, то используется директория, найденная в процессе поиска по каталогам.
    2. Если цель нуждается в обновлении (является устаревшей), то найденный в процессе поиска по каталогам путь отбрасывается, и цель обновляется с использовании только ее имени, указанном в make-файле. Другими словами, если make должна обновить цель, то эта цель строится или обновляется "локально", а не в той директории, которая была найдена во время поиска по каталогам.

Хотя этот алгоритм и выглядит сложным, на практике, он, как правило, дает именно тот результат, который вы и ожидали.

Другии версии make используют более простой алгоритм: если файла нет в текущей директории, но он был найден в процесс поиска по каталогам, установленный таким образом путь к этому файлу используется всегда, независимо от того, нуждается ли цель в обновлении или нет. Таким образом, при обновлении цели, новая версия файла будет расположена по тому же пути, где была найдена и "старая" версия.

Если для вас желательно именно такое поведение make по отношению к некоторым (или всем) каталогам, вы можете использовать переменную GPATH.

Для переменной GPATH используется такой же синтаксис, что и для VPATH (список имен каталогов, разделенных пробелами или двоеточиями). Если "устаревший" целевой файл был найден в результате проведения поиска по каталогам, и найденный путь присутствует в списке GPATH, он не будет "отброшен". Далее, цель будет обновлена именно по этому пути.

Написание команд с учетом поиска по каталогам

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

Это может быть сделано с использованием автоматических переменных, таких как `$^'(смотрите раздел Автоматические переменные). Например, значением переменной `$^' является список всех пререквизитов правила с именами каталогов, где эти пререквизиты были найдены, а значением переменной`$@' является имя цели. Например:

foo.o : foo.c
        cc -c $(CFLAGS) $^ -o $@

(Переменная CFLAGS используется для того, чтобы иметь возможность указать опции компиляции исходных текстов на Си для неявных правил; в данном случае мы использовали ее просто в целях "унификации" процесса компиляции (смотрите раздел Используемые в неявных правилах переменные).

Часто, в список пререквизитов попадают файлы, которые не нужно передавать в исполняемую команду (например, заголовочные файлы). В такой ситуации можно использовать автоматическую переменную `$<', которая содержит лишь первый пререквизит правила:

VPATH = src:../headers
foo.o : foo.c defs.h hack.h
        cc -c $(CFLAGS) $< -o $@

Поиск в каталогах и неявные правила

Поиск в каталогах, указанных с помощью VPATH или vpath происходит также и при использовании неявных правил (смотрите раздел Использование неявных правил).

Например, если для файла `foo.o' не имеется явных правил, то make пробует использовать имеющиеся у нее неявные правила, в частности, правило, говорящее что для получения `foo.o', надо скомпилировать файл `foo.c' (если, конечно, такой файл существует). Если искомого файла нет в текущей директории, то make предпринимает его поиск по каталогам. Если файл `foo.c' будет найден в каком-либо из каталогов (или упомянут в make-файле), то к нему будет применено соответствующее неявное правило для компиляции программ на языке Си.

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

Поиск в каталогах для подключаемых библиотек

Поиск в каталогах может производиться специальным образом для файлов, являющихся библиотеками. Эта специфическая особенность вступает в силу для пререквизитов, чье имя имеет специальную форму`-lимя'. (Возможно, вам это покажется странным, поскольку пререквизит, обычно, является именем файла, а файл библиотеки имя, как правило, называется `libимя.a', а не `-lимя'.)

Когда имя пререквизита имеет форму `-lимя', make обрабатывает ее специальным образом, производя поиск файла с именем `libимя.so' сначала в текущей директории, затем в каталогах, перечисленных в подходящих директивах vpath, каталогах из VPATH, и, наконец, в каталогах `/lib', `/usr/lib', и `prefix/lib' (обычно `/usr/local/lib', но версии make для операционных систем MS-DOS/MS-Windows ведут себя так, как если бы prefix был корневым каталогом, где инсталлирован компилятор DJGPP).

Если такой файл не обнаружен, предпринимается попытка найти файл `libимя.a' (в перечисленных выше каталогах).

Так, если в вашей системе имеется библиотека `/usr/lib/libcurses.a' (и отсутствует файл `/usr/lib/libcurses.so'), то в следующем примере:

foo : foo.c -lcurses
        cc $^ -o $@

будет выполнена команда `cc foo.c /usr/lib/libcurses.a -o foo' если `foo' "старше" чем `foo.c' или `/usr/lib/libcurses.a'.

Хотя, по умолчанию проводится поиск файлов с именами `libимя.so' и `libимя.a', это поведение может быть изменено с помощью переменной .LIBPATTERNS. Каждое слово в значении этой переменной рассматривается как шаблонная строка. Встретив пререквизит вида`-lимя', make заменяет символ процента в каждом из шаблонов на имя и производит описанную выше процедуру поиска для полученного имени библиотечного файла. Если библиотечный файл не найден, используется следующий шаблон из списка и так далее.

По умолчанию, значением переменной .LIBPATTERNS является строка "`lib%.so lib%.a'", которая и обеспечивает описанное выше поведение.

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

Абстрактные цели (phony targets)

Абстрактная цель (phony target) - это цель, которая не является, на самом деле, именем файла. Это - просто имя для некоторой последовательности команд, которую при необходимости может выполнить make. Есть по крайней мере два соображения в пользу использования абстрактных целей: их использование позволяет избежать конфликтов с файлами, имеющими такое же имя, а также ускорить работу make.

Если вы напишите правило, которое не будет порождать указанный в нем целевой файл, то команды этого правила будут выполняться всякий раз при попытке достижения цели правила. Например:

clean:
        rm *.o temp

Поскольку исполнение команды rm не приводит к созданию файла `clean', такой файл, скорее всего, вообще не будет существовать. В таком случае, команда rm будет выполняться всякий раз, когда вы скажете `make clean'.

Однако, правило с такой "псевдо-целью" откажется работать, если в текущем каталоге по какой-нибудь причине окажется файл с именем `clean'. Поскольку в правиле не указано каких-либо пререквизитов, файл `clean' всегда будет считаться "новым" и команды, указанные в правиле никогда не выполнятся. Во избежании подобной проблемы, вы можете прямо указать, что некоторая цель является абстрактной. Для этого используется специальная цель .PHONY (смотрите раздел Имена специальных целей). В нашем примере достаточно записать:

.PHONY : clean

После этого, вызов `make clean' будет приводить к исполнению нужных команд, независимо от того, существует файл `clean' или нет.

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

Таким образом, сначала должна идти строка, объявляющая clean абстрактной целью, а затем уже следует правило, описывающее эту цель:

.PHONY: clean
clean:
        rm *.o temp

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

SUBDIRS = foo bar baz

subdirs:
        for dir in $(SUBDIRS); do \
          $(MAKE) -C $$dir; \
        done

Такому методу, однако, присущи некоторые недостатки. Во-первых, любые ошибки, возникшие при обработке подпроектов, останутся "незамеченными" - при возникновении ошибки в подпроекте make будет продолжать обработку оставшихся подкаталогов "как ни в чем ни бывало". Разумеется, в цикл можно ввести дополнительный код, который будет детектировать ошибочные ситуации и прерывать работу. К сожалению, при запуске make с опцией -k, такое поведение будет нежелательно. Второй недостаток, (возможно, более серьезный) состоит в том, что при таком подходе нельзя задействовать возможность "параллельной" работы make (из-за наличия единственного правила).

Объявив подкаталоги абстрактными целями (вы должны это сделать так как подкаталоги проектов обычно уже существуют и иначе они не стали бы обрабатываться) вы можете решить эти проблемы:

SUBDIRS = foo bar baz

.PHONY: subdirs $(SUBDIRS)

subdirs: $(SUBDIRS)

$(SUBDIRS):
        $(MAKE) -C $

foo: baz

Мы также объявили, что подкаталог `foo' не может быть обработан до тех пор, пока не будет закончена обработка подкаталога `baz'; подобного рода декларация потребуется для случая "параллельной" работы.

Как правило, абстрактная цель не должна быть пререквизитом какого-либо целевого файла, в противном случае указанные в подобном правиле команды будут исполняться всякий раз при его обработке. Если абстрактная цель не является пререквизитом какого-либо реального файла, команды из правила, где она описана, будут исполняться только в том случае, когда эта цель будет указана в качестве главной (смотрите раздел Аргументы для задания главной цели).

Абстрактные цели могут иметь пререквизиты. Например, когда в одном каталоге содержится сразу несколько собираемых программ, удобно хранить их описания в одном make-файле. Так как главной целью по умолчанию становится первая цель из make-файла, в таких случаях, обычно, первым правилом make-файла делают правило с абстрактной целью`all', пререквизитами которой являются все собираемые программы. Например:

all : prog1 prog2 prog3
.PHONY : all

prog1 : prog1.o utils.o
        cc -o prog1 prog1.o utils.o

prog2 : prog2.o
        cc -o prog2 prog2.o

prog3 : prog3.o sort.o utils.o
        cc -o prog3 prog3.o sort.o utils.o

Теперь вам достаточно сказать `make', чтобы обновить все три программы, или указать нужные аргументы для обновления конкретных программ (например, `make prog1 prog3').

Когда одна абстрактная цель является пререквизитом другой абстрактной цели, она работает как своего рода "подпрограмма". В следующем примере, `make cleanall' удалит объектные файлы, diff-файлы, и файл `program':

.PHONY: cleanall cleanobj cleandiff

cleanall : cleanobj cleandiff
        rm program

cleanobj :
        rm *.o

cleandiff :
        rm *.diff

Правила без команд и пререквизитов

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

Например:

clean: FORCE
        rm $(objects)
FORCE:

Здесь, цель `FORCE' удовлетворяет специальным условиям (не имеет пререквизитов и команд). Цель `clean' зависит от `FORCE', поэтому команды из правила с `clean' вынуждены будут выполняться. В имени`FORCE' нет ничего "необычного", просто оно часто используется для подобных целей.

Очевидно, что такое использование `FORCE' эквивалентно объявлению цели clean абстрактной, с помощью`.PHONY: clean'.

Подход с использованием `.PHONY' более понятен и эффективен, однако другие версии make могут не поддерживать `.PHONY'. В силу этой причины, во многих make-файлах используется`FORCE'. Смотрите раздел Абстрактные цели.

Использование пустых целей (empty target files) для фиксации событий

Пустая цель (empty target) является вариантом абстрактной цели. Такие цели используются для хранения команд, исполняющих действие, выполнение которого вам может иногда потребоваться. В отличие от астрактных целей, пустая цель действительно может существовать в виде файла. Однако, содержимое такого файла никоим образом не используется, и, зачастую, он просто пуст.

Назначение подобной цели - запомнить (с помощью времени последней модефикации), когда последний раз исполнялись указанные в правиле команды. Это делается при помощи включения в список команд, содержащихся в правиле, команды touch, обновляющей эту цель.

Пустая цель должна иметь какие-нибудь пререквизиты (иначе в ней нет смысла). Когда вы запрашиваете обновление этой цели, команды из ее правила будут выполняться, если какой-либо из пререквизитов "новее", чем цель. Другими словами, команды будут выполняться если какой-либо из пререквизитов был обновлен со времени последнего обновления цели. Например:

print: foo.c bar.c
        lpr -p $?
        touch print

С таким правилом, `make print' приведет к выполнению команды lpr, если какой-нибудь из исходных файлов был изменен с момента последнего вызова `make print'. Автоматическая переменная `$?' использована для того, чтобы печатать только те исходные файлы, которые были изменены (смотрите раздел Автоматические переменные).

Имена специальных целей

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

.PHONY
Пререквизиты специальной цели .PHONY объявляются абстрактными целями. При необходимости обновления таких целей, make будет выполнять команды "безусловно", независимо от того, существует ли файл с таким именем, и времени, когда он был модефицирован. Смотрите раздел Абстрактные цели.
.SUFFIXES
Пререквизиты специальной цели .SUFFIXES представляют собой список суффиксов (расширений) имен файлов, которые будут использоваться при поиске суффиксных правил. Смотрите раздел Устаревшие суффиксные правила.
.DEFAULT
Команды, определенные для цели .DEFAULT, будут использованы со всеми целями make-файла, для которых не найдено ни явных, ни неявных правил. Смотрите раздел Определение правил "последнего шанса". Команды, определенные для .DEFAULT, будут использованы для всех пререквизитов, не являющихся целями каких-либо правил. Смотрите раздел Алгоритм поиска неявных правил.
.PRECIOUS
Цели, перечисленные в качестве пререквизитов .PRECIOUS, подвергаются специальной обработке. В том случае, если make будет принудительно завершена или прервана во время исполнения команд для их обновления, эти цели не будут удалены. Смотрите раздел Прерывание или принудительное завершение make. Также, если цель является "промежуточным" файлов, он не будет, как обычно, удаляться после того, как необходимость в нем отпала. Смотрите раздел "Цепочки" неявных правил. В последнем случае, эта специальная цель работает подобно .SECONDARY. В качестве пререквизита .PRECIOUS может быть указан шаблон имени (например, `%.o'), что позволит сохранять все промежуточные файлы с именами, удовлетворяющими этому шаблону.
.INTERMEDIATE
Пререквизиты цели .INTERMEDIATE рассматриваются как промежуточные файлы. Смотрите раздел "Цепочки" неявных правил. .INTERMEDIATE без списка пререквизитов не производит никакого эффекта.
.SECONDARY
Цели, указанные в качестве пререквизитов .SECONDARY рассматриваются как промежуточные файлы, за исключением того, что они никогда не удаляются автоматически. Смотрите раздел "Цепочки" неявных правил. .SECONDARY без указания пререквизитов, помечает таким образом все цели, перечисленные в make-файле.
.DELETE_ON_ERROR
При наличии в make-файле цели с именем .DELETE_ON_ERROR, make будет удалять цель правила если она была модефицированы, а обновляющая ее команда завершилась с ненулевым кодом возврата; аналогично, цель будет удаляться при прерывании работы make. Смотрите раздел Ошибки при исполнении команд.
.IGNORE
make будет игнорировать ошибки при выполнении команд, обновляющих цели, перечисленные в качестве пререквизитов .IGNORE. Команды, указываемые для .IGNORE, не имеют значения. Использование .IGNORE без списка пререквизитов, означает необходимость игнорирования ошибок во всех командах, исполняемых для обновления любой цели make-файла. Такое использование `.IGNORE' поддерживается только по историческим соображениям для обеспечения совместимости. Этот прием не слишком полезен, поскольку воздействует на любую команду make-файла; вместо этого, мы рекомендуем использовать более "избирательный" метод, позволяющий игнорировать ошибки в конкретных командах. Смотрите раздел Ошибки при исполнении команд.
.SILENT
Если вы указали некоторые цели в качестве пререквизитов .SILENT, то в процессе обновления этих целей, make не будет печатать выполняемые при этом команды. Указываемые для .SILENT команды не имеют значения. В случае использования .SILENT без списка пререквизитов, будет отключена печать всех исполняемых команд. Такое использование `.SILENT' поддерживается только по историческим причинам, для обеспечения совместимости. Мы рекомендуем использовать более избирательный метод для подавления печати отдельных команд. Смотрите раздел Отображение исполняемых команд. Временно подавить печать исполняемых команд можно, запуская make с опциями `-s' или `--silent'(смотрите раздел Обзор опций).
.EXPORT_ALL_VARIABLES
Будучи просто упомянутой в качестве цели, указывает make на необходимость, по умолчанию, экспортировать все переменные для возможности их использования в дочернем процессе. Смотрите раздел Связь с make "нижнего уровня" через переменные.
.NOTPARALLEL
При наличии в make-файле цели .NOTPARALLEL, данный экземпляр make будет работать "последовательно" (даже при наличии опции `-j'). Рекурсивно запущенные экземпляры make по-прежнему могут работать "параллельно" (если только их make-файлы не содержат такой же специальной цели). Любые пререквизиты данной цели игнорируются.

Любой суффикс, определенный для суффиксных правил, а также "сцепление" двух суффиксов (например, такое как `.c.o'), находясь на месте цели, рассматриваются специальным образом. Такие цели представляют из себя суффиксные правила - устаревший, однако, по-прежнему, широко распространенный способ задания шаблонных правил. В принципе, любое имя могло бы, таким образом, стать специальной целью, если разбить его на две части и добавить обе из них к списку суффиксов. На практике, суффиксы обычно начинаются с символа `.', поэтому такие специальные цели также начинаются с `.'. Смотрите раздел Устаревшие суффиксные правила.

Правила с несколькими целями

Правило с несколькими целями, эквивалентно нескольким правилам с одной целью, которые, за исключением имени цели, полностью идентичны друг другу. Ко всем целям будет применяться один и тот же набор команд, однако, эффект от их исполнения может быть разным, поскольку они могут ссылаться на имя обрабатываемой в данный момент цели, используя автоматическую переменную`$@'. А также, все цели подобного правила имеют один и тот же список пререквизитов.

Это может быть полезно в двух случаях.

Предположим, вы хотели бы менять список пререквизитов для конкретной цели, подобно тому, как переменная `$@' позволяет вам варьировать исполняемые команды. Этого невозможно добиться при помощи обычного правила с несколькими целями, однако вы можете это сделать, используя статические шаблонные правила. Смотрите раздел Статические шаблонные правила .

Несколько правил с одной целью

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

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

Дополнительное правило, содержащее только пререквизиты, может быть использовано для "быстрого" добавления нескольких дополнительных пререквизитов одновременно ко многим файлам. Например, в make-файле обычно имеется переменная objects, содержащая список всех объектных файлов собираемой программы. Возможно, простейший путь указать, что все объектные файлы должны быть перекомпилированы при изменении `config.h' - это написать:

objects = foo.o bar.o
foo.o : defs.h
bar.o : defs.h test.h
$(objects) : config.h

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

Другой возможный прием заключается в том, чтобы передавать список дополнительных пререквизитов в переменной, значение которой устанавливать в командной строке при вызове make (смотрите раздел "Перекрытие" переменных). В следующем примере,

extradeps=
$(objects) : $(extradeps)

вызов `make extradeps=foo.h' будет добавлять `foo.h' в список пререквизитов каждого из объектных файлов. При обычном вызове `make', этого делаться не будет.

Если ни одно из правил, описывающее цель, не имеет команд, make попытается применить к этой цели неявные правила (смотрите раздел Использование неявных правил).

Статические шаблонные правила (static pattern rules)

Статические шаблонные правила (static pattern rules) - это правила с несколькими целями, и возможностью автоматически создавать список пререквизитов для каждой цели, используя ее имя. Это - механизм более общий, чем обычные правила с несколькими целями, потому что их цели не должны иметь идентичные пререквизиты. Их пререквизиты должны быть похожими, но не обязательно идентичными.

Синтаксис статических шаблонных правил

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

цели ...: шаблон-цели: шаблоны-пререквизитов ...
        команды
        ...

В списке целей перечисляются цели, к которым будет применяться данное правило. Так же, как и в обычных правилах, при задании имен целей могут использоваться шаблонные символы (смотрите раздел Использование шаблонных символов в именах файлов).

Шаблон-цели и шаблоны-пререквизитов описывают, как вычислять список пререквизитов для каждой цели. Каждая цель статического шаблонного правила сопоставляется с шаблоном-цели, для получения части имени цели, называемой основой. Далее, полученная основа имени подставляется в каждый из шаблонов-пререквизитов для получения имен пререквизитов (по одному имени из каждого шаблона-пререквизита).

Обычно, в каждом шаблоне содержится по одному символу `%'. Когда цель сопоставляется с шаблоном-цели, символ `%' может соответствовать любой части имени цели; именно эта часть будет являться основой. Прочие части имени цели должны в точности совпадать с шаблоном. Например, цель `foo.o' удовлетворяет шаблону `%.o' и ее основой будет `foo'. Цели же `foo.c' и `foo.out' не будут удовлетворять этому шаблону.

Имена пререквизитов для каждой цели генерируются путем подстановки основы вместо символа`%' в каждом из шаблонов пререквизитов. Например, из одного шаблона пререквизита `%.c' и основы`foo', будет получено имя пререквизита `foo.c'. Шаблоны пререквизитов, не содержащие символа`%' также вполне допустимы, в этом случае, указанный пререквизит будет одинаков для всех целей.

Специальное значение символа `%' в шаблоне может быть отменено с помощью предшествующего ему символа `\'. Специальное значение символа `\', предшествующего символу `%', может быть, в свою очередь, отменено добавлением еще одного символа `\'(строка \\% будет интерпретироваться как два символа. Первый из них - символ `\', второй - символ `%', который будет интерпретироваться как шаблонный). Символы `\', имеющие специальное значение, удаляются из шаблона перед тем, как он будет сравниваться с именами файлов. Символы `\', которые не могут повлиять на интерпретацию `%', остаются в шаблоне. Например, шаблон `the\%weird\\%pattern\\' состоит из строки `the%weird\', за которой следуют шаблонный символ`%' и строка `pattern\\'. Последние два символа остаются без изменений, поскольку не могут повлиять на способ интерпретации какого-либо символа %.

Вот пример, где объектные файлы `foo.o' `bar.o' компилируются из соответствующих им исходных файлов с расширением `.c':

objects = foo.o bar.o

all: $(objects)

$(objects): %.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@

В этом примере, автоматическая переменные `$<' и `$@'содержат, соответственно, имя пререквизита и имя цели (смотрите раздел Автоматические переменные).

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

files = foo.elc bar.o lose.o

$(filter %.o,$(files)): %.o: %.c
        $(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
        emacs -f batch-byte-compile $<

В этом примере, результатом `$(filter %.o,$(files))' является `bar.o lose.o', и первое статическое правило вызывает компиляцию этих объектных файлов из соответствующих им исходных файлов. Результатом выражения`$(filter %.elc,$(files))' является `foo.elc', и этот файл получается из `foo.el'.

Следующий пример иллюстрирует использование автоматической переменной $* в статическом шаблонном правиле:

bigoutput littleoutput : %output : text.g
        generate text.g -$* > $@

При запуске команды generate, ссылка на $* будет заменена соответствующей основой имени - строкой`big' или `little'.

Сравнение статических шаблонных правил (static pattern rules) и неявных правил (implicit rules)

Статические шаблонные правила имеют много общего с обычными шаблонными правилами (смотрите раздел Определение и переопределение шаблонных правил). Оба вида правил содержат шаблон для цели и шаблон для конструирования имен пререквизитов. Разница заключается в том, каким образом make принимает решение о необходимости применения данного правила.

Неявное правило может быть применено к любой цели, которая подходит под его шаблон, однако оно действительно будет применено только в том случае, когда цель не имеет команд, определенных иным способом и имеются все необходимые для этого пререквизиты. Если для одной цели могут быть применены сразу несколько неявных правил, будет использовано только одно из них; какое именно - будет зависеть от порядка их следования.

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

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

Правила с двойным двоеточием (double-colon rules)

Правила с двойным двоеточием (double-colon rules) представляют собой правила, записанные с помощью `::' вместо обычного`:' после имени цели. По сравнению с обычными правилами, они обрабатываюся по-другому в случаях, когда одна и та же цель указана сразу в нескольких правилах.

Когда цель указана в нескольких правилах, все они должны быть одного и того же типа: либо обычными правилами, либо правилами с двойным двоеточием. Если все они являются правилами с двойным двоеточием, то каждое из них является независимым от других. Команды, указанные в правиле с двойным двоеточием, будут выполняться, если его цель окажется "старше", чем какой-либо из его пререквизитов. Результатом может быть выполнение всех или нескольких правил. Может получиться и так, что ни одно из правил не будет выполнено.

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

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

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

Каждое правило с двойным двоеточием должно содержать команды, в противном случае make попытается применить подходящее неявное правило. Смотрите раздел Использование неявных правил.

Автоматическая генерация списка пререквизитов

Как правило, в типичном make-файле значительная часть правил служит лишь для того, чтобы описать зависимость объектных файлов от некоторых заголовочных файлов. Например, если `main.c' использует `defs.h', включая его с помощью директивы #include, вы можете написать:

main.o: defs.h

Это правило необходимо для того, чтобы make обновляла объектный файл `main.o' при каждом изменении `defs.h'. Для большой программы, скорее всего, вам придется написать большое количество подобных правил. Далее, каждый раз при изменении исходных текстов путем добавления или удаления директивы #include, вам придется модефицировать соответствующим образом и make-файл.

Чтобы избежать подобных неудобств, большинство современных компиляторов могут автоматически создать для вас такие правила, просматривая содержимое исходных файлов, и учитывая встретившиеся в них директивы #include. Обычно, это делается при помощи опции компилятора `-M'. Например, результатом работы команды

cc -M main.c

будет строка:

main.o : main.c defs.h

Таким образом, вам больше не потребуется писать подобные правила "вручную" - эту работу возьмет на себя компилятор.

Обратите внимание, что в приведенной выше зависимости упоминается файл `main.o' и, следовательно, этот файл не сможет рассматриваться как промежуточный в процессе поиска неявных правил. Как следствие, make никогда не будет удалять этот файл после его использования; смотрите раздел "Цепочки" неявных правил.

При работе со старыми реализациями make, обычной практикой являлась генерация пререквизитов по отдельному запросу, наподобие`make depend'. Эта команда создаст файл `depend', содержащий все автоматически сгенерированные пререквизиты; затем они могут быть включены в make-файл с помощью директивы include (смотрите раздел Подключение других make-файлов).

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

Мы рекомендуем вам использовать подход, когда для каждого исходного файла имеется свой маленький make-файл, содержащий список пререквизитов этого исходного файла. Для каждого исходного файла `имя.c' имеется make-файл `имя.d', в котором перечислен список файлов, от которых зависит объектный файл `name.o'. При таком подходе, новые списки пререквизитов могут строиться только для тех исходных файлов, которые действительно были модефицированы.

Вот пример шаблонного правила для генерации файлов пререквизитов (то есть make-файлов), имеющих имя `имя.d' из файлов с исходным текстом `имя.c':

%.d: %.c
        set -e; $(CC) -M $(CPPFLAGS) $< \
                  | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
                [ -s $@ ] || rm -f $@

Для получения подробной информации об определении шаблонных правил смотрите раздел Определение и переопределение шаблонных правил. Флажок `-e' заставляет интерпретатор командной строки немедленно завершать работу в случае, если при вызове $(CC) произойдет ошибка (команда возвратит отличный от нуля код завершения). Обычно, интерпретатор командной строки завершается с кодом возврата, полученным от последней выполненной команды из всей цепочки команд (sed в данном случае) и make может просто "не заметить" ошибочной ситуации, произошедшей при вызове компилятора.

При использовании компилятора GNU C, вместо опции `-M' вы можете попробовать использовать опцию`-MM'. При этом, в список пререквизитов не будут попадать системные заголовочные файлы. Смотрите раздел `Options Controlling the Preprocessor' руководства по компилятору GNU C.

Назначение команды sed заключается в преобразовании (например) строки:

main.o : main.c defs.h

в строку:

main.o main.d : main.c defs.h

Таким образом, получается, что каждый файл с расширением `.d'зависит от всех тех же исходных и заголовочных файлов, что и соответствующий ему объектный файл `.o'. Теперь, make будет заново генерировать список пререквизитов при любом изменении исходного либо заголовочных файлов программы.

После того, как вы создали правило, обновляющее все `.d' файлы, надо сделать эти файлы доступными для make. Для этого используется директива include. Смотрите раздел Подключение других make-файлов. Например:

sources = foo.c bar.c

include $(sources:.c=.d)

(В этом примере, для преобразования списка исходных файлов`foo.c bar.c' в список пререквизитов (`foo.d bar.d'), используется техника ссылки на переменную с подстановкой. Смотрите раздел Ссылка с заменой). Поскольку файлы с расширением`.d' являются полноправными make-файлами, утилита make будет сама заботится об их своевременном обновлении, не требуя от вас каких-либо дополнительных усилий. Смотрите раздел Автоматическое обновление make-файлов.

Написание команд

Определенные в правиле команды, представляют собой текстовые строки с командами для интерпретатора командной строки. Команды эти исполняются последовательно, одна за другой. Каждая строка, содержащая команду, должна начинаться с символа табуляции. Первая команда также может быть расположена в строке правила, содержащей список целей и пререквизитов - в таком случае она отделяется от списка пререквизитов символом точки с запятой и не требует наличия символа табуляции в ее начале. Среди строк, содержащих команды, могут присутствовать пустые строки и строки, содержащие лишь комментарии - все они будут проигнорированы. (Но имейте ввиду, что "пустая" строка, начинающаяся с символа табуляции, на самом деле не является пустой! Она рассматривается как строка, содержащая пустую команду; смотрите раздел Пустые команды.)

Несмотря на то, что пользователи могут пользоваться разными интерпретаторами командной строки, для интерпретации команд из make-файла всегда используется оболочка `/bin/sh'(если только в make-файле явно не задается использование какой-либо другого интерпретатора). Смотрите раздел Исполнение команд.

Тип используемой в системе оболочки определяется исходя из того, может ли в командных строках использоваться комментарий и используемый для этого синтаксис. В оболочке `/bin/sh', комментарий начинается с символа `#'и продолжается до конца строки. Символ `#' может располагаться и не в начале строки. Текст до символа `#' не является частью комментария.

Отображение исполняемых команд (command echoing)

Обычно, make печатает каждую командную строку перед тем, как она будет выполнена. Мы называем такой механизм эхом (echoing), поскольку он создает впечатление, что это вы сами набираете исполняемые команды.

Если строка, содержащая команду, начинается с символа `@', печать этой команды не производится. Символ `@' удаляется из строки с командой перед тем, как она передается для обработки интерпретатору командной строки. Такой прием часто используется для команд, назначением которых является вывод некоторого сообщения, например, команд echo, используемых для отображения хода обработки make-файла:

@echo About to make distribution files

Когда make вызывается с опцией `-n' или`--just-print', происходит только лишь отображение команд, без их реального выполнения. Смотрите раздел Обзор опций. Это единственный случай, когда команды, начинающиеся с символа`@', также будут напечатаны. Используя эти опции, можно увидеть, какие команды make считает необходимым выполнить, без того, чтобы реально их выполнять.

Опции `-s' и `--silent' отключают всякое отображение команд, как если бы все команды начинались с символа`@'. Использование в make-файле правила со специальной целью .SILENT без указания пререквизитов, имеет аналогичный эффект (смотрите раздел Имена специальных целей). Использование специальной цели .SILENT является устаревшей практикой, взамен которой мы рекомедуем пользоваться более гибким механизмом - символом`@'.

Исполнение команд

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

Это, в частности, означает, что (обратите внимание!) такие команды, как cd, влияющие на переменные среды процесса, не окажут никакого влияния на следующие за ними команды. (2) Если вы хотите, чтобы команда cd повлияла на следующую за ней команду, поместите обе команды на одну строку make-файла, отделив друг от друга с помощью точки с запятой. В таком случае, make будет рассматривать их как единую команду и "вместе" передаст их интерпретатору командной строки для последовательного выполнения. Например:

foo : bar/lose
        cd bar; gobble lose > ../foo

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

foo : bar/lose
        cd bar;  \
        gobble lose > ../foo

Имя программы, являющейся интерпретатором командной строки, берется из переменной SHELL. По умолчанию, используется программа `/bin/sh'.

При работе в операционной системе MS-DOS, если переменная SHELL не установлена, имя интерпретатора командной строки берется из переменной COMSPEC (которая установлена всегда).

При работе в операционной системе MS-DOS, обработка строк make-файла, изменяющих содержимое переменной SHELL, имеет некоторые особенности. Стандартный для MS-DOS интерпретатор командной строки `command.com' обладает столь ограниченными возможностями, что большое число пользователей make предпочитают заменить его на что-нибудь более приемлимое. Поэтому, работая под управлением MS-DOS, make отслеживает значение переменной SHELL, и меняет свое поведение в зависимости от того, указывает ли эта переменная на интерпретатор с ограниченными функциональными возможностями (в стиле MS-DOS), либо на "полнофункциональный" интерпретатор (в стиле Unix). Это позволяет утилите make сохранять приемлимую функциональность даже в случае, когда переменная SHELL указывает на командный интерпретатор `command.com'.

Если переменная SHELL указывает на интерпретатор командной строки, выдержанный в Unix-стиле, программа make, работающая под управлением MS-DOS, дополнительно проверяет - действительно ли указанный интерпретатор существует; если нет, make будет игнорировать строки make-файла, изменяющие значение переменной SHELL. Работая под управлением MS-DOS, утилита GNU make проводит поиск интерпретатора командной строки в следующих местах:

  1. В точности том месте, куда указывает значение переменной SHELL. Например, если в make-файле указано `SHELL = /bin/sh', make будет искать интерпретатор в каталоге `/bin' текущего диска.
  2. В текущем каталоге.
  3. В каждом из каталогов, перечисленных в переменной PATH (в том порядке, как они указаны).

В каждом из проверяемых каталогов make сначала пытается найти файл с известным ей конкретным именем (`sh' в приведенном выше примере). Если такого файла не существует, делается попытка найти файл с подобным именем, но имеющим другое расширение. При этом, проверяются нзвестные расширения, используемые для исполняемых файлов ( `.exe', `.com', `.bat', `.btm', `.sh' и некоторые другие).

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

Обратите внимание, что описанная выше процедура поиска командного интерпретатора выполняется только в тех случаях, когда переменная SHELL устанавливается из из make-файла. Если значение этой переменной берется из среды (environment) или устанавливается с помощью командной строки, ожидается что она будет содержать полное имя (с путем) интерпретатора командной строки, подобно тому, как это происходит в Unix.

Эффект от подобной специфической для MS-DOS обработки, состоит в том, что строка make-файла`SHELL = /bin/sh' (встречающаяся во многих make-файлах, ориентированных на Unix), без именений будет работать в среде MS-DOS - достаточно лишь поместить (например) программу `sh.exe' в какой-нибудь из каталогов, перечисленных в PATH.

В отличие от большинства переменных, SHELL никогда не получает свое значение из среды (environment). Это делается потому, что значение переменной SHELL используется для указания командного интерпретатора, который выбран вами для интерактивного использования. Было бы неправильно, если бы ваш персональный выбор отражался бы на работоспособности make-файлов. Смотрите раздел Переменные из операционного окружения. Переменная среды SHELL используется, однако, при работе make в операционных системах MS-DOS и MS-Windows, поскольку, как правило, пользователи, работающие в этих системах, не используют переменную SHELL для каких-либо иных целей, кроме работы с make. Если, при работе в MS-DOS, вы по какой-либо причине не можете воспользоваться переменной SHELL, вместо нее вы можете использовать переменную MAKESHELL. При наличии переменой MAKESHELL, значение переменной SHELL не учитывается.

Параллельное исполнение команд

GNU make умеет одновременно выполнять несколько команд. Обычно, make выполняет команды поочередно, ожидая завершения очередной команды, перед тем, как выполнять следующую. Однако, с помощью опций `-j' и`--jobs' можно заставить make выполнять одновременно несколько команд.

В операционной системе MS-DOS, опция `-j' не работает, поскольку эта система не поддерживает многозадачность.

За опцией `-j' может следовать целое число, которое будет указывать количество одновременно исполняемых команд (это понятие называется числом слотов задания (job slots)). В случае, если после опции `-j' не указано конкретное число слотов задания, подразумевается их неограниченное количество. По умолчанию, количество слотов задания равняется единице, что, фактически, означает последовательное выполнение (одновременно может выполняться только одна команда).

Одно из неприятных последствий одновременной работы нескольких команд, заключается в возможности "перемешивания" их сообщений, поскольку нескольким командам может "одновременно" понадобится вывести некоторую информацию.

Другая проблема заключается в том, что два разных процесса не могут одновременно читать данные из одного устройства. Дабы иметь уверенность в том, что одновременно только одна команда сможет попытаться прочесть входные данные с терминала, make закрывает стандартные потоки ввода у всех запущенных команд, кроме одной. Это означает, что попытка запущенной команды прочитать данные из стандартного ввода обычно заканчивается фатальной ошибкой (например, получением сигнала `Broken pipe').

Невозможно заранее предсказать, какая именно команда получит в качестве стандартного ввода работающий входной поток (подключенный к терминалу или другому источнику, куда был перенаправлен стандартный ввод утилиты make). Сначала этот входной поток получит в свое распоряжение первая запущенная команда, затем первая команда, которая была запущена по окончанию работы этой команды и так далее.

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

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

При аварийном завершении команды (от нее был получен ненулевой код возврата либо она была прервана полученным сигналом) для которой не был указан режим игнорирования ошибок (смотрите раздел Ошибки при исполнении команд), оставшиеся командные строки (обновляющие ту же цель) не будут выполняться. При этом, если в командной строке не были указаны опции `-k' или`--keep-going'(смотрите раздел Обзор опций), программа make аварийно завершается. При любом аварийном завершении (в том числе и из-за получения сигнала), перед тем как закончить работу, программа make дожидается завершения всех своих дочерних процессов.

Если ваша компьютерная система сильно загружена, вам возможно захочется, чтобы make одновременно запускала меньшее число заданий, чем это делается при нормальной загрузке. В таком случае можно использовать опцию`-l' для того, чтобы поставить число одновременно выполняемых команд в зависимость от средней загрузки системы. Для этого, за опцией `-l'или `--max-load' должно следовать число с плавающей точкой. Например в следующем случае:

-l 2.5

make будет запускать одновременно не более одной команды, если средняя загрузка системы будет больше чем 2.5. Опция `-l', за которой не следует число, отменяет установленное ранее ограничение на максимальную загрузку систему.

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

По умолчанию, загрузка системы не ограничивается.

Ошибки при исполнении команд

После завершения очередной команды, make проверяет полученный от нее код возврата. В случае успешного ее завершения, выполняется (своим экземпляром командного интерпретатора) следующая командная строка; после выполнения последней команды, обработка правила считается завершенной.

Если во время выполнения команды произошла ошибка (от нее был получен ненулевой код возврата), make прекращает обработку текущего правила, и, возможно, прерывает работу.

В определенных ситуациях, ошибка при выполнении некоторой команды не является проблемой. Например, вы можете использовать команду mkdir, дабы быть уверенным в существовании некоторого каталога. Если такая директория уже существует, команда mkdir сообщит об ошибке, но, скорее всего, вы захотите, чтобы make в таком случае продолжила работу, не обращая внимания на ошибку.

Для того, чтобы проигнорировать ошибки в команде, поместите в начало строки (после символа табуляции), где она описана, символ `-'. Перед тем, как эта команда будет передана интерпретатору командной строки, символ`-' будет из нее удален.

В следующем примере:

clean:
        -rm -f *.o

обработка make-файла не будет прервана даже в том случае, если команда rm не сможет удалить файл.

При запуске make с опцией `-i' или `--ignore-errors', будут игнорироваться ошибки во всех командах, любого из правил. Такой же эффект достигается при изпользовании специальной цели .IGNORE в правиле, не имеющем пререквизитов. Вместо подобной устаревшей практики, мы рекомендуем применять более гибкую методику с использованием`-'.

Когда произошедшая ошибка игнорируется (например, вследствие использования`-' или опции`-i'), ошибочное завершение команды обрабатывается аналогично нормальному завершению, за исключением того, что при этом печатается полученный от команды код возврата и выдается сообщение, что ошибка была проигнорирована.

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

Обычно, в такой ситуации make прекращает работу, возвращая ненулевой результат. Однако, если была указана опция`-k' или `--keep-going', make продолжает обработку других пререквизитов оставшихся целей, при необходимости обновляя их. Например, после неудачной компиляции объектного файла,`make -k' продолжит работу, компилируя оставшиеся объектные файлы, хотя уже заранее известно, что их компоновка закончится неудачей. Смотрите раздел Обзор опций. По окончанию работы make, ненулевой код возврата будет указывать на произошедшую ошибку.

Мотивы подобного поведения make просты. Обычно, запуская make, вы хотите получить свежую версию указанной цели. Как только make понимает, что это невозможно, она сразу же может собщить о происшедшей ошибке. Напротив, задание опции `-k' означает, что ваша цель - наболее полно протестировать процесс сборки программы, по возможности обнаружив максимальное количество проблем. После устранения всех найденных проблем, можно будет заново повторить процесс компиляции. Подобными соображениями, например, руководствуется редактор Emacs, по умолчанию запуская make с опцией `-k', при выполнении команды compile.

Обычно, если при аварийном завершении команды, целевой файл все же обновился, то он, скорее всего просто поврежден и непригоден для дальнейшего использования. В любом случае, он, как минимум, обновился некорректно. Однако, поскольку время модефикации файла все-таки изменилось, при следующем запуске, make уже не будет обновлять этот файл, считая что имеется его "свежая" версия. Похожая ситуация возникает, когда исполняемая команда аварийно завершается из-за получения сигнала (смотрите раздел Прерывание или принудительное завершение make. Пожалуй, правильнее всего будет удалять целевой файл, если обновляющая его команда завершилась с ошибкой. Утилита make будет поступать подобным образом при наличии в make-файле специальной цели .DELETE_ON_ERROR. Практически во всех случаях подобное поведение является наилучшей стратегией, однако, по умолчанию, make этого не делает (из "исторических" сображений). Для того, чтобы make автоматически удаляла некорректно построенные целевые файлы, вы должны явно этого потребовать.

Прерывание (interrupting) или принудительное завершение (killing) make

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

Смысл удаления целевого файла заключается в том, чтобы при следующем запуске make, он был построен заново. Для чего это делается? Предположим, что во время работы компилятора, в то самое время как он начал записывать на диск объектный файл `foo.o', вы нажали Ctrl-c. Нажатие Ctrl-c немедленно прервет работу компилятора, в результате чего на диске останется фрагмент не полностью записанного файла с более поздним временем модефикации, чем исходный файл `foo.c'. К счастью, make также получит сигнал Ctrl-c и удалит этот "не доделанный" файл. Если бы make этого не сделала, при следующем вызове она могла бы подумать, что уже имеется "свежая" версия файла `foo.o', и он больше не нуждается в обновлении - результатом был бы странный сбой в работе компоновщика, попытающегося скомпоновать поврежденный объектный файл.

Вы можете предотвратить удаление целевого файла в подобной ситуации, сделав его пререквизитом специальной цели .PRECIOUS. Перед тем, как обновить цель, make проверяет - не является ли она пререквизитом цели .PRECIOUS, и на основании этого решает - нужно ли удалять ее при получении сигнала или нет. В некоторых ситуациях вам может потребоваться, чтобы при возникновении сигнала, цель, тем не менее, не удалялась. Например, если цель служит только для запоминания времени последней модефикации (и ее содержимое не имеет значия), или, по каким-либо соображениям, она должна существовать всегда, или же процесс ее обновления является "атомарной" операцией.

Рекурсивный вызов make

При рекурсивном использовании, программа make сама выступает в качестве одной из команд make-файла. Подобная техника полезна, когда вы хотите иметь отдельные make-файлы для различных подсистем, составляющих большую систему. Предположим, у вас имеется подкаталог `subdir', содержащий свой собственный make-файл, и вы хотите, чтобы make-файл из "объемлющего" каталога запускал make в этом подкаталоге. Вы можете сделать это, написав:

subsystem:
        cd subdir && $(MAKE)

или (смотрите раздел Обзор опций):

subsystem:
        $(MAKE) -C subdir

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

Для удобства, GNU make записывает имя текущего рабочего каталога в переменную CURDIR. В случае, если make была запущена с параметром -C, эта переменная будет содержать имя нового (установленного с помощью параметра -C) каталога, а не "оригинального" рабочего каталога. Переменная CURDIR имеет "приоритет" такой же, как если бы она была установлена внутри make-файла (по умолчанию, переменная среды CURDIR не будет "перекрывать" ее значение). Если вы сами запишете в переменную CURDIR новое значение, это никак не повлияет на работу make.

Как работает переменная MAKE

При рекурсивном использовании make, вместо "прямого" указания имени команды (`make'), всегда следует использовать переменную MAKE, как показано в следующем примере:

subsystem:
        cd subdir && $(MAKE)

Эта переменная содержит имя исполняемого файла, запущенного в ответ на команду make. Если, например, этот файл назывался `/bin/make', то в приведенном выше примере будет вызвана команда`cd subdir && /bin/make'. Таким образом, при каждом рекурсивном вызове, будет использована та же самая программа make, которая была вызвана для make-файла "верхнего" уровня.

Использование переменной MAKE оказывает влияние на работу опций`-t' (`--touch'),`-n' (`--just-print') и `-q'(`--question'). Командная строка, содержащая переменную MAKE, работает так, как если бы в ее начале находился специальный символ`+'(смотрите раздел Вместо исполнения команд).

Предположим, в предыдущем примере make была вызвана следующим образом: `make -t'. (Опция`-t' заставляет make пометить все цели как "обновленные", не выполняя в действительности каких-либо команд; смотрите раздел Вместо исполнения команд.) Следуя тому, каким образом обычно описывается поведение опции`-t', команда `make -t' создала бы файл с именем `subsystem' и на этом завершила бы свою работу. Скорее всего, однако, вы хотели бы получить другой результат, а именно, запуск команды`cd subdir && make -t'. Но для достижения такого результата потребовалось бы выполнение команды, в то время как опция`-t' говорит, что команды выполняться не должны.

Для получения желаемого результата, make обрабатывает строки с командами, содержащие ссылку на переменную MAKE специальным образом: опции`-t', `-n' и `-q' на такие строки не действуют. Командные строки с переменной MAKE выполняются обычными образом, не обращая внимания на опции, отключающие выполнение команд. Для передачи параметров от make "высшего" уровня на "нижние" уровни используется обычный механизм - переменная MAKEFLAGS (смотрите раздел Передача опций в make "нижнего уровня"). Таким образом, все ваши запросы на обновление даты модефикации целевых файлов или печать исполняемых команд, будут переданы "вниз", во все подсистемы.

Связь с make "нижнего уровня" (sub-make) через переменные

Значения переменных, определенных в make "верхнего уровня", могут быть переданы в "порожденные" make через среду (как переменные среды), при явном на то указании. Эти переменные будут определены и в "порожденных" make, однако их значение может быть "перекрыто" другим значением, устанавливаемым в самом make-файле "нижнего уровня" (если только не использовать опцию`-e'; смотрите раздел Обзор опций).

Чтобы "передать вниз" или экспортировать переменную, make добавляет переменную с таким же именем и значением в набор переменных среды перед выполнением каждой команды. В свою очередь, "порожденные" копии make, будут использовать значения переменных среды для инициализации своих внутренних таблиц переменных. Смотрите раздел Переменные из операционного окружения.

За исключением случаев явного указания, make экспортирует только те переменные, которые "изначально" были определены в среде, либо те из них, которые были определены с помощью командной строки (и только в том случае, если имя переменной состоит только из букв, цифр и символов подчеркивания, поскольку прочие имена могут "не работать" с некоторыми версиями командных интерпретаторов).

Специальные переменные SHELL и MAKEFLAGS экспортируются всегда (за исключением случаев, когда вы "принудительно" запретили их экспорт). Переменная MAKEFILES экспортируется в том случае, если вы присвоили ей какое-либо значение.

Переменные, определенные с помощью командной строки, автоматически передаются "вниз", поскольку make помещает их (наряду с другими параметрами) в специальную переменную MAKEFLAGS (смотрите следующий раздел).

Переменные, которые по умолчанию созданы самой make, не передаются "вниз" (смотрите раздел Используемые в неявных правилах переменные). Такие переменные каждая make "нижнего уровня", при необходимости, создаст самостоятельно.

Для экспорта указанной переменной в make "нижнего уровня", используется директива export:

export переменная ...

Для запрета экспорта переменной, используется директива unexport:

unexport переменная ...

Для удобства, вы можете одновременно определить переменную и указать на необходимость ее экспортирования. Это делается с помощью записи:

export переменная = значение

что эквивалентно:

переменная = значение
export переменная

или

export переменная := значение

что эквивалентно:

переменная := значение
export переменная

Аналогично,

export переменная += значение

эквивалентно:

переменная += значение 
export переменная

Смотрите раздел Добавление текста к переменной.

Вы можете заметить, что директивы export и unexport работают в make таким же образом, как и подобные директивы командного интерпретатора sh.

Если вы хотите, чтобы, по умолчанию, все переменные экспортировались, используйте директиву export без аргументов:

export

Эта конструкция говорит о том, что все переменные, которые не были явно указаны в директивах export и unexport, должны быть экспортированы. Любые переменные, перечисленные в директиве unexport, по-прежнему не будут экспортироваться. При использовании директивы export без параметров, переменные, чьи имена содержат не только алфавитно-цифровые символы и подчеркивания, экспортированы не будут. Для экспорта таких переменных надо явно указать их в директиве export.

Старые версии GNU make, по умолчанию, экспортируют все переменные (как если бы была использована директива export без параметров). Если ваш make-файл рассчитан на такое поведение и вы хотите, чтобы он оставался "совместим" со старыми версиями make, то вместо директивы export без параметров, можно использовать правило со специальной целью .EXPORT_ALL_VARIABLES. Старые версии make просто проигнорируют такое правило, в то время как использование директивы export вызвало бы синтаксическую ошибку.

Аналогично, вы можете использовать директиву unexport без параметров для того, чтобы, по умолчанию, не экспортировать переменные. Поскольку именно так, по умолчанию, и ведет себя make, необходимость в директиве unexport без параметров может возникнуть только в случае, если ранее где-то была использована директива export без параметров (возможно, в каком-нибудь из включаемых make-файлов). Вы не можете использовать директивы export и unexport без параметров для того, чтобы экспортировать переменные для одних команд и не экспортировать для других. Сработает самая "последняя" из перечисленных в make-файле директив export или unexport, которая и будет определять поведение make на все время обработки make-файла.

Специальная переменная MAKELEVEL используется для отражения "уровня вложенности" make. Ее значение меняется при переходе "с уровня на уровень". Значением этой переменной является строка с десятичным числом, показывающим "уровень вложенности" данной копии make. Для make самого "верхнего" уровня, ее значением является `0'. Далее, во "вложенной" копии make ее значением будет `1', следующая "вложенная" копия make получит значение `2' и так далее. Значение этой переменной увеличивается в тот момент, когда make устанавливает переменные среды для запуска очередной команды.

В основном, переменная MAKELEVEL применяется в условных директивах (смотрите раздел Условные части make-файла); с ее использованием вы можете написать make-файл, который будет вести себя по-разному в зависимости от того, был ли он запущен непосредственно вами, либо исполнялся рекурсивно вызванной копией make.

Для передачи во "вложенные" копии make дополнительного списка make-файлов, которые нужно интерпретировать, вы можете использовать переменную MAKEFILES. Значением этой переменной является список имен make-файлов, разделенных пробелами. Будучи определенной в make-файле "высшего уровня", эта переменная будет передаваться "вниз" через переменные среды и будет работать как список make-файлов, которые должны быть прочтены "порожденными" копиями make перед чтением основного make-файла. Смотрите раздел Переменная MAKEFILES.

Передача опций в make "нижнего уровня"

Такие опции как `-s' и `-k' автоматически передаются в "порожденные" make с помощью переменной MAKEFLAGS. Эта автоматически устанавливаемая переменная содержит имена всех опций, переданных программе make в командной строке. Например, при вызове `make -ks', переменная MAKEFLAGS получит значение`ks'.

Далее, каждая "порожденная" копия make получит значение переменной MAKEFLAGS через переменные среды и интерпретирует ее содержимое как набор опций для своей работы (аналогично тому, как если бы эти опции были переданы через командную строку). Смотрите раздел Обзор опций.

Аналогично, переменные, определенные с помощью командной строки, передаются в "порожденные" make через переменную MAKEFLAGS. Слова (из переменной MAKEFLAGS), содержащие символ`=', make рассматривает как определение переменной (аналогично тому, как если бы она были определена с помощью командной строки). Смотрите раздел "Перекрытие" переменных.

Опции`-C', `-f', `-o', и `-W'не записываются в переменную MAKEFLAGS и, соответственно, не передаются в "порожденные" копии make.

Опция `-j' обрабатывается специальным образом (смотрите раздел Параллельное исполнение команд). Если в этой опции вы задали некоторое числовое значение `N', то при наличии в вашей операционной системе соответствующих возможностей (присутствующих в большинстве UNIX системах; в других системах, обычно, отсутствуют), make "верхнего уровня" и "подчиненные" make взаимодействуют между собой, контролируя общее число запущенных во всех копиях make заданий, не допуская ситуацию, когда оно превысит`N'. Обратите внимание, что задания, помеченные как рекурсивно исполняемые (смотрите раздел Вместо исполнения команд), при подсчете общего количества заданий не учитываются (иначе, может получиться, что у нас запущено `N' "порожденных" копий make и не осталось свободных слотов заданий для выполнения "реальной" работы!)

Если ваша операционная система не поддерживает нужный механизм межпрограммного взаимодействия, то, вместо указанного вами числового значения, в переменную MAKEFLAGS всегда записывается`-j 1'. Это делается для того, чтобы случайно не превысить максимальное число одновременной запускаемых заданий из-за возможного рекурсивного запуска make. Опция `-j' без числовых аргументов передается "вниз" без изменений (поскольку она означает запуск максимального возможного числа заданий).

Если вы не хотите передавать "вниз" другие опции, вы должны соответствующим образом изменить значение MAKEFLAGS, например:

subsystem:
        cd subdir && $(MAKE) MAKEFLAGS=

На самом деле, определения переменных, заданные в командной строке, помещаются в переменную MAKEOVERRIDES, а MAKEFLAGS содержит ссылку на эту переменную. Если вы хотите передать опции в make "нижнего уровня", но не хотите передавать определения переменных, заданные в командной строке, вы можете записать в переменную MAKEOVERRIDES пустое значение, например:

MAKEOVERRIDES =

Обычно, в этом нет особого смысла, однако, некоторые системы имеют небольшой и фиксированный лимит размера операционной среды, который легко может быть превышен при записи в переменную MAKEFLAGS такого большого количества информации. Эта проблема может проявляться в виде сообщения об ошибке`Arg list too long' (список аргументов слишком велик). (Для строгого соответствия стандарту POSIX.2, изменение MAKEOVERRIDES не влияет на MAKEFLAGS при наличии в make-файле специальной цели `.POSIX'. Для вас, скорее всего, это и неважно.)

По "историческим" соображениям (для обеспечения совместимости) существует похожая переменная MFLAGS. Она содержит такое же значение, как и MAKEFLAGS, но в это значение не попадают определения переменных, заданных в командной строки, и, если это значение не пусто, оно всегда начинается с дефиса (значение переменной MAKEFLAGS начинается с дефиса только в том случае, если первая опция не имеет однобуквенного варианта названия, например`--warn-undefined-variables'). Традиционно, MFLAGS используется исключительно для рекурсивного вызова make, наподобие:

subsystem:
        cd subdir && $(MAKE) $(MFLAGS)

Переменная MAKEFLAGS делает подобную технику ненужной. Используйте эту методику в том случае, если вы хотите сделать ваш make-файл "совместимым" со старыми вариантами make; она будет нормально работать и с современными версиями make.

Переменная MAKEFLAGS может оказаться полезной и в том случае, если вы хотите, чтобы некоторые опции, такие как`-k' (смотрите раздел Обзор опций), использовались при каждом запуске make. Поместите нужное значение в переменную среды MAKEFLAGS. Вы также может установить значение MAKEFLAGS в make-файле, задав, таким образом, опции, которые должны использоваться для этого make-файла. (Обратите внимание, что вы не можете подобным образом использовать переменную MFLAGS. Значение этой переменной устанавливается только для совместимости; самостоятельное присваивание этой переменной другого значения никак не будет интерпретироваться make.)

При интерпретации значения MAKEFLAGS (полученного как из операционной среды, так и из make-файла), значение этой переменной сначала предваряется дефисом (если оно еще не начинатеся с дефиса). Далее, это значение рассматривается как разделенные пробелами слова, являющиеся именами опций. Эти опции интерпретируются так, как если бы они были заданы в командной строке (за исключением того, что опции `-C', `-f',`-h', `-o', `-W' и их версии с длинными именами, игнорируются, а неверные опции не вызывают ошибки).

Используя MAKEFLAGS как переменную среды будьте внимательны и не помещайте в нее никаких опций, которые оказывают "глобальное влияние" на работу make. Так, например, помещение опций `-t',`-n' или `-q' в переменные среды будет иметь "катастрофические" последствия и приведет к "удивительным" и неприятным эффектам.

Опция `--print-directory'

При многократном рекурсивном вызове make, могут оказаться полезными опции`-w' и `--print-directory', заставляющие make печатать имя текущего каталога, когда утилита начинает и заканчивает работу в нем. Например, при запуске`make -w' в директории `/u/gnu/make', следующая строка:

make: Entering directory `/u/gnu/make'.

будет выведена перед тем, как make начнет что-либо делать, а строка:

make: Leaving directory `/u/gnu/make'.

будет выведена перед тем, как работа будет закончена.

Как правило, вам не придется самостоятельно указывать эти опции, поскольку печать каталогов автоматически включаются при наличии опции `-C', а также в "порожденных" копиях make. Печать каталогов не будет включаться автоматически при наличии опции`-s' (подавляющей вывод информации) или опции`--no-print-directory' (явно запрещающей печать каталогов).

Именованные командные последовательности (canned command sequences)

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

Вот пример определения именованной командной последовательности:

define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

Здесь, run-yacc является именем определяемой переменной; endef обозначает конец определения; остальные строки являются командами. Ссылки на переменные и функции внутри директивы define не "раскрываются"; символы `$', скобки, имена переменных и прочее, становятся частью значения определяемой вами переменной. Смотрите раздел Многострочные переменные, где описана работа директивы define.

В этом примере, первая команда запустит программу Yacc для первого пререквизита правила, в котором использована данная командная последовательность. Выходная информация программы Yacc всегда будет помещаться в файл `y.tab.c'. Вторая команда даст выходному файлу имя целевого файла правила.

Для того, чтобы задействовать именованную последовательность команд, подставьте переменную с этой последовательностью в качестве команды правила (подстановка делается "обычным" для всех переменных способом; смотрите раздел Обращение к переменным). Переменные, определенные с помощью define являются рекурсивно вычисляемыми, поэтому все все ссылки на переменные, находящиеся внутри директивы define, будут при этом вычислены. Так, в следующем примере:

foo.c : foo.y
        $(run-yacc)

при вычислении значения переменной run-yacc, вместо `$^' будет подставлено имя `foo.y', и имя `foo.c' вместо `$@'.

Это достаточно реалистичный пример, однако, на практике, в данном конкретном правиле нет необходимости, поскольку make имеет соответствующие неявные правила, имеющие аналогичный эффект (смотрите раздел Использование неявных правил).

При выполнении команды, каждая строка именованной командной последовательности рассматривается так, как если бы она являлась отдельной строкой правила и ей предшествовал бы символ табуляции. Так же, каждая строка будет выполняться своей отдельной копией интерпретатора командной строки. В начале каждой командной строки именованной последовательности могут использоваться специальные символы`@',`-', и `+'. Смотрите раздел Написание команд. Например, при использовании следующей командной последовательности:

define frobnicate
@echo "frobnicating target $@"
frob-step-1 $< -o $@-step-1
frob-step-2 $@-step-1 -o $@
endef

make не будет отображать первую командную строку, однако напечает следующие две строки с командами.

В то же время, специальный символ в начале строки, ссылающейся на именованную командную последовательность, будет применен к каждой строке этой последовательности. Так, при обработке правила:

frob.out: frob.in
        @$(frobnicate)

ни одна команда отображена не будет. (Смотрите раздел Отображение исполняемых команд, где обсуждается использование специального символа `@'.)

Пустые команды (empty commands)

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

target: ;

определяется пустую команду для цели `target'. Можно также использовать отдельную командную строку, начинающуюся с символа табуляции, однако это может вызвать путаницу, поскольку такая строка выглядит как пустая.

Если вам непонятно, зачем может понадобиться пустая команда, вспомните о наличии неявных правил. Правило с пустой командой может предовратить применение для указанной цели команд, определенных в неявных правилах (или правилах со специальной целью .DEFAULT); смотрите разделы Использование неявных правил и Определение правил "последнего шанса").

Вы можете попытаться использовать пустые команды для тех целей, которые на самом деле не являются файлами, а служат лишь для того, чтобы были обновлены все их пререквизиты. Это, однако, не слишком хорошая идея, поскольку при наличии реального файла, имя которого совпадает с именем цели, пререквизиты могут и не быть обновлены в нужный момент. В таких ситуациях лучше пользоваться абстрактными целями (смотрите раздел Абстрактные цели).

Использование переменных (variables)

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

За исключением нескольких мест, переменные и функции во всех частях make-файла вычисляются при его чтении. Исключение составляют команды, передаваемые интерпретатора командной строки, правые части определений (с помощью символа `=') переменных, а также определения переменных с помощью директивы define.

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

Именем переменной может быть любая последовательность символов, не содержащая`:', `#', `=' и начальных или конечных пробелов. Однако, мы рекомендуем избегать использования имен переменных, содержащих символы, отличные от букв, цифр и символа подчеркивания. Во-первых, такие имена в будущем могут получить какое-либо специальное значение, и, во-вторых, не все интерпретаторы командной строки смогут передать (через переменные среды) такие переменные "порожденным" копиям make. (смотрите раздел Связь с make "нижнего уровня" через переменные).

Имена переменных чувствительны к регистру. Таким образом, имена `foo',`FOO', и `Foo' будут ссылаться на разные переменные.

Традиционно, имена переменных записывались с использованием букв верхнего регистра. Мы, однако, рекомендуем вам пользоваться нижним регистром для всех переменных, используемых для "внутренних нужд" make-файла. Верхний же регистр мы рекомендуем оставить для переменных, влияющих на работу неявных правил или содержащих параметры, которые пользователь может переопределять (смотрите раздел "Перекрытие" переменных).

Некоторые переменные имеют имена, состоящие лишь из одного или нескольких символов пунктуации. Это, так называемые, автоматические переменные; они используются специальным образом. Смотрите раздел Автоматические переменные.

Обращение к переменным

Для подстановки значения переменной, напишите знак доллара, за которым следует имя переменной, заключенное в круглые или фигурные скобки: обе записи `$(foo)' и`${foo}' представляют собой ссылку на переменную foo. Из-за подобного специального значения символа `$', для получения знака доллара в имени файла или команде нужно использовать запись `$$'.

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

objects = program.o foo.o utils.o
program : $(objects)
        cc -o program $(objects)

$(objects) : defs.h

Ссылки на переменную обрабатываются при помощи простой текстовой подстановки. Таким образом, правило, описывающее процесс компиляции программы из исходного файла `prog.c', могло бы выглядеть так:

foo = c
prog.o : prog.$(foo)
        $(foo)$(foo) -$(foo) prog.$(foo)

Пробелы, находящиеся в операторе присваивания перед новым значеним переменной, игнорируются, поэтому переменная foo будет содержать строку `c'. (Не следует, однако, принимать этот пример "всерьез" и писать подобным образом свои make-файлы!)

Если за знаком доллара следует символ, отличный от доллара, открывающейся круглой скобки или открывающейся фигурной скобки, то этот одиночный символ рассматривается как имя переменной. Таким образом, вы можете обратиться к переменной x, используя запись`$x'. Однако, такая практика крайне нежелательна, за исключением случаев обращения к автоматическим переменным (смотрите раздел Автоматические переменные).

Две разновидности (flavors) переменных

В GNU make есть два способа, с помощью которых переменные могут получить свое значение. Мы называем это двумя разновидностями (flavors) переменных. Две разновидности отличаются тем, каким образом переменная была определена и что происходит при вычислении ее значения.

Первая разновидность - это рекурсивно вычисляемые (recursively expanded) переменные. Такие переменные определяются с помощью`=' (смотрите раздел Установка значения переменной) или директивы define (смотрите раздел Многострочные переменные). Значение этой переменной запоминается точно в том виде, как вы его указали; если оно содержит ссылки на другие переменные, то эти ссылки будут вычислены (заменены своими текстовыми значениями) только в момент вычисления значения самой переменной (когда будет вычисляться какая-то другая строка, где использована эта переменная). Этот процесс называется рекурсивным вычислением (recursive expansion).

Например, следущий make-файл:

foo = $(bar)
bar = $(ugh)
ugh = Huh?

all:;echo $(foo)

выдаст на экран `Huh?': при вычислении ссылки `$(foo)', она будет заменена на`$(bar)', которая, свою очередь, заменена на `$(ugh)', которая , наконец, будет расширена в`Huh?'.

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

CFLAGS = $(include_dirs) -O
include_dirs = -Ifoo -Ibar

будет работать так, как и ожидалось: ссылки на переменную `CFLAGS'будут "раскрываться" в текст`-Ifoo -Ibar -O'. С другой стороны, серьезный недостаток заключается в том, что вы не можете ничего "добавить" к переменной, наподобие

CFLAGS = $(CFLAGS) -O

поскольку это вызовет бесконечный цикл при попытке вычислить ее значение. (На самом деле, make распознает ситуацию зацикливания и сообщает об ошибке.)

Другой недостаток рекурсивно вычисляемых переменных состоит в том, что все функции, на которые они ссылаются (смотрите раздел Функции преобразования текста) будут вычисляться заново при каждой "подстановке" этой переменной. Работа make при этом, разумеется, замедляется. Но еще хуже то, что результат выполнения функций wildcard и shell становится труднопредсказуемым, поскольку сложно в точности сказать, когда и сколько раз эти функции будут выполнены.

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

Упрощенно вычисляемые (simply expanded) переменные определяются с помощью`:=' (смотрите раздел Установка значения переменной). Значение такой переменной вычисляется (с расширением всех ссылок на другие переменные и вычислением функций) только в момент присваивания ей нового значения. После определения переменной, ее значение представляет собой обычный текст, уже не содержащий ссылок на другие переменные. Таким образом,

x := foo
y := $(x) bar
x := later

эквивалентно

y := foo bar
x := later

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

Вот чуть более сложный пример, иллюстрирующей использование`:=' совместно с функцией shell. (Смотрите раздел Функция shell.) Этот пример также демонстрирует использование переменной MAKELEVEL, которая изменяется во время переходов "с уровня на уровень" при рекурсивном использовании make. Смотрите раздел Связь с make "нижнего уровня" через переменные.

ifeq (0,${MAKELEVEL})
cur-dir   := $(shell pwd)
whoami    := $(shell whoami)
host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
endif

Преимущество использования `:=' заключается в том, что типичная команда `спуска в подкаталог' будет выглядеть как:

${subdirs}:
      ${MAKE} cur-dir=${cur-dir}/$@ -C $@ all

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

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

nullstring :=
space := $(nullstring) # end of the line

Здесь, значением переменной space будет в точности один пробел. Комментарий`# конец строки' включен только для большей ясности. Поскольку конечные пробелы не удаляются из значения переменной, единственного пробела в конце строки было бы достаточно для получения нужного эффекта (но такая запись была бы менее понятна). Если вы помещаете пробел в конец значения переменной, хорошей идеей будет помещение соответствующего комментария в конец строки, поясняющего ваши намерения. И наоборот, если для вас не желательно наличие пробелов в конце значения переменной, помните, что вы не должны помещать каких-либо комментариев в конец строки после пробелов:

dir := /foo/bar    # directory to put the frobs in

Здесь, значением переменной dir будет строка `/foo/bar '(с четырьмя пробелами в конце), чего вы, скорее всего, совсем не хотели. (Представьте себе, что случится со строкой, наподобие`$(dir)/file' в этом случае!)

GNU make поддерживает еще один оператор присваивания`?='. Он называется оператором условного присваивания, поскольку срабатывает лишь в том случае, когда переменная еще не была определена. Например, выражение:

FOO ?= bar

эквивалентно (смотрите раздел Функция origin):

ifeq ($(origin FOO), undefined)
  FOO = bar
endif

Обратите внимание на то, что переменная, содержащая "пустое" значение, все равно считается определенной, и оператор`?=' не будет присваивать ей нового значения.

"Расширенные" способы обращения к переменным

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

Ссылка с заменой (substitution reference)

При использовании ссылки с заменой (substitution reference), вместо нее подставляется значение переменной, модефицированное указанным вами способом. Такая ссылка имеет форму`$(переменная:a=b)' (или`${переменная:a=b}'). Это значит, что должно быть взято значение переменной переменная, и каждая найденная в нем цепочка символов a, находящаяся в конце слова, должна быть заменена на цепочку символов b.

Говоря "находящаяся в конце слова", мы имеем ввиду, что за последовательностью символов a должен следовать пробел, либо она должна находиться в конце строки (со значением переменной); только в этих случаях она будет заменена на последовательность b. Все прочие цепочки a (не удовлетворяющие указанным условиям) будут оставлены без изменений. В следующем примере:

foo := a.o b.o c.o
bar := $(foo:.o=.c)

переменная `bar' получит значение `a.c b.c c.c'. Смотрите раздел Установка значения переменной.

На самом деле, ссылка с заменой представляет собой "укороченый" вариант использования функции patsubst (смотрите раздел Функции анализа и подстановки строк). Для поддержания совместимости с другими версиями make, мы поддерживаем оба этих механизма - функцию patsubst и ссылки с заменой.

Другой вариант ссылки с заменой соизмерим по "мощности" с использование функции patsubst. Он имеет аналогичную форму`$(переменная:a=b)', но теперь в строке a должен присутствовать одиночный символ `%'. Этот вариант ссылки с заменой эквивалентен `$(patsubst a,b,$(переменная))'. Смотрите раздел Функции анализа и подстановки строк, где описана работа функции patsubst. В следующем примере:

foo := a.o b.o c.o
bar := $(foo:%.o=%.c)

переменная `bar' получит значение `a.c b.c c.c'.

Вычисляемые имена переменных (computed variable names)

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

Внутри имени переменной может находится ссылка на другую переменную. Это называется вычисляемым именем переменной (computed variable name) или вложенной ссылкой (nested variable reference). В следущем примере:

x = y
y = z
a := $($(x))

переменная a получит значение `z': ссылка `$(x)'внутри выражения`$($(x))' будет заменена на `y', так что строка `$($(x))'будет преобразована в `$(y)' и, далее, расширена в `z'. Здесь имя переменной не указано "прямо", а вычисляется при расширении выражения`$(x)'. Ссылка `$(x)' здесь находится внутри другой ссылки на переменную.

Предыдущий пример демонстрировал два "уровня вложенности". На самом деле, число таких уровней может быть неограниченным. Следующий пример демонстрирует три "уровня вложенности":

x = y
y = z
z = u
a := $($($(x)))

Здесь самая внутренняя ссылка `$(x)' заменяется на `y', так что строка`$($(x))' расширяется в `$(y)', которая, в свою очередь, расширяется в`z'; теперь мы получаем ссылку `$(z)', которая заменяется на`u'.

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

x = $(y)
y = z
z = Hello
a := $($(x))

переменная a получит значение `Hello': строка `$($(x))' преобразуется в строку`$($(y))', которая преобразуется в строку `$(z)' которая, в свою очередь, имеет значение`Hello'.

Вложенные ссылки могут содержать ссылки с заменой, а также вызовы функций (смотрите раздел Функции преобразования текста). Вот пример, в котором используется функция subst (смотрите раздел Функции анализа и подстановки строк):

x = variable1
variable2 := Hello
y = $(subst 1,2,$(x))
z = y
a := $($($(z)))

Здесь, переменная a получает значение `Hello'. Вряд ли кто-нибудь будет писать подобным образом, однако, это пример действительно работает: выражение `$($($(z)))' преобразуется в строку `$($(y))', которая, затем, преобразуется в `$($(subst 1,2,$(x)))'. Далее, из переменной x берется ее текущее значение (`variable1'), которое, с помощью подстановки, заменяется на `variable2'. После этого, выражение выглядит как`$(variable2)', и его значеним является строка`Hello'.

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

a_dirs := dira dirb
1_dirs := dir1 dir2

a_files := filea fileb
1_files := file1 file2

ifeq "$(use_a)" "yes"
a1 := a
else
a1 := 1
endif

ifeq "$(use_dirs)" "yes"
df := dirs
else
df := files
endif

dirs := $($(a1)_$(df))

переменная dirs получит значение одной из переменных (a_dirs 1_dirs, a_files или 1_files) в зависимости от значений переменных use_a и use_dirs.

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

a_objects := a.o b.o c.o
1_objects := 1.o 2.o 3.o

sources := $($(a1)_objects:.o=.c)

переменная sources получит значение `a.c b.c c.c' либо`1.c 2.c 3.c', в зависимости от значения переменной a1.

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

ifdef do_sort
func := sort
else
func := strip
endif

bar := a d b g q c

foo := $($(func) $(bar))

в переменную `foo', вместо ожидаемого значения (результата применения функций sort или strip к аргументу `a d b g q c'), будет записана строка`sort a d b g q c' или `strip a d b g q c'. Возможно, в будущем подобное ограничение будет снято, если это окажется полезным.

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

dir = foo
$(dir)_sources := $(wildcard $(dir)/*.c)
define $(dir)_print
lpr $($(dir)_sources)
endef

В данном примере определяются переменные `dir',`foo_sources', и `foo_print'.

Обратите внимание, что вложенные ссылки на переменные и рекурсивно вычисляемые переменные (смотрите раздел Две разновидности переменных), - это разные концепции, хотя при написаниии "нетривиальных" make-файлов, они часто используются совместно.

Как переменные получают свои значения

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

Установка значения переменной

Для установки значения переменной внутри make-файла, используется строка, начинающаяся с имени переменной, за которым следует`=' или `:='. Все, что в этой строке следует за символом`=' или `:=', становится значением переменной. В следующем примере:

objects = main.o foo.o bar.o utils.o

определяется переменная с именем objects. Пробелы "вокруг" имени переменной и после`=', игнорируются.

Переменные, определенные с помощью `=', являются рекурсивно вычисляемыми (recursively expanded) переменными. Переменные, определенные с помощью `:=', являются упрощенно вычисляемыми (simply expanded) переменными; их определения могут содержать ссылки на другие переменные, которые будут вычислены до того, как будет сделано определение (иными словами, до того, как в переменную будет записано новое значение). Смотрите раздел Две разновидности переменных.

Имена переменных могут содержать ссылки на другие переменные и функции, которые будут вычислены (во время чтения make-файла) для получения действительного имени переменной.

На длину строки, являющейся значением переменной, не накладывается каких-либо ограничений (за исключением доступного программе объема памяти). "Хорошей идеей" является разбиение длинного определения переменной на несколько отдельных строк с помощью символа '\', за которым следует символ перевода строки. Такое разбиение никак не отразится на работе make, но будет способствовать повышению удобочитаемости make-файла.

Большинство переменных, значение которых вы нигде не устанавливали, рассматриваются как содержащие пустую строку. Некоторые переменные имеют заранее определенные непустые начальные значения (которые, разумеется, вы можете изменить обычным образом; смотрите раздел Используемые в неявных правилах переменные). Некоторые специальные переменные автоматически получают новое значение при обработке каждого правила; они называются автоматическими переменными (смотрите раздел Автоматические переменные).

Если вы хотите, чтобы переменная получила новое значение только в том случае, если ей еще не было присвоено какого-либо значения, вместо `=' используйте оператор`?='. Следующие два фрагмента make-файла производят одинаковый эффект (смотрите раздел Функция origin):

FOO ?= bar

и

ifeq ($(origin FOO), undefined)
FOO = bar
endif

Добавление текста к переменной

Часто возникает необходимость добавить некоторый текст к значению уже определенной переменной. Вы можете это сделать с помощью оператора `+=', например:

objects += another.o

Здесь, к значению переменной objects добавляется текст`another.o' (предваренный одиночным пробелом). Так, в результате выполнения фрагмента:

objects = main.o foo.o bar.o utils.o
objects += another.o

переменная objects получит значение `main.o foo.o bar.o utils.o another.o'.

Примерный аналог этого фрагмента без использования `+='может выглядеть так:

objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o

Однако, аналогия здесь не полная, поскольку работа оператора `+='отличается некоторыми деталями, которые проявляются при работе с более сложными значениями переменных.

Если рассматриваемая переменная до сих пор не была определена, оператор `+='ведет себя как обычный `=', определяя рекурсивно вычисляемую переменную. Если же переменная была ранее определена, поведение оператора `+=' будет зависеть от ее разновидности (смотрите раздел Две разновидности переменных).

Когда вы что-либо добавляете с помощью `+=' к значению уже определенной переменной, make, по существу, действует так, как если бы этот дополнительный текст был включен в первоначальное определение переменной. Предположим, что переменная была ранее определена с помощью `:=' и является, вследствие этого, упрощенно вычисляемой переменной. Тогда, при добавлении к ней нового текста, оператор `+=' предварительно его "расширит" (аналогично тому, как это делает оператор `:='; смотрите раздел Установка значения переменной, где описана работа оператора `:='). Таким образом, фрагмент

variable := value
variable += more

эквивалентен следующему:

variable := value
variable := $(variable) more

С другой стороны, при использовании оператора `+=' с рекурсивно вычисляемой переменной, make работает немного по-другому. Вспомните, что когда вы определяете подобную переменную, make не сразу вычисляет ссылки на функции и другие переменные, присутствующие в устанавливаемом для нее значении. Вместо этого, make запоминает указанный вами текст в "оригинальном" виде, так что все присутствующие в нем ссылки на переменные и функции остаются и могут быть вычислены позднее, когда переменная будет "раскрываться" (смотрите раздел Две разновидности переменных). Таким образом, при использовании оператора `+=' с рекурсивно вычисляемой переменной, указанный вами текст добавляется к "нераскрытому" значению, которое хранится внутри переменной. Поэтому, следующий фрагмент:

variable = value
variable += more

примерно эквивалентен:

temp = value
variable = $(temp) more

(разумеется, на самом деле, никакой переменной temp не создается). Важность этого становится понятной при рассмотрении более сложных случаев, когда "старое" значение переменной содержит ссылки на другие переменные. Рассмотрим типичный пример:

CFLAGS = $(includes) -O
...
CFLAGS += -pg # enable profiling

В первой строке этого примера определяется переменная CFLAGS, которая содержит ссылку на другую переменную с именем includes. (переменная CFLAGS используется в неявных правилах для компиляции программ на языке Си; смотрите раздел Перечень имеющихся неявных правил.) Использование оператора `=' определяет переменную CFLAGS как рекурсивно вычисляемую, и, значит, выражение `$(includes) -O'не будет вычисляться вв момент определения этой переменной. Таким образом, переменная includes совсем не обязана к этому времени быть определена. Достаточно, чтобы она была определена к тому моменту, когда будет вычисляться значение переменной CFLAGS. Если мы попробуем обойтись без оператора`+=', придется сделать что-нибудь, наподобие:

CFLAGS := $(CFLAGS) -pg # enable profiling

К сожалению, этот фрагмент работает не совсем так, как хотелось бы. Из-за использования оператора `:='переменная CFLAGS становится упрощенно вычисляемой; это означает, что make "раскроет" выражение `$(CFLAGS) -pg' перед тем, как присвоить его переменной. Если переменная includes еще не была определена, в качестве результата "раскрытия" мы получим строку ` -O -pg', и последующее определение includes уже не сможет повлиять на этот результат. Напротив, при использовании `+=' в переменную CFLAGS запишется нераскрытое значение `$(includes) -O -pg'. Таким образом, мы сохраняем ссылку на переменную includes. Если переменная includes будет определена где-нибудь позднее, то ссылка на`$(CFLAGS)' будет использовать ее значение.

Директива override

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

override переменная = значение

или

override переменная := значение

При добавлении текста к переменной, определенной через командную строку, используйте конструкцию:

override переменная += добавляемый-текст

Смотрите раздел Добавление текста к переменной.

Разумеется, директива override была придумана не для "экскалации войны" между make-файлом и параметрами командной строки. Идея заключалась в том, чтобы дать возможность изменять или дополнять передаваемые пользователем в командной строке значения.

Предположим, вы хотите, чтобы компилятор Си всегда запускался с опцией `-g'и, в то же время, хотели бы дать пользователю возможность самостоятельно указать необходимые опции компиляции. Это можно сделать с помощью директивы override:

override CFLAGS += -g

Директиву override можно также использовать совместно с директивой define. Выглядит это аналогично:

override define foo
bar
endef

Смотрите следующий раздел, где описана работы директивы define.

Многострочные переменные

Другой способ установки значения переменной - использование директивы define. Эта директива имеет несколько необычный синтаксис, позволяющий включать в ее значение символы перевода строки. С ее помощью удобно определять именованные командные последовательности (смотрите раздел Именованные командные последовательности).

На первой строке находится только название директивы (define), за которым следует имя переменной. Значение переменной указывается в следующих строках. Меткой конца значения переменной служит строка, содержащая единственное слово endef. За исключением синтаксических различий, директива define работает аналогично оператору `=', создавая рекурсивно вычисляемую переменную (смотрите раздел Две разновидности переменных). Имя этой переменной может содержать функции и ссылки на другие переменные, которые будут "вычислены" в момент чтения директивы define для нахождения действительного имени определяемой переменной.

define two-lines
echo foo
echo $(bar)
endef

При использовании обычного оператора присваивания, значение переменной не может содержать символов перевода строки. При использовании же директивы define, символы перевода строки (за исключением символа, находящегося перед строкой с endef) становятся частью значения переменной.

Предыдущий пример функционально подобен:

two-lines = echo foo; echo $(bar)

поскольку две команды, разделенные точкой с запятой работают во многом также, как и две отдельные команды. Заметьте, однако, что для команд, расположенных в двух отдельных строках, make будет вызывать командный интерпретатор дважды, запуская каждую команду в своей отдельной копии интерпретатора. Смотрите раздел Исполнение команд.

Для переменных, определенных при помощи define, также может использоваться директива override. Как обычно, при ее использовании, определение переменной внутри make-файла будет иметь "приоритет" перед определением этой же переменной из командной строки:

override define two-lines
foo
$(bar)
endef

Смотрите раздел Директива override.

Переменные из операционного окружения (environment)

Переменные в make могут "приходить" из программного окружения (environment), в котором make была запущена. Каждая переменная среды (environment variable), видимая для make, преобразуется в соответствующую переменную make с таким же именем и значением. Однако, явное определение такой же переменной внутри make-файла или через командную строку, "перекроет" значение, полученное из операционной среды. (При наличии опции `-e', значения из переменных среды будут иметь "приоритет" перед значениями, определенными в make-файле. Смотрите раздел Обзор опций. Но мы не рекомендуем использовать такую практику.)

Таким образом, установив, например, переменную среды CFLAGS, вы заставите большинство make-файлов запускать компилятор Си с указанными вами опциями. Такая методика относительно безопасна для переменных со стандартными или общепринятыми значениями, поскольку вряд-ли make-файлы будут использовать такие переменные для каких-либо других целей. (Разумеется, стропроцентной гарантии надежности здесь дать нельзя; например, некоторые make-файлы самостоятельно устанавливают переменную CFLAGS и, таким образом, не зависят от значения соответствующей переменной среды.)

При рекурсивном вызове make, переменные, определенные на "верхних уровнях" могут быть переданы на "нижние уровни" через операционное окружение (смотрите раздел Рекурсивный вызов make). По умолчанию, через операционную среду будут передаваться только переменные, которые были "первоначально" в ней определены, а также переменные, определенные с помощью командной строки. Для передачи через операционную среду любых других переменных, следует использовать директиву export. Смотрите раздел Связь с make "нижнего уровня" через переменные, где обсуждается этот вопрос.

Использовать переменные среды для других целей мы не рекомендуем. Плохо, если поведение make-файлов будет зависеть от значения (неподконтрольных им) переменных среды; это может привести к тому, что один и тот же make-файл у разных пользователей будет работать по-разному, выдавая разные результаты. Это противоречило бы самой идее make-файлов.

Скорее всего, такие проблемы возникли бы и с переменной SHELL, которая обычно присутствует в операционной среде для указания выбранной пользователем командной оболочки. Было бы очень нежелательно, чтобы этот выбор пользователя влиял на работу make. Поэтому make игнорирует значение переменной среды SHELL (за исключением случаев, когда она работает в операционных системах MS-DOS и MS-Windows, где переменная SHELL , как правило, не устанавливается. Смотрите раздел Исполнение команд.)

Целе-зависимые (target-specific) значения переменных

Значения переменных в make обычно являются глобальными; другими словами, они одинаковы - в каком бы месте make-файла они ни вычислялись. Одно из исключений - автоматические переменные (смотрите раздел Автоматические переменные).

Другое исключение - это целе-зависимые значения переменных (target-specific variable values). С их помощью вы можете задать для одной и той же переменной разные значения в зависимости от того, какую цель в данный момент обновляет make. Так же как и автоматические переменные, эти значения доступны только в контексте выполняемых для обновления цели команд (а также других целе-зависимых операторов присваивания).

Целе-зависимые значения переменных устанавливаются с помощью конструкции вида:

цель ... : присваивание-переменной

или:

цель ... : override присваивание-переменной

При указании сразу нескольких целей, для каждой из них создается свое отдельное целе-зависимое значение.

Присваивание-переменной может быть любой допустимой формой оператора присваивания; рекурсивной (`='), статической (`:='), дополняющей (`+='), или условной (`?='). Все переменные, участвующие в присваивании-переменной, вычисляются "в контексте" указанных целей: таким образом, все ранее определенные для этих целей целе-зависимые переменные будут здесь доступны. Обратите внимание, что целе-зависимые значения переменных не обязательно должны принадлежать к одной разновидности (рекурсивно вычисляемые или упрощенно вычисляемые).

Целе-зависимые переменные имеют такой же приоритет как и любые другие переменные make-файла; переменные, определенные через командную строку (или "взятые" из переменных среды при наличии опции `-e') будут иметь перед ними "приоритет". По-прежнему, использование директивы override позволит целе-зависимой переменной избежать "перекрытия".

Одна из особенностей целе-зависимых переменных заключается в следующем: когда вы определили целе-зависимую переменную, ее значение также будет "видно" для всех пререквизитов данной цели (конечно, если для пререквизитов не определены свои собственные целе-зависимые переменные). Так, например, в следующем выражении:

prog : CFLAGS = -g
prog : prog.o foo.o bar.o

переменная CFLAGS будет иметь значение `-g' во всех командах, выполняемых для цели `prog', а также (обратите внимание!) для целей `prog.o', `foo.o', `bar.o', и всех их пререквизитов.

Шаблонно-зависимые (pattern-specific) значения переменных

В дополнении к целе-зависимым значениям переменных (смотрите раздел Целе-зависимые значения переменных), GNU make поддерживает шаблонно-зависимые значения переменных. Эти переменные считается определенными для всех целей, подходящих под указанный шаблон. Определенные таким образом переменные "принимаются в рассчет" после целе-зависимых переменных, явно определенных для рассматриваемой цели но до того, как будут рассмотрены целе-зависимые переменные "родительских" целей.

Шаблонно-зависимые переменные устанавливаются с помощью конструкции вида:

шаблон ... : присваивание-переменной

или:

шаблон ... : override присваивание-переменной

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

В следующем примере:

%.o : CFLAGS = -O

переменной CFLAGS будет присвоено значение `-O' при обработке всех целей, удовлетворяющих шаблону %.o.

Условные части (conditional parts) make-файла

Условная конструкция (conditional) заставляет make обрабатывать или игнорировать часть make-файла в зависимости от значения некоторых переменных. В качестве условия может использоваться сравнение двух переменных или сравнение переменной с константной строкой. Условные конструкции управляют тем, "каким" make "увидит" обрабатываемый make-файл, и, поэтому, их нельзя использовать для управления командами оболочки во время их исполнения.

Пример условной конструкции

В следующем примере, условная конструкция инструктирует make использовать разные наборы библиотек в зависимости от того, имеет ли переменная CC значение `gcc' или нет. Условная конструкция работает, управляя тем, какая из двух командных строк будет использоваться в качестве команды правила. В результате, при запуске make с параметром`CC=gcc' произойдет не только изменение используемого компилятора, но и изменение набора библиотек, с которыми будет компоноваться собираемая программа.

libs_for_gcc = -lgnu
normal_libs =

foo: $(objects)
ifeq ($(CC),gcc)
        $(CC) -o foo $(objects) $(libs_for_gcc)
else
        $(CC) -o foo $(objects) $(normal_libs)
endif

В этой условной конструкции используется три директивы: ifeq, else и endif.

Директива ifeq определяет начало условной конструкции и указывает само условие. Она имеет два параметра, разделенных запятой и заключенных в скобки. Эти параметры вычисляются и, затем, сравниваются. Если два параметра совпадают, строки, следующие за ifeq, обрабатываются; в противном случае они игнорируются.

При использовании директивы else, следующие за ней строки должны быть обработаны, если условие (из директивы ifeq) не выполняется. В предыдущем примере, это означает использование второй, альтернативной команды компоновки, если первая альтернатива не будет использована. Наличие директивы else в условной конструкции не является обязательным.

Директива endif завершает условную конструкцию. Следующие за этой директивой строки, относятся уже к "безусловной" части make-файла. Наличие директивы endif является обязательным.

Как видно из предыдущего примера, условные конструкции работают на "текстовом" уровне: отдельные строки рассматриваются как часть make-файла либо игнорируются, в зависимости от проверяемого условия. Поэтому, более крупные синтаксические элементы (например, правила) могут пересекать "границы" условной конструкции.

Если переменная CC будет содержать значение`gcc', то приведенный выше пример будет работать как:

foo: $(objects)
        $(CC) -o foo $(objects) $(libs_for_gcc)

При любом другом значении переменной CC, тот же пример будет работать как:

foo: $(objects)
        $(CC) -o foo $(objects) $(normal_libs)

Аналогичного результата можно добиться, заключив оператор присваивания переменной нужного значения в условную конструкцию, и, затем, использовать эту переменную "безусловно":

libs_for_gcc = -lgnu
normal_libs =

ifeq ($(CC),gcc)
  libs=$(libs_for_gcc)
else
  libs=$(normal_libs)
endif

foo: $(objects)
        $(CC) -o foo $(objects) $(libs)

Синтаксис условных конструкций

Синтаксис простой (без директивы else) условной конструкции выглядит следующим образом:

условная-директива
фрагмент-для-выполненного-условия
endif

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

Синтаксис "сложной" условной конструкции выглядит так:

условная-директива
фрагмент-для-выполненного-условия
else
фрагмент-для-невыполненного-условия
endif

При выполнении условия, используется фрагмент фрагмент-для-выполненного-условия; иначе, используется фрагмент фрагмент-для-невыполненного-условия. Фрагмент фрагмент-для-невыполненного-условия может содержать любое количество строк.

Условная-директива имеет одинаковый синтаксис как в простой, так и в сложной условной конструкции. Имеется четыре разных директивы, проверяющих разные условия. Вот они:

ifeq (параметр1, параметр2)
ifeq 'параметр1' 'параметр2'
ifeq "параметр1" "параметр2"
ifeq "параметр1" 'параметр2'
ifeq 'параметр1' "параметр2"
Значения параметров параметр1 и параметр2 вычисляются и сравниваются между собой. При их совпадении используется фрагмент фрагмент-для-выполненного-условия; иначе используется фрагмент фрагмент-для-невыполненного-условия (если он имеется). Часто возникает необходимость проверить - содержит ли переменная какое-нибудь "непустое" значение. Трудность состоит в том, что после разного рода преобразований и вычислений функций, значение, выглядящее как "пустое", будет, на самом деле, состоять из пробелов и, таким образом, не будет считаться "пустым". Для того, чтобы избежать интерпретации пробелов как непустых значений, можно воспользоваться функцией strip (смотрите раздел Функции анализа и подстановки строк). В следующем примере:
ifeq ($(strip $(foo)),)
фрагмент-для-случая-пустого-значения
endif
фрагмент фрагмент-для-случая-пустого-значения будет использован даже в том случае, если значение переменной $(foo) будет состоять из пробелов.
ifneq (параметр1, параметр2)
ifneq 'параметр1' 'параметр2'
ifneq "параметр1" "параметр2"
ifneq "параметр1" 'параметр2'
ifneq 'параметр1' "параметр2"
Значения параметров параметр1 и параметр2 вычисляются и сравниваются между собой. Если они не совпадают, используется фрагмент фрагмент-для-выполненного-условия; иначе используется фрагмент фрагмент-для-невыполненного-условия (если он имеется).
ifdef имя-переменной
Если переменная имя-переменной имеет непустое значение, будет использован фрагмент фрагмент-для-выполненного-условия; иначе, будет использован фрагмент фрагмент-для-невыполненного-условия (если таковой имеется). Переменные, которые еще не определены, рассматриваются как имеющие пустые значения. Обратите внимание, что директива ifdef просто проверяет - имеет ли переменная непустое значение. Она никогда не пытается вычислить это значение и проверить - не пустое ли оно. Как следствие, проверка с помощью ifdef будет возвращать "истину" для всех определений, кроме определений, подобных: foo =. Для проверки "вычисленного" значения переменной, используйте конструкцию ifeq ($(foo),). В следующем примере:
bar =
foo = $(bar)
ifdef foo
frobozz = yes
else
frobozz = no
endif
переменная `frobozz' получит значение `yes', а в примере:
foo =
ifdef foo
frobozz = yes
else
frobozz = no
endif
переменная `frobozz' будет установлена в `no'.
ifndef имя-переменной
Если переменная имя-переменной имеет пустое значение, будет использован фрагмент фрагмент-для-выполненного-условия; иначе, будет использован фрагмент фрагмент-для-невыполненного-условия (если такой фрагмент имеется).

В начале строки с условной директивой могут находится пробелы (которые игнорируются) но не символ табуляции. (При наличии символа табуляции такая строка рассматривалась бы как команда правила.) За этим маленьким исключением, пробелы и символы табуляции могут свободно использоваться в любом месте строки с условной директивой (только, разумеется, не внутри имени самой директивы и не внутри аргументов). В конце строки может располагаться комментарий, начало которого обозначается символом `#'.

Две другие директивы, используемые в условных конструкциях - это директивы else и endif. Каждая из этих директив записывается в одно слово и не имеет параметров. В начале строк с этими директивами, могут находится дополнительные пробелы (которые будут игнорированы), а в конце строк - пробелы и символы табуляции (которые также будут игнорированы). В конце таких строк может располагаться комментарий, начало которого обозначается символом `#'.

Условные конструкции влияют на то, какие строки make-файла в действительности будет использовать make. При выполнении указаного условия, make будет рассматривать строки фрагмент-для-выполненного-условия как часть make-файла; при невыполнении условия, эти строки будут игнорироваться. Вследствие этого, синтаксические единицы make-файла (такие как правила) вполне могут пересекать границы условной конструкции.

Условия, указанные в условных конструкциях, вычисляются в момент чтения make-файла. Как следствие, в качестве условий не может использоваться проверка автоматических переменных, поскольку они являются неопределенными до момента запуска команд правила (смотрите раздел Автоматические переменные).

Во избежании неприятных конфузов, не разрешается "начинать" условную конструкцию в одном make-файле и "заканчивать" ее в другом. Однако, внутри условной конструкции вы можете использовать директиву include (при условии, что включаемый make-файл не будет пытаться "завершить" эту условную конструкцию).

Проверка опций запуска make в условных конструкциях

Вы можете написать условную конструкцию, проверяющую наличие определенных опций (например, `-t'), указанных при запуске make. Это можно сделать, используя переменную MAKEFLAGS совместно с функцией findstring (смотрите раздел Функции анализа и подстановки строк). Необходимость в этом может возникнуть, например, в ситуации, когда одного лишь использования команды touch недостаточно для обновления файла.

Функция findstring определяет, входит ли одна строка в другую в качестве подстроки. Если, например, вы хотите проверить наличие опции `-t', используйте`t' как первую строку (первый параметр функции), а переменную MAKEFLAGS - как другую строку (второй параметр функцции).

В следующем примере, в качестве завершающего шага пометки архивного файла как "обновленного", используется команда`ranlib -t':

archive.a: ...
ifneq (,$(findstring t,$(MAKEFLAGS)))
        +touch archive.a
        +ranlib -t archive.a
else
        ranlib archive.a
endif

Префикс `+' помечает командные строки как "рекурсивные". Эти команды будут выполняться даже при наличии опции `-t'. Смотрите раздел Рекурсивный вызов make.

Функции преобразования текста

С помощью функций, вы можете производить в make-файле некоторую текстовую обработку, определяя с ее помощью имена обрабатываемых файлов или используемые команды. При вызове функции, вы указываете ее имя и некоторый текст (параметры), который будет обрабатываться этой функцией. Результат работы функции будет "подставлен" в make-файл на месте ее вызова (подобно тому, как вместо ссылки на переменную подставляется ее значение).

Синтаксис вызова функций

Вызов функции внешне напоминает ссылку на переменную. Он выглядит так:

$(функция
параметры)

или так:

${функция
параметры}

Здесь функция является именем функции. В make имеется некоторое количество "встроенных" функций. С помощью встроенной функции call вы можете определить свою собственную функцию.

Параметры являются параметрами функции. От имени функции они отделяются одним или несколькими пробелами или символами табуляции. При наличии нескольких параметров, они отделяются друг от друга запятыми. Такие пробелы и запятые не рассматриваются как часть значения параметра. Разделители, которые вы использовали для обозначения вызова функции (круглые или фигурные скобки), могут появляться в аргументах только "попарно"; другие символы разделителей могут появляться и поодиночке. Если аргументы сами, в свою очередь, содержат ссылки на другие функции или переменные, для всех ссылок рекомендуется использовать один и тот же вид разделителей; то есть, например, писать`$(subst a,b,$(x))', а не `$(subst a,b,${x})'. Такая запись является не только более ясной, но и более "простой" для make (только один вид разделителей используется при поиске конца ссылки).

Перед тем, как аргумент будет передан для обработки в функцию, вычисляются все содержащиеся в нем ссылки на переменные и функции. Обработка аргументов производится в том порядке, как они перечислены.

Запятые и непарные скобки не могут "явным" образом появляться в аргументах функции; нельзя также "явным" образом указать наличии ведущих пробелов в первом параметре функции. Однако, эти символы могут быть вставлены в аргумент с помощью ссылки на переменные. Это можно сделать, определив, например, переменные comma и space, значениями которых будут, соответственно, одиночные символы запятой и пробела. Далее, значения этих переменных могут быть подставлены в любое место аргументов, где требуется наличие соответствующего символа. Например:

comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
# bar is now `a,b,c'.

Здесь, с помощью функции subst, каждый символ пробела, содержащийся в переменной foo, заменяется на символ запятой.

Функции анализа и подстановки строк

Ниже перечислены функции, оперирующие со строками:

$(subst заменяемый_фрагмент,замена,текст)
Производит текстовую замену в тексте текст: каждой вхождение подстроки заменяемый_фрагмент заменяется на фрагмент замена. Результат подставляется в место вызова функции. Результатом следующего примера:
$(subst ee,EE,feet on the street)
будет строка `fEEt on the strEEt'.
$(patsubst шаблон,замена,текст)
Находит в тексте разделенные пробелом слова, удовлетворяющие шаблону и заменяет их на строку замена. Шаблон может содержать символ `%', который работает как специальный шаблонный символ, соответствующий любому количеству произвольных символов внутри слова. Если строка замена также содержит символ `%', он будет заменен текстом, соответствующим символу `%' в шаблоне. Специальное значение символа `%'может быть отменено предшествующим ему символом`\'. Специальное значение символа `\', который мог бы отменить специальное значение символа`%', может, в свою очередь, быть отменено дополнительным символом `\'. Символы `\', отменяющие специальное значение символов `%' и`\', удаляются из шаблона перед тем, как он будет использоваться для сравнения или подстановки. Символы `\', не могущие повлиять на трактовку`%', остаются нетронутыми. Например, в шаблоне `the\%weird\\%pattern\\' за строкой `the%weird\' следует шаблонный символ`%' и строка `pattern\\'. Два завершающих символа `\' остаются нетронутыми, поскольку они не могут повлиять на трактовку символа`%'. Пробельные символы между словами преобразуются в одиночные пробелы; начальные и конечные пробелы отбрасываются. Например, результатом выражения
$(patsubst %.c,%.o,x.c.c bar.c)
будет строка `x.c.o bar.o'. Ссылка с заменой (смотрите раздел Ссылка с заменой) является упрощенным способом получения эффекта, аналогичного использованию функции patsubst. Выражение:
$(переменная:шаблон=замена)
эквивалентно
$(patsubst шаблон,замена,$(переменная))
Еще одна упрощенная форма записи имеется для распространенного способа использования функции patsubst: замены суффиксов в именах файлов. Выражение:
$(переменная:суффикс=замена)
эквивалентно:
$(patsubst %суффикс,%замена,$(переменная))
Пусть, например, у вас имеется список объектных файлов:
objects = foo.o bar.o baz.o
Тогда, для получения списка соответствующих исходных файлов, вы можете просто написать:
$(objects:.o=.c)
вместо того, чтобы использовать "обобщенную" форму записи:
$(patsubst %.o,%.c,$(objects))
$(strip строка)
Удаляет начальные и конечные пробелы из строки, а также заменяет все внутренние последовательности пробельных символов на одиночные пробелы. Так, результатом выражения`$(strip a b c )' будет строка `a b c'. Функция strip весьма полезна в условных конструкциях. Например, при использовании директив ifeq и ifneq для сравнения с пустой строкой`', обычно желательно, чтобы строка, целиком состоящая из пробельных символов, рассматривалась как пустая (смотрите раздел Условные части make-файла). Так, например, следующий фрагмент make-файла не всегда будет работать желаемым образом:
.PHONY: all
ifneq   "$(needs_made)" ""
all: $(needs_made)
else
all:;@echo 'Nothing to make!'
endif
Заменив в директиве ifneq ссылку на переменную`$(needs_made)' вызовом функции`$(strip $(needs_made))', мы получим более надежно работающую конструкцию.
$(findstring фрагмент,строка)
Производит поиск фрагмента в строке. В случае успеха (фрагмент найден) возвращает значение фрагмент; в противном случае, возвращается пустая строка. Эту функцию можно использовать в условных конструкциях для проверки наличия в рассматриваемой строке определенной подстроки. Результатами следующих двух примеров:
$(findstring a,a b c)
$(findstring a,b c)
будут, соответственно, строки `a' и `' (пустая строка). В разделе Проверка опций запуска make в условных конструкциях приведен достаточно реалистичный пример использования функции findstring.
$(filter шаблон...,текст)
Удаляет из текста все разделенные пробелами слова, которые не удовлетворяют ни одному из указанных шаблонов и возвращает только слова, подходящие под шаблоны. Шаблоны записываются с использованием шаблонного символа `%', аналогично тому, как это делается в функции patsubst (описана выше). Функция filter может быть использована для отделения друг от друга строк (например, имен файлов) разных "типов". В следующем примере:
sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
        cc $(filter %.c %.s,$(sources)) -o foo
объявляется, что цель `foo' зависит от файлов `foo.c', `bar.c', `baz.s' и `ugh.h', однако, при вызове компилятора, ему будут переданы только файлы `foo.c', `bar.c' и `baz.s'.
$(filter-out шаблон...,текст)
Удаляет из текста все разделенные пробелами слова, которые соответствуют какому-либо из перечисленных шаблонов, возвращая только слова, не соответствующие ни одному из шаблонов. Эта функция представляет собой "противоположность" функции filter. Если, например, у нас имеется такой фрагмент:
objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
то следующее выражение возвратит список объектных файлов, не входящих в`mains':
$(filter-out $(mains),$(objects))
$(sort список)
Отсортировывает слова из списка в лексикографическом порядке, удаляя дубликаты (повторяющейся слова). Результатом является список слов, разделенных одиночными пробелами. Так, результатом выражения
$(sort foo bar lose)
будет строка `bar foo lose'. Даже если вас не интересует лексикографическая сортировка, вы можете пользоваться фунцией sort просто для удаления повторяющихся слов.

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

Значение переменной VPATH представляет собой список имен каталогов, разделенных двоеточиями, например`src:../headers'. Сперва используем функцию subst для замены символов двоеточия на пробелы:

$(subst :, ,$(VPATH))

Полученный результат будет выглядеть как `src ../headers'. Далее, с помощью функции patsubst, преобразуем каждое из имен каталогов в соответствующую опцию `-I' компилятора. Полученное значение можно добавить к содержимому переменной CFLAGS, которая автоматически передается компилятору:

override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))

Как результат, к первоначальному значению переменной CFLAGS добавляется строка `-Isrc -I../headers'. Директива override была использована для того, чтобы изменить значение переменной CFLAGS даже в том случае, если она была задана с помощью командной строки (смотрите раздел Директива override).

Функции для обработки имен файлов

Несколько функций ориентированы на работу с именами файлов или списками имен файлов.

Каждая из перечисленных ниже функций выполняет некоторое преобразование имени файла. Аргумент функции рассматривается как последовательность имен файлов, разделенных пробелами. (Начальные и конечные пробелы игнорируются.) Каждое из перечисленных имен файлов преобразуется одинаковым образом и результаты этих преобразований, разделенные одиночными пробелами, объединяются вместе.

$(dir имена...)
Из каждого имени файла, перечисленного в именах, выделяет имя каталога, где этот файл расположен. Именем каталога считается часть имени до последнего встреченного символа `/'(включая и этот символ). Если имя файла не содержит символов `/', его именем каталога считается строка`./'. Результатом следующего примера:
$(dir src/foo.c hacks)
будет строка `src/ ./'.
$(notdir имена...)
Из каждого имени файла, перечисленного в именах, удаляет имя каталога, где он находится. Имена файлов, не содержащие символов `/', остаются без изменений. В противном случае (при наличии символов `/'), из имени файла удаляется все, что расположено до последнего встреченного символа `/'(включая и сам этот символ). Это означает, что имя файла, оканчивающееся символом `/' преобразуется в пустую и строку, и, таким образом, количество имен файлов на выходе функции может не совпадать с количеством имен файлов, переданных ей на вход. К сожалению, мы пока не видим лучшей альтернативы. Результатом следующего примера:
$(notdir src/foo.c hacks)
будет строка `foo.c hacks'.
$(suffix имена...)
Из каждого имени файла, перечисленного в именах, выделяется его суффикс. Если имя файла содержит точку, суффиксом имени считается строка, начинающаяся с последнего встреченного символа точки. В противном случае (имя не содержит точек), суффиксом считается пустая строка. Из-за этого, во многих случаях результатом функции может быть пустая строка, хотя список имен был непуст. Вдобавок, список имен файлов, полученный на выходе функции, может оказаться "короче" чем список, переданный ей на вход. Например, результатом следующего выражения:
$(suffix src/foo.c src-1.0/bar.c hacks)
будет строка `.c .c'.
$(basename имена...)
Из каждого имени файла, перечисленного в именах, выделяет так называемое "базовое имя" (basename) - все то, что не относится к суффиксу. Если имя файла содержит точку, то базовым именем считается все, что находится до последнего символа точки (не включая ее). Точки, которые находятся внутри имени каталога, игнорируются. Если рассматриваемое имя файла не содержит точек, оно целиком считается базовым именем. Результатом следующего примера:
$(basename src/foo.c src-1.0/bar hacks)
будет строка `src/foo src-1.0/bar hacks'.
$(addsuffix суффикс,имена...)
Аргумент имена рассматривается как последовательность разделенных пробелами имен; аргумент суффикс рассматривается как строка. Результатом работы этой функции является список имен (разделенных одиночными символами пробелов), каждое из которых получено из соответствующего "исходного" имени, в конец которого добавлен суффикс суффикс. Результатом следующего примера:
$(addsuffix .c,foo bar)
будет строка `foo.c bar.c'.
$(addprefix префикс,имена...)
Аргумент имена рассматривается как последовательность разделенных пробелами имен; аргумент префикс рассматривается как строка. Результатом этой функции является список имен (разделенных одиночными символами пробелов), каждое из которых получено из соответствующего "исходного" имени, в начало которого добавлен префикс префикс. Например, результатом следующего выражения:
$(addprefix src/,foo bar)
будет строка `src/foo src/bar'.
$(join список1,список2)
"Пословно" объединяет оба аргумента: первые два слова (по одному из каждого аргумента) объединяются в первое слово результата; вторые два слова (второе слово каждого из аргументов) объединяются во второе слово результата и так далее. Таким образом n-ное слово результата строится из n-ного слова каждого из аргументов. Если один из аргументов содержит большее количество слов чем другой, "избыточные" слова копируются в результат без изменений. Например, результатом выражения: `$(join a b,.c .o)' будет строка `a.c b.o'. "Оригинальные" пробелы между словами списка не сохраняются - они заменяются на одиночный символ пробела. Применив join к результатам работы функций dir и notdir, можно получить "исходный" список файлов.
$(word n,текст)
Возвращает n-ное слово текста. Допустимые значения n начинаются с 1. Если значение n превышает количество слов в тексте, результатом работы фунции будет пустая строка. В следующий примере:
$(word 2, foo bar baz)
будет получена строка `bar'.
$(wordlist s,e,текст)
Возвращает список слов текста, начиная со слова номер s и заканчивая словом номер e (включительно). Допустимые значения s и e начинаются с 1. Если s превышает количество слов в тексте, возращается пустая строка. Если e превышается количество слов в тексте, возвращаются все слова до конца текста. Если величина s превышает e, также возвращается пустая строка. В следующем примере:
$(wordlist 2, 3, foo bar baz)
будет получен результат `bar baz'.
$(words текст)
Возвращает число слов в тексте. Таким образом, последнее слово текста можно получить с помощью выражения $(word $(words текст),текст).
$(firstword имена...)
Аргумент имена рассматривается как последовательность имен, разделенных пробелами. Результатом функции является первое имя из списка. Остальные имена игнорируются. Например, результатом выражения:
$(firstword foo bar)
будет строка `foo'. Хотя выражение $(firstword текст) и эквивалентно $(word 1,текст), использование функции firstword может повысить удобочитаемость make-файла.
$(wildcard шаблон)
Аргумент шаблон является шаблоном имени файла и, обычно, содержит шаблонные символы (такие же как в шаблонах имен файлов интерпретатора командной строки). Результатом функции wildcard является список разделенных пробелами имен существующих в данный момент файлов, удовлетворяющих указанному шаблону. Смотрите раздел Использование шаблонных символов в именах файлов.

Функция foreach

Функция foreach сильно отличается от других функций. При ее использовании, некоторый фрагмент текста используется многократно, каждый раз с "подстановкой" в него нового значения. Это напоминает команду for командного интерпретатора sh или команду foreach оболочки csh.

Синтаксис функции foreach выглядит следующим образом:

$(foreach переменная,список,текст)

Сначала, вычисляются значения первых двух аргументов - переменной и списка; последний аргумент, текст, пока не вычисляется. Далее, каждое слово из вычисленного значения аргумента список поочередно подставляется в переменную с (заранее вычисленным) именем переменная и производится "расширение" текста текст. Как правило, текст содержит ссылку на эту переменную, поэтому при каждой новой подстановке получаются разные результаты.

Затем, полученные таким образом результаты "расширений" текста (их количество равно количеству разделенных пробелами слов в аргументе список) "соединяются" вместе (с вставкой пробела между ними). Полученная таким образом строка и является результатом работы функции foreach.

В следующем примере, в переменную `files' заносится список всех файлов, находящихся в каталогах, которые перечислены в переменной`dirs':

dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))

Здесь, аргументом текст является выражение`$(wildcard $(dir)/*)'. При первой итерации, переменная dir получает значение`a', что производит эффект, аналогичный`$(wildcard a/*)'; вторая интерация даст результат, аналогичный`$(wildcard b/*)'; и, наконец, третья итерация даст результат, как от выражения`$(wildcard c/*)'.

Таким образом, приведенный выше пример даст результат, аналогичный (за исключением установки переменной `dirs') выражению:

files := $(wildcard a/* b/* c/* d/*)

Когда выражение текст достаточно сложно, вы можете повысить удобочитаемость make-файла, поместив его в отдельную дополнительную переменную:

find_files = $(wildcard $(dir)/*)
dirs := a b c d
files := $(foreach dir,$(dirs),$(find_files))

Для подобной цели в приведенном выше примере использована переменная find_files. Для ее определения как рекурсивно вычисляемой переменной, мы использовали обычный оператор`='. Вследствие этого, ее значение (содержащее ссылку на функцию wildcard), будет вычисляться многократно, под управлением функции foreach; с упрощенно вычисляемой переменной этого бы не произошло, поскольку функция wildcard была бы выполнена лишь однажды, во время определении переменной find_files.

Работа функции foreach не оказывает "необратимого" влияния на переменную; ее значение и "разновидность" после выполнения функции foreach остаются неизменными (такими же, как и до выполнения этой функции). Другие значения, которые берутся из списка, "действуют" только временно, на период работы функции foreach. Во время работы функции foreach, переменная считается упрощенно вычисляемой. Если до выполнения функции foreach, переменная не была определена, она остается неопределенной и после вызова этой функции. Смотрите раздел Две разновидности переменных.

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

files := $(foreach Esta escrito en espanol!,b c ch,$(find_files))

по-видимому, может оказаться полезным только в том случае, если find_files будет содержать ссылку на переменную с именем`Esta escrito en espanol!' (нет ли у вас такой переменной?). Но, скорее всего, вы просто ошиблись.

Функция if

Функция if обеспечивает поддержку для условного вычисления выражений (не путайте с поддерживаемыми GNU make условными конструкциями наподобие ifeq, которые "действуют" на уровне make-файла; смотрите раздел Синтаксис условных конструкций).

При вызове функции if, ей передается два или три аргумента:

$(if условие,фрагмент-для-выполненного-условия[,фрагмент-для-невыполненного-условия])

Сначала из первого аргумента, условия, удаляются начальные и конечные пробелы, затем он вычисляется. Если в результате получается любая непустая строка, то условие считается "истинным". При получении пустой строки, условие считается "ложным".

Если условие выполняется, вычисляется второй аргумент, фрагмент-для-выполненного-условия, и полученный результат становится результатом вычисления всей функции if.

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

Обратите внимание, что всегда вычисляется только один из фрагментов - либо фрагмент-для-выполненного-условия, либо фрагмент-для-невыполненного-условия. Поэтому, оба из них могут производить какие-либо "побочные" эффекты (например, вызывать функцию shell).

Функция call

Функция call уникальна тем, что с ее помощью вы можете определять свои собственные функции с параметрами. Вы можете запомнить сложное выражение в качестве значения переменной, а затем использовать функцию call для его вычисления с разными параметрами.

Для функции call используется следующий синтаксис:

$(call переменная,параметр,параметр,...)

При вычислении этой функции, make помещает каждый из параметров во временные переменные $(1), $(2) и так далее. Переменная $(0) будет содержать имя переменной. На максимальное число параметров ограничения нет. Нет ограничения и на минимальное число параметров, однако, нет особого смысла в использовании call без параметров.

Далее, значение переменной вычисляется "в контексте" этих временных переменных. Так, любая ссылка на $(1) в значении переменной будет ссылаться на первый параметр, переданный при вызове call.

Обратите внимание, что переменная - это имя переменной, а не ссылка на эту переменную. Поэтому, как правило, вам не потребуется использовать`$' или скобки при описании этого аргумента. (Вы можете, однако, использовать внутри имени ссылку на другую переменную, если вы хотите, чтобы имя не было "константным".)

Если переменная представляет собой имя "встроенной" функции, то вызывается именно она (даже если существует переменная с таким же именем).

Перед тем, как присвоить значения временным переменным, функция call вычисляет значения всех параметров. Это означает, что значения переменной, содержащие ссылки на встроенные функции, имеющие специальные правила вычисления (наподобие foreach или if), могут работать не так, как вы ожидали.

Вот несколько примеров использования функции call.

Следующая функция "переставляет" свои аргументы в обратном порядке:

reverse = $(2) $(1)

foo = $(call reverse,a,b)

Переменная foo будет содержать `b a'.

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

pathsearch = $(firstword $(wildcard $(addsufix /$(1),$(subst :, ,$(PATH)))))

LS := $(call pathsearch,ls)

Переменная LS будет содержать /bin/ls или что-нибудь подобное.

Функция call может быть "вложенной". Каждый рекурсивный вызов получит свои собственные локальные копии $(1) и прочих переменных, которые "замаскируют" своих "тезок" из call более "высокого" уровня. Вот пример реализации функции map:

map = $(foreach a,$(2),$(call $(1),$(a)))

Теперь, с помощью функции map, вы можете "за один шаг" вызывать функции, имеющие только один параметр (наподобие origin), сразу для нескольких значений. Так, в следующем примере:

o = $(call map,origin,o map MAKE)

переменная o будет содержать нечто вроде `file file default'.

И последнее предупреждение: будьте осторожны при добавлении пробелов к аргументам функции call. Как и с другими функциями, любые пробелы, содержащиеся во втором и последующих аргументах, сохраняются; это может привести к весьма странным результатам. Надежнее всего, удалять все "дополнительные" пробелы, указывая параметры для функции call.

Функция origin

В отличие от других функций, функция origin не оперирует значениями переменных; вместо этого, она позволяет вам получить некоторую информацию о самой переменной. Точнее, она позволяет узнать, откуда "взялась" рассматриваемая переменная.

Синтаксис функции origin следующий:

$(origin переменная)

Обратите внимание, что переменная является именем переменной, а не ссылкой на нее. Таким образом, вам, как правило, не придется использовать символ`$' или скобки при написании этого аргумента. (Однако, внутри имени переменной может находится ссылка на другую переменную, если вы хотите, чтобы имя переменной не было "фиксированным".)

Результатом этой функции будет строка, указывающая на то, каким образом переменная переменная была определена:

`undefined'
Если переменная не была определена.
`default'
Если переменная была определена по умолчанию (как, например, переменная CC и ей подобные). Смотрите раздел Используемые в неявных правилах переменные. Обратите внимание, что если вы переопределили переменную, имеющую значение по умолчанию, функция origin возвратит информацию о более позднем переопределении.
`environment'
Если переменная была создана из соответствующей переменной среды и опция`-e'не была включена (смотрите раздел Обзор опций).
`environment override'
Если переменная была создана из соответствующей переменной среды и опция`-e'была включена (смотрите раздел Обзор опций).
`file'
Если переменная была определена внутри make-файла.
`command line'
Если переменная была определена с помощью командной строки.
`override'
Если переменная была определена в make-файле с с использованием директивы override (смотрите раздел Директива override).
`automatic'
Если переменная является автоматической переменной, определяемой во время выполнения команд каждого правила (смотрите раздел Автоматические переменные).

Помимо "праздного любопытства", подобная информация может быть полезна, в первую очередь, для того, чтобы определить, насколько вы можете "доверять" значению, содержащемуся в рассматриваемой переменной. Предположим, для примера, что у вас имеется make-файл `foo', который включает в себя другой make-файл `bar'. Вы хотите, чтобы при запуске команды `make -f bar', переменная bletch была определена в make-файле `bar' даже в том случае, если аналогичная переменная bletch будет содержаться в операционном окружении. Однако, если переменная bletch уже была определена в make-файле `foo' (до подключения make-файла `bar'), вы бы не хотели "переопределять" эту переменную в `bar'. Это можно было бы сделать, используя в файле `foo' директиву override: в этом случае определение переменной, данное в файле `foo' имело бы приоритет перед более поздним ее определением в файле `bar'. К сожалению, директива override также "перекрыла" бы любое определение этой переменное, заданное в командной строке. Решение может выглядеть следующим образом (фрагмент make-файла `bar'):

ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc.
endif
endif

Здесь, переменная bletch будет переопределена, если она была определена из соответствующей переменной среды.

Если вы хотите "перекрыть" определение bletch, пришедшее из программного окружения, даже при наличии опции`-e', то можно написать:

ifneq "$(findstring environment,$(origin bletch))" ""
bletch = barf, gag, etc.
endif

Здесь, переопределение произойдет, если выражение `$(origin bletch)'вернет любую из строк -`environment' или `environment override'. Смотрите раздел Функции анализа и подстановки строк.

Функция shell

В отличие от большинства других функций (кроме, пожалуй, функции wildcard; смотрите раздел Функция wildcard), функция shell служит для "общения" make с внешним миром.

Функция shell работает аналогично символу``' в большинстве интерпретаторов командной строки: она производит подстановку результата выполнения команды. Это означает, что в качестве аргумента она принимает команду интерпретатора командной строки, а в качестве результата возвращает "выходные данные" этой команды. Единственным преобразованием полученного результата, которое выполняет make перед подстановкой его в окружающий текст, является преобразование символов перевода строки (или пар перевод-строки/возврат-каретки) в одиночные пробелы. Также производится удаление "конечных" (находящихся в конце данных) символов перевода строки (или пар перевод-строки/возврат-каретки).

Команды, указанные в shell, запускаются в момент вычисления этой функции. Как правило, это происходит в момент чтения make-файла. Исключение составляет случай, когда эта функция shell используется в командах правила. В этом случае она будет вычисляться (будут выполняться указанные в ней команды) во время работы команд правила.

Вот несколько примеров использования функции shell:

contents := $(shell cat foo)

В этом примере, в переменную contents записывается содержимое файла `foo' (видоизмененное таким образом, что все символы перевода строки заменены в нем на пробелы). В следующем примере:

files := $(shell echo *.c)

в переменную files записывается список файлов, полученных по маске `*.c'. Скорее всего (если только вы не имеете какой-нибудь очень странный командный интерпретатор), результат будет аналогичен использованию выражения `$(wildcard *.c)'.

Функции управления сборкой

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

$(error текст...)
Генерирует "фатальную" ошибку с сообщением текст. Обратите внимание, что ошибка генерируется в момент вычисления функции. Соответственно, если вы вызываете эту функцию внутри команд правила или в правой части оператора присваивания для рекурсивной переменной, ошибка будет генерироваться не сразу. Перед генерацией ошибки сообщение "расширяется". В следующем примере:
ifdef ERROR1
$(error error is $(ERROR1))
endif
во время чтения make-файла будет генерироваться фатальная ошибка если была определена переменная ERROR1. Здесь:
ERR = $(error found an error!)

.PHONY: err
err: ; $(ERR)
фатальная ошибка будет генерироваться при обработке цели err.
$(warning текст...)
Эта функция работает подобно описанной выше функции error, но, в отличии от нее, не вызывает завершения работы make. Сообщение текст "расширяется" и выводится, после чего обработка make-файла продолжается. Возвращаемое значение этой функции - пустая строка.

Запуск make

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

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

Указывая дополнительные параметры при запуске make, вы сможете выполнить эти и многие другие действия.

По окончанию работы make, код завершения программы представляет собой одно из трех возможных значений:

0
Код завершения равен нулю если работа make завершена успешно.
2
Код завершения равен двум если в ходе работы make возникли какие-то ошибки. Суть происшедших ошибок описана в выдаваемых make сообщениях.
1
Код завершения равен одному, если при запуске make была указана опция `-q' и make определила, что некоторые цели нуждаются в обновлении. Смотрите раздел Вместо исполнения команд.

Аргументы для задания make-файла

Для указания имени make-файла, который следует интерпретировать, служат опции`-f' и`--file' (также работает опция `--makefile'). Например,`-f altmake' указывает на необходимость использования `altmake' в качестве make-файла.

При задании сразу нескольких опций `-f' с аргументом, все указанные make-файлы будут использованы (логически "объединяясь" в один make-файл).

При отсутствии опций `-f' или `--file', по умолчанию, make пытается найти файлы с именами `GNUmakefile', `makefile', и `Makefile' (в указанном порядке). Первый же найденный файл, который существует или может быть построен, используется как make-файл для работы (смотрите раздел Создание make-файлов).

Аргументы для задания главной цели (goal)

Главная цель (goal) - это цель которую стремится достичь make в результате своей работы. Прочие цели make-файла обновляеются только в том случае, если они прямо или косвенно являются пререквизитами главной цели.

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

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

В качестве главной цели может быть указана любая цель make-файла (за исключением целей, чье имя начинается с символа`-' или содержит символ `=', поскольку такая цель будет "воспринята" как задание опции или определение переменной). Можно задать даже такую цель, которая не описана в make-файле; в этом случае make попытается ее достичь, используя имеющиеся у нее неявные правила.

Список главных целей, указанных вами в командной строке, make записывает в специальную переменную MAKECMDGOALS. Если в командной строке не было задано ни одной цели, эта переменная остается пустой. Обратите внимание, что эта переменная должна использоваться только в особых случаях.

Следующий пример демонстрирует "надлежащее" использование переменной MAKECMDGOALS. Она используется для того, чтобы избежать подключения файлов `.d', когда в командной строке указывается цель clean (смотрите раздел Автоматическая генерация списка пререквизитов), так что make не будет пытаться создать эти файлы только для того, чтобы тут же их удалить:

sources = foo.c bar.c

ifneq ($(MAKECMDGOALS),clean)
include $(sources:.c=.d)
endif

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

.PHONY: all
all: size nm ld ar as

Если вы работаете над программой size, удобно запускать`make size' чтобы перекомпилировались только файлы, относящиеся к этой программы.

Явное задание цели может применяться для построения тех файлов, которые при "обычной" работе не строятся. Это, например, может быть файл с отладочной информацией или специальная тестовая версия программы, для которых в make-файле имеется свое правило, но которые не являются пререквизитами главной цели, выбираемой по умолчанию.

Явное указание главной цели может использоваться для запуска команд, ассоциированных с абстрактной (смотрите раздел Абстрактные цели) или пустой (смотрите раздел Использование пустых целей для фиксации событий) целью. Например, во многих make-файлах есть абстрактная цель `clean', которая очищает каталог, удаляя все файлы, кроме файлов с исходными текстами. Естественно, это делается только по вашему требованию`make clean'. Ниже приведен список типичных абстрактных и пустых целей. Смотрите раздел Стандартные имена целей для пользователей, где описываются все "стандартные" имена целей, используемые в программах GNU.

`all'
Построить все "высокоуровневые" цели make-файла.
`clean'
Удалить все файлы, которые, обычно, создаются в результате работы make.
`mostlyclean'
Работает аналогично `clean', но может воздержаться от удаления некоторых файлов, которые, как правило, не желательно перекомпилировать. Например, в make-файле, описывающем сборку компилятора GCC, цель`mostlyclean' не удаляет файл `libgcc.a', поскольку его перекомпиляция требуется редко и занимает много времени.
`distclean'
`realclean'
`clobber'
Любая из этих целей может быть определена для удаления большего числа файлов, чем это делает `clean'. Так, например, могли бы удаляться конфигурационные файлы или линки, которые создаются при подготовке к компиляции (не обязательно самим make-файлом).
`install'
Скопировать исполняемый файл в каталог, где обычно хранятся исполняемые файлы программ; скопировать дополнительные файлы, используемые исполняемым файлом, в нужные каталоги (где исполняемый файл ожидает их найти).
`print'
Печать листингов всех исходных файлов, которые были модефицированы.
`tar'
Создает tar-архив с файлами исходных текстов.
`shar'
Создать самораспаковывающийся архив (shar-файл) из исходных файлов.
`dist'
Создать из исходных файлов дистрибутив. Это может быть tar-файл, shar-файл, сжатые их версии или что-нибудь другое.
`TAGS'
Обновить таблицу тегов для этой программы.
`check'
`test'
Выполнить самотестирование программ, построенных этим make-файлом.

Вместо исполнения команд

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

`-n'
`--just-print'
`--dry-run'
`--recon'
"Нет операции". Будут печататься (без реального выполнения) команды, которые бы выполнила make для обновления целей.
`-t'
`--touch'
Цели помечаются как "обновленные" без реального их изменения. Иначе говоря, make просто "делает вид" что скомпилировала нужные цели, на самом деле не изменяя их.
`-q'
`--question'
"Проверка". Делается проверка - нуждаются ли цели в обновлении, но никаких команд не исполняется. Никакой компиляции и никакого вывода сообщений при этом не производится.
`-W файл'
`--what-if=файл'
`--assume-new=файл'
`--new-file=файл'
"Что если?". За каждой опцией`-W' следует имя файла. Для указанных таким образом файлов, make предполагает, что их время модефикации равно текущему времени (при этом, реальное время модефикации этих файлов не меняется). Совместно используя опции`-W' и `-n', можно увидеть, какие действия предпримет make, если перечисленные файлы действительно будут модефицированы.

При наличии опции `-n', make только печатает команды, без реального их выполнения.

Эффект опции `-t' состоит в том, что make игнорирует команды, указанные в правилах и использует вместо них команду touch для всех целей, нуждающихся в обновлении. Печатается также команда touch, если только не были указаны опции `-s' или .SILENT. В действительности, для увеличения скорости, make не вызывает программу touch, а выполняет всю требуемую работу "напрямую".

При наличии опции `-q', make ничего не печатает и не исполняет никаких команд, а просто возвращает соответствующий код возврата. Нулевой код возврата означает, что цели не нуждаются в обновлении. Код возврата, равный единице, означает, что какие-то из целей нуждаются в обновлении. И, наконец, код возврата, равный двум, означает, что произошла ошибка (таким образом, вы можете отличить ошибочную ситуацию от случая, когда цели нуждаются в обновлении).

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

Опции `-n', `-t' и `-q' не влияют на командные строки, начинающиеся с`+', а также строки, содержащие`$(MAKE)' или `${MAKE}'. Обратите внимание, что при наличии вышеперечисленных опций будут запускаться только строки, начинающиеся с`+' или содержащие`$(MAKE)' или `${MAKE}' - другие строки тех же правил не будут запускаться (смотрите раздел Как работает переменная MAKE).

Опцию `-W' можно использовать двумя путями:

Другую информацию о make и используемых make-файлах вы можете получить с помощью опций `-p' и `-v'(смотрите раздел Обзор опций).

Предотвращение перекомпиляции некоторых файлов

Иногда, после изменения исходного файла, вам хотелось бы избежать перекомпиляции всех файлов, которые от него зависят. Предположим, что вы добавили макрос или прототип функции в заголовочный файл, от которого зависят многие исходные файлы. Будучи "консервативной", make предполагает что любые изменения, внесенные в заголовочные файлы, требуют перекомпиляции всех файлов, которые от них зависят. Вы, однако, понимаете, что, в данном случае, нет необходимости в подобной перекомпиляции и не хотели бы тратить время, ожидая ее завершения.

Если вы заранее предвидели эту проблему и еще не внесли изменения в заголовочный файл, вы можете воспользоваться опцией`-t'. Эта опция заставит make не исполняя команд, пометить все цели как "обновленные", изменив время их последней модефикации. Поступая так, вам следует придерживаться следующей процедуры:

  1. Используйте команду `make' для перекомпиляции всех файлов, которые действительно в этом нуждаются.
  2. Внесите изменения в заголовочные файлы.
  3. Используйте команду `make -t', чтобы пометить все объектные файлы как "обновленные". При следующем запуске make, внесенные в заголовочные файлы изменения, уже не вызовут перекомпиляции программы.

Однако, если вы уже внесли изменения в заголовочный файл, в то время как у вас еще имеются другие файлы, нуждающиеся в обновлении, использовать приведенную выше процедуру уже поздно. Вместо этого, вы можете воспользоваться опцией `-o файл' дабы указанный файл рассматривался как "старый" (смотрите раздел Обзор опций). В таком случае ни этот файл, ни зависящие от него файлы обновляться не будут. Придерживайтесь следующей процедуры:

  1. Перекомпилируйте все исходные файлы, которые нуждаются в компиляции по причинам, не связанным с вашей модефикацией заголовочного файла, используя`make -o имя_заголовочного_файла'. Если вы изменили несколько заголовочных файлов, используйте отдельные опции`-o' для каждого из них.
  2. Обновите время модефикации всех объектных файлов, используя`make -t'.

"Перекрытие" (overriding) переменных

Аргумент командной строки, содержащий `=' определяет значение переменной: запись `v=x' означает, что переменная v получит значение x. Если значение переменной было задано подобным образом, то все "обычные" присваивания этой переменной нового значения внутри make-файла будут игнорироваться; мы говорим что они будут перекрыты (overridden) аргументом командной строки.

Чаще всего, данное средство используется для передачи дополнительных опций компилятору. Например, в "правильно" написанном make-файле переменная CFLAGS используется при каждом вызове компилятора Си, так что исходный файл `foo.c' мог бы компилироваться приблизительно так:

cc -c $(CFLAGS) foo.c

Таким образом, значение, хранящееся в CFLAGS, будет влиять на любой процесс компиляции. Вполне возможно, что в make-файле определяется некоторое "обычное" значение для переменной CFLAGS, например:

CFLAGS=-g

Каждый раз, запуская make, вы, при желании, можете "перекрыть" это значение переменной CFLAGS. Например, при вызове `make CFLAGS='-g -O'', каждая компиляция будет осуществляться с помощью`cc -c -g -O'. (Этот пример также иллюстрирует, как вы можете включать пробелы и другие специальные символы в значение переменной при ее перекрытии.)

Переменная CFLAGS - лишь одна из многих "стандартных" переменных, существующих только для того, чтобы вы могли изменять их подобным образом. Смотрите раздел Используемые в неявных правилах переменные, где приведен полный список таких переменных.

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

Когда вы "перекрываете" значение переменной с помощью командной строки, вы можете определить как рекурсивно вычисляемую, так и упрощенно вычисляемую переменную. В приведенном выше примере создавалась рекурсивно вычисляемая переменная; для определения упрощенно вычисляемой переменной, достаточно вместо `=' использовать оператор `:='. С другой стороны, если указанное в командной строке значение переменной не будет ссылаться на другие переменные или функции, тип создаваемой переменной не имеет значения.

Имеется один способ, с помощью которого внутри make-файла можно изменить значение переменной, заданное с помощью командной строки. Для этого нужно использовать директиву override, которая выглядит следующим образом: `override переменная = значение' (смотрите раздел Директива override).

Проверка компиляции программы

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

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

В такой ситуации следует использовать опции`-k' или `--keep-going'. При этом make будет продолжать обработку других пререквизитов рассматриваемой цели, обновляя их при необходимости. Только после этого make завершит работу с возвратом ненулевого статуса. Например, при возникновении ошибки во время компиляции объектного файла, `make -k' продолжит компиляции других объъектных файлов, хотя уже и понятно, что скомпоновать готовую программу будет невозможно. В дополнении к этому,`make -k' будет пытаться продолжать работу как можно дольше и после того, как станет ясно что make не знает, как можно обновить рассматриваемую цель или пререквизит. В этом случае будет выдано соответствующее сообщение об ошибке, но make попытается продолжить работу (в то время, как без опции`-k' такая ошибка считалась бы фатальной; смотрите раздел Обзор опций).

Обычно, make исходит из того, что ваша задача - получить новую версию главной цели; как только make понимает что это невозможно, она сообщает об этом сразу же. Запуск с опцией `-k' говорит, что, на самом деле, ваша задача - протестировать максимальное количество внесенных вами изменений (все обнаруженные таким образом проблемы можно было исправить "сразу", до следующей попытки компиляции). Вот почему, кстати, при выполнении команды M-x compile редактор Emacs по умолчанию использует опцию `-k'.

Обзор опций

Вот полный список опций, распознаваемых программой make:

`-b'
`-m'
Эти опции оставлены для совместимости с другими версиями make. При работе они игнорируются.
`-C каталог'
`--directory=каталог'
Перед чтением make-файла перейти в каталог каталог. При наличии сразу нескольких опций `-C', каждая из них рассматривается относительно предыдущей: так, `-C / -C etc'эквивалентно `-C /etc'. Обычно, это используется при рекурсивном вызове make (смотрите раздел Рекурсивный вызов make).
`-d'
В дополнение к основной работе, выводить отладочную информацию. Отладочная информация содержит в себе много интересного: например, какие файлы make считает необходимым обновить, для каких файлов сравнивается их время изменения и каков полученный результат, какие неявные правила рассматриваются в качестве кандидатов на исполнение и какие из них действительно выполняются и так далее. Опция -d эквивалентна использованию опции`--debug=a' (смотрите ниже).
`--debug[=опции]'
В дополнение к основной работе, выводить отладочную информацию. При выводе отладочной информации можно выбрать нужный ее тип и степень "подробности". При отсутствии аргументов, выбирается "базовый" уровень отладочной информации. Ниже перечислены все возможные аргументы; при "разборе" аргументов учитывается только первый символ названия. При задании нескольких аргументов, они должны разделяться пробелами или запятыми.
a (all)
Выдача всей имеющейся отладочной информации ("максимальный уровень"). Эквивалентно использованию опции`-d'.
b (basic)
"Базовый уровень" отладочной информации: печатаются все цели, которые были найдены "устаревшими" и информация об успешности или неуспешности попытки их обновления.
v (verbose)
Следующий уровень после "базового"; дополнительно выдается информация о том, какие make-файлы обрабатываются, какие пререквизиты не нуждаются в обновлении и так далее. Включение этой опции также приводит к выдаче отладочной информации "базового" уровня.
i (implicit)
Выдается информация о процессе поиска подходящих неявных правил для каждой из целей. Включение этой опции также приводит к выдаче отладочной информации "базового" уровня.
j (jobs)
Выдача информации о вызове некоторых команд.
m (makefile)
По умолчанию, описанная выше отладочная информация не выдается на стадии, когда make пробует обновить make-файлы. Данная опция разрешает выдачу отладочной информации в процессе обновления make-файлов. Обратите внимание, что `all' также включает данную опцию. Эта опция также разрешает выдачу отладочных сообщений "базового" уровня.
`-e'
`--environment-overrides'
Дает переменным, созданным из соответствующих переменных среды "приоритет" перед переменными, определенными внутри make-файла. Смотрите раздел Переменные из операционного окружения.
`-f файл'
`--file=файл'
`--makefile=файл'
Указанный файл рассматривается в качестве make-файла. Смотрите раздел Создание make-файлов.
`-h'
`--help'
Напоминает вам список опций, распознаваемых make и завершает работу.
`-i'
`--ignore-errors'
Игнорировать все ошибки, возникающие в любых командах, исполняемых для обновления файлов. Смотрите раздел Ошибки при исполнении команд.
`-I каталог'
`--include-dir=каталог'
Указывает каталог для поиска включаемых make-файлов. Смотрите раздел Подключение других make-файлов. При наличии нескольких опций `-I', поиск в указанных каталогах производится в том порядке, как они были перечислены.
`-j [число_заданий]'
`--jobs[=число_заданий]'
Указывает количество одновременно выполняемых заданий (команд). При отсутствии аргумента, число одновременно выполняемых заданий не ограничено. При наличии сразу нескольких опций `-j', будет действовать только последняя из перечисленных. Смотрите раздел Параллельное исполнение команд, где подробно описан процесс запуска команд. Обратите внимание, что при работе в операционной системе MS-DOS, эта опция игнорируется.
`-k'
`--keep-going'
После возникновения ошибки, продолжить, насколько это возможно, обработку make-файла. Хотя цель, при обновлении которой произошла ошибка, уже не сможет быть корректно обновлена, и, следовательно, не могут быть правильно обновлены и все цели, зависящие от нее, make попробует обработать другие пререквизиты этих целей. Смотрите раздел Проверка компиляции программы.
`-l [загрузка]'
`--load-average[=загрузка]'
`--max-load[=загрузка]'
Указывает, что новые задания (команды) не должны запускаться если уже имеется хотя бы одно запущенная задание и загрузка системы равна или превышает значение загрузка (число с плавающей точкой). При отсутствии аргумента, ограничение на максимальную загрузку снимается. Смотрите раздел Параллельное исполнение команд.
`-n'
`--just-print'
`--dry-run'
`--recon'
Печатать команды, которые должны выполняться, но не исполнять их. Смотрите раздел Вместо исполнения команд.
`-o файл'
`--old-file=файл'
`--assume-old=файл'
Не обновлять файл даже если он "старше" своих пререквизитов и при обработке других файлов не принимать в рассчет возможные изменения в этом файле. По существу, этот файл обрабатывается как "очень старый" и его правила игнорируются. Смотрите раздел Предотвращение перекомпиляции некоторых файлов.
`-p'
`--print-data-base'
Перед началом основной работы, распечатать базу данных (правила и значения переменных), полученную в результате чтения make-файла. Печатается также информация о номере версии (аналогично опции `-v', смотрите ниже). Для того, чтобы просто распечатать базу данных, не обновляя при этом никаких файлов, используйте`make -qp'. Для распечатки базы данных с предопределенными правилами и переменными, используйте `make -p -f /dev/null'. Помимо всего прочего, выводимая информация содержит имя файла и номер строки, где было дано определение правила или переменной. Это может оказаться ценным подспорьем для отладки сложных make-файлов.
`-q'
`--question'
"Режим проверки". Никаких команд не выполняется и не печатается никаких сообщений. Вся работа make заключается в возврате соответствующего кода завершения. В случае, если указанная цель не нуждается в обновлении, возвращается нулевой код. В случае, если обновление требуется, возвращается код, равный единице. При возникновении каких-либо ошибок ошибок, возвращается код, равный двум. Смотрите раздел Вместо исполнения команд.
`-r'
`--no-builtin-rules'
Отключает использование встроенных неявных правил (смотрите раздел Использование неявных правил). Однако, вы по-прежнему можете задать свои собственные неявные правила с помощью шаблонных правил (смотрите раздел Определение и переопределение шаблонных правил). Опция `-r' также очищает используемый по умолчанию список суффиксов для суффиксных правил. (смотрите раздел Устаревшие суффиксные правила). По-прежнему, вы можете использовать специальную цель .SUFFIXES для определения своего собственного списка суффиксов. Далее, эти суффиксы можно будет использовать в своих суффиксных правилах. Обратите внимание, что опция -r воздействует только на правила и никак не влияет на используемые по умолчанию переменные (смотрите раздел Используемые в неявных правилах переменные); смотрите описание опции `-R'.
`-R'
`--no-builtin-variables'
Отключает использование встроенных переменных, используемых неявными правилами (смотрите раздел Используемые в неявных правилах переменные). Разумеется, вы по-прежнему можете определять свои собственные переменные. Включение опции `-R' автоматически приводит к включению опции`-r' (смотрите выше), поскольку нет смысла в наличии неявных правил без наличия переменных, которые в них используются.
`-s'
`--silent'
`--quiet'
"Бесшумный режим". Отключается печать исполняемых команд. Смотрите раздел Отображение исполняемых команд.
`-S'
`--no-keep-going'
`--stop'
Отменяет опцию `-k'. Как правило, это может потребоваться только при рекурсивном использовании make, когда опция`-k' может быть "унаследована" через переменную MAKEFLAGS от make "верхнего уровня" (смотрите раздел Рекурсивный вызов make) или в случае, если эта опция была установлена через переменную среду MAKEFLAGS.
`-t'
`--touch'
Не выполняя команд, просто обновляет время последней модефикации файлов (в действительности не изменяя их). Таким образом, make "делает вид" что все необходимые команды были выполнены, дабы "обмануть" последующие запуски make. Смотрите раздел Вместо исполнения команд.
`-v'
`--version'
Выдает информацию о версии программы make, ее авторах, авторских правах, замечание об отсутствии гарантий и завершает работу.
`-w'
`--print-directory'
Печатать сообщение с именем текущего каталога до и после обработки make-файла. Это может оказаться полезным при поиске нетривиальных ошибок, связанных с рекурсивным вызовом make. Смотрите раздел Рекурсивный вызов make. (На практике, вам редко когда понадобится указывать эту опцию, поскольку, во многих случаях, make включает ее автоматически; смотрите раздел Опция `--print-directory'.)
`--no-print-directory'
Отменить печать рабочего каталога (опции -w). Эта опция может оказаться полезной в тех случаях, когда make автоматически включает опцию -w, а вы не хотели бы получать дополнительные сообщения. Смотрите раздел Опция `--print-directory'.
`-W файл'
`--what-if=файл'
`--new-file=файл'
`--assume-new=файл'
"Притвориться", что цель файл только что была модефицирована. Будучи использована совместно с опцией `-n', покажет, какие действия будут выполнены если этот файл действительно будет модефицирован. Без опции `-n', эффект сходен с выполнением команды touch для указанного файла с последующим запуском make, за исключеним того, что время последней модефикации этого файла происходит только в "воображении" make. Смотрите раздел Вместо исполнения команд.
`--warn-undefined-variables'
Когда make будет встречать ссылки на неопределенные переменные, будут выдаваться соответствующие предупреждающие сообщения. Это может оказаться полезным при отладке make-файлов, в которых переменные используются нетривиальным образом.

Использование неявных правил (implicit rules)

Некоторые "стандартные" способы обновления целевых файлов используются очень часто. Например, одним из типичных способов порождения объектного файла является его получение из соответствующего исходного файла на языке Си с использованием программы cc (компилятора языка Си).

Неявные правила (implicit rules) указывают make на некоторые "стандартные" приемы обработки файлов, дабы пользователь мог использовать их, не занимаясь каждый раз детальным описанием способа обработки. Так, например, имеется неявное правило для компиляции исходных файлов на языке Си. Вопрос о запуске тех или иных правил решается исходя из имен обрабатываемых файлов. Как правило, например, при компиляции программ на Си, из "входного" файла с расширением `.c' получается файл с расширением `.o'. Таким образом, при наличии подобной комбинации расширений файлов, make может применить к ним неявное правило для компиляции Си-программ.

Неявные правила могут применяться последовательно, связываюсь в "цепочки"; так например, make может получить файл `.o' из файла `.y', используя "промежуточный" файл `.c'. Смотрите раздел "Цепочки" неявных правил.

Во встроенных неявных правилах используются некоторые переменные, изменяя которые, можно влиять на работу этих правил. Так, например, в неявном правиле для компиляции Си-программ используется переменная CFLAGS, содержащая передаваемые компилятору опции. Смотрите раздел Используемые в неявных правилах переменные.

Вы можете определить свои собственные неявные правила с помощью шаблонных правил (pattern rules). Смотрите раздел Определение и переопределение шаблонных правил.

Суффиксные правила (suffix rules) - более ограниченный (и устаревший) механизм задания неявных правил. Механизм шаблонных правил является более общим и понятным, однако суффиксные правила по-прежнему поддерживаются из соображений обеспечения совместимости. Смотрите раздел Устаревшие суффиксные правила.

Использование неявных правил (implicit rules)

Для того, чтобы предоставить make возможность использовать "общепринятую" методику для обновления целевого файла, достаточно воздержаться от самостоятельного задания команд. Для этого, можно либо задать правило, не содержащее команд, либо вообще не задавать правила. Исходя из имеющихся в наличии исходных файлов, make решит, каким неявным правилом следует воспользоваться.

Представьте себе такой фрагмент make-файла:

foo : foo.o bar.o
        cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)

Поскольку, вы упомянули файл `foo.o', но не указали правила для его создания, make автоматически попробует найти неявное правило, с помощью которого можно этот файл обновить. Такая попытка будет произведена независимо от того, существует ли в данный момент файл `foo.o' или нет.

В случае, если неявное правило найдено, из него могут быть получены как нужные команды, так и пререквизиты (исходные файлы). Для задания дополнительных пререквизитов, которые не могут быть получены из неявного правила (например, заголовочных файлов), вы можете написать дополнительное правило для `foo.o' без указания команд.

Каждое неявное правило имеет шаблон цели и шаблоны пререквизитов. Один и тот же шаблон цели может фигурировать сразу в нескольких неявных правилах. Например, сразу несколько правил описывают создание файлов`.o': одно - из файлов `.c' с помощью компилятора языка Си; другое - из файлов `.p' с помощью компилятора языка Паскаль; и так далее. В действительности, будет использовано то правило, чьи пререквизиты существуют или могут быть получены. Так, если у вас имеется файл `foo.c', make запустит компилятор Си; в противном случае, если у вас есть файл `foo.p', make запустит компилятор Паскаля; и так далее.

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

Выше, мы уже сказали, что неявное правило может быть использовано в том случае, если его пререквизиты "существуют или могут быть построены". Считается, что файл "может быть построен", если его имя упоминается в make-файле в качестве цели или пререквизита, или же для его построения может быть использовано подходящее неявное правило. В случае, когда пререквизит одного неявного правила является результатом работы другого неявного правила, мы говорим, что эти правила связаны в цепочку (происходит chaining). Смотрите раздел "Цепочки" неявных правил.

В общем случае, make производит поиск подходящих неявных правил для каждой цели и каждого правила с двойным двоеточием, которые не имеют команд. Файлы, упоминаемые только в качестве пререквизитов, расматриваются как цели, описанные в "пустых" правилах (без пререквизитов и команд), поэтому к таким файлам также могут быть применены неявные правила. Смотрите раздел Алгоритм поиска неявных правил, где детально описана процедура поиска подходящих неявных правил.

Заметьте, что явное указание пререквизитов не влияет на процедуру поиска неявных правил. Рассмотрим, например, следующее явное правило:

foo.o: foo.p

Наличие пререквизита `foo.p' не означает, что для получения объектного файла `foo.o' make обязательно будет использовать неявное правило, описывающее получение файла `.o' из исходного файла `.p' на языке Паскаль. Например, при наличии файла `foo.c', вместо неявного правила компиляции исходных файлов на Паскале, будет использовано правило для компиляции исходных файлов на Си, поскольку в списке предопределенных неявных правил оно находится ближе к началу списка (смотрите раздел Перечень имеющихся неявных правил).

Если вы не хотите, чтобы неявное правило было использовано для цели, не имеющей команд, задайте для этой цели пустую команду с помощью символа ';'(смотрите раздел Пустые команды).

Перечень имеющихся неявных правил

Ниже приведен полный список предопределенных неявных правил. Эти правила доступны всегда, если только make-файл явно не заменяет или не отменяет их. Смотрите раздел Отмена действия неявных правил, где обсуждается вопрос перекрытия и отмены действия неявных правил. Опции `-r' и `--no-builtin-rules' отменяют все предопределенные правила.

Даже в отсутствие опции `-r', не всегда все эти правила являются определенными. Дело в том, что многие из них реализованы в make в виде суффиксных правил, поэтому список действительно определенных правил будет зависеть от используемого списка суффиксов (списка пререквизитов специальной цели .SUFFIXES). По умолчанию используется следующий список суффиксов: .out, .a, .ln, .o, .c, .cc, .C, .p, .f, .F, .r, .y, .l, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch .web, .sh, .elc, .el. Все описанные ниже неявные правила, чьи пререквизиты имеют одно из перечисленных расширений, на самом деле являются суффиксными правилами. Если вы модефицируете список суффиксов, "в силе" останутся только те предопределенные правила, чьи суффиксы остались в этом списке; прочие правила будут "отключены". Смотрите раздел Устаревшие суффиксные правила, где подробно описаны суффиксные правила.

Компиляция программ на языке Си
`n.o' автоматически получается из `n.c' при помощи команды`$(CC) -c $(CPPFLAGS) $(CFLAGS)'.
Компиляция программ на языке C++
`n.o' автоматически получается из `n.cc' или `n.C' с помощью команды`$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)'. Мы рекомендуем вам пользоваться суффиксом`.cc' (вместо`.C').
Компиляция программ на языке Паскаль
`n.o' автоматически получается из `n.p' с помощью команды `$(PC) -c $(PFLAGS)'.
Компиляция программ на языках Фортран и Ратфор
`n.o' автоматически получается из `n.r', `n.F' или `n.f' при помощи компилятора Фортрана. При этом, используются следующие команды:
`.f'
`$(FC) -c $(FFLAGS)'.
`.F'
`$(FC) -c $(FFLAGS) $(CPPFLAGS)'.
`.r'
`$(FC) -c $(FFLAGS) $(RFLAGS)'.
Препроцессорная обработка программ на языках Фортран и Ратфор
`n.f' автоматически получается из `n.r' или `n.F'. При этом, исходный текст на Ратфоре или Фортране пропускается через препроцессор для получения "обычной" фортрановской программы. Для этого, используются следующие команды:
`.F'
`$(FC) -F $(CPPFLAGS) $(FFLAGS)'.
`.r'
`$(FC) -F $(FFLAGS) $(RFLAGS)'.
Компиляция программ на языке Modula-2
`n.sym' получается из `n.def' с помощью команды `$(M2C) $(M2FLAGS) $(DEFFLAGS)'. `n.o' получается из `n.mod' с помощью команды `$(M2C) $(M2FLAGS) $(MODFLAGS)'.
Ассемблирование и препроцессорная обработка ассемблерных программ
`n.o' автоматически получается из `n.s' путем запуска ассемблера (as). Для этого используется команда`$(AS) $(ASFLAGS)'. `n.s' автоматически получается из `n.S' с помощью препроцессора языка Си (cpp). При этом используется команда`$(CPP) $(CPPFLAGS)'.
Компоновка одиночного объектного файла
`n' автоматически получается из `n.o' путем запуска компоновщика (обычно, ld) с помощью компилятора Си. Для этого используется команда `$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)'. Это правило будет работать правильно как в простейшем случае, когда текст программы состоит только из одного исходного файла, так и в более сложной ситуации, когда программа состоит из нескольких объектных файлов, один из которых имеет имя, соответствующее имени исполняемого файла. Таким образом, обрабока правила
x: y.o z.o
при наличии файлов `x.c', `y.c' и `z.c', вызовет выполнение команд:
cc -c x.c -o x.o
cc -c y.c -o y.o
cc -c z.c -o z.o
cc x.o y.o z.o -o x
rm -f x.o
rm -f y.o
rm -f z.o
В более сложных ситуациях, когда, например, отсутствует объектный файл, чье имя соответствует имени исполняемого файла, вам придется задать явное правило для компоновки программы. Все типы файлов, автоматически преобразуемые в объектные файлы`.o', автоматически компонуются путем вызова соответствующего компилятора (`$(CC)', `$(FC)' или `$(PC)'; компилятора Си `$(CC)' для ассемблирования файлов `.s') без опции `-c'. Для ускорения работы, компиляция и компоновка делается за один шаг (вместо того, чтобы использовать объектные файлы`.o' в качестве промежуточных).
Генерация программы на Си с помощью Yacc
`n.c' автоматически получается из `n.y' путем запуска программы Yacc с помощью команды `$(YACC) $(YFLAGS)'.
Генерация программы на Си с помощью Lex
`n.c' автоматически получается из `n.l' с помощью программы Lex. При этом, используется команда`$(LEX) $(LFLAGS)'.
Генерация программы на Ратфоре с помощью Lex
`n.r' автоматически получается из `n.l' с помощью программы Lex. Для этого используется команда`$(LEX) $(LFLAGS)'. Соглашение об использовании суффикса`.l' для всех Lex-файлов, независимо от того, должны ли они преобразовываться в код на языках Си или Ратфор, делает невозможным автоматическое определение используемого в данном случае языка. При необходимости получения объектного файла из файла`.l', программа make должна решить - какой компилятор нужно использовать. Она будет использовать компилятор Си, поскольку он более распространен. Если вы используете язык Ратфор, убедитесь в том, что make знает об этом. Для этого достаточно, чтобы нужный файл `n.r' был упомянут в make-файле. Или, если вы пользуетесь исключительно Ратфором и не используете Си, удалите`.c' из списка суффиксов для неявных правил:
.SUFFIXES:
.SUFFIXES: .o .r .f .l ...
Получение Lint-библиотек из исходных файлов на Си, Yacc или Lex
`n.ln' получается из `n.c' путем запуска lint. При этом, используется команда`$(LINT) $(LINTFLAGS) $(CPPFLAGS) -i'. Эта же команда используется для Си-программ, полученных из `n.y' или `n.l'.
Файлы программ TeX и Web
`n.dvi' получается из `n.tex' с помощью команды `$(TEX)'. `n.tex' получается из `n.web' с помощью`$(WEAVE)', или из `n.w' (и из `n.ch' если такой файл существует или может быть получен) с помощью`$(CWEAVE)'. `n.p' получается из `n.web' с помощью `$(TANGLE)' и `n.c' получается из `n.w' (и из `n.ch' если такой существует или может быть создан) с помощью`$(CTANGLE)'.
Файлы программ Texinfo и Info
`n.dvi' получается из `n.texinfo', `n.texi', или `n.txinfo', с помощью команды `$(TEXI2DVI) $(TEXI2DVI_FLAGS)'. `n.info' получается из `n.texinfo', `n.texi', или `n.txinfo', с помощью команды `$(MAKEINFO) $(MAKEINFO_FLAGS)'.
RCS
Любой файл `n' при необходимости может быть извлечен из RCS-файла с именем `n,v' или `RCS/n,v'. Для этого используется команда `$(CO) $(COFLAGS)'. Если файл `n' уже существует, он не будет извлекаться из RCS-файла, даже если этот RCS-файл является более "новым". Правила для RCS являются терминальными (смотрите раздел Шаблонные правила с призвольным соответствием), поэтому RCS-файлы не могут быть получены из других файлов - они должны действительно существовать.
SCCS
Любой файл `n' при необходимости может быть извлечен SCCS-файла с именем `s.n' или `SCCS/s.n'. Для этого используется команда`$(GET) $(GFLAGS)'. Правила для SCCS являются терминальными (смотрите раздел Шаблонные правила с призвольным соответствием), поэтому SCCS-файлы не могут быть получены из других файлов - они должны в действительности существовать. При работе с системой SCCS, файл с именем `n.sh' извлекается в файл `n' и его атрибуты устанавливаются как "исполняемый всеми (everyone)". Это делается для нормальной работы скриптов, помещаемых в SCCS. При работе с системой RCS подобных манипуляций не производится, поскольку она запоминает атрибуты помещаемых в нее файлов. Мы не рекомендуем вам использовать систему SCCS. Общепризнано, что RCS более совершенна и, к тому же, является свободным программным обеспечением. Используя свободное программное обеспечение вместо аналогичного или даже худшего "закрытого" (proprietary) программного обеспечения, вы, тем самым, поддерживаете движение за свободное программное обеспечение.

Как правило, у вас может возникнуть необходимость в изменении только упоминаемых выше переменных (все они перечислены в следующем разделе).

Однако, на самом деле, для выполнения команд, предопределенные неявные правила используют такие переменные, как COMPILE.c, LINK.p, и PREPROCESS.S, которые содержат указанные выше команды.

make следует соглашению, согласно которому, правило, описывающее процесс компиляции исходного файла `.x', использует переменную COMPILE.x. Аналогично, правило для получения исполняемого файла из файла `.x' использует переменную LINK.x, а правило для препроцессорной обработки файла `.x' использует переменную PREPROCESS.x.

Каждое правило, создающее объектный файл, использует переменную OUTPUT_OPTION. В зависимости от опций, с которыми была скомпилирована программа make, она определяет эту переменную как содержащую строку`-o $@' или как пустую. Опция `-o' нужна для того, чтобы выходные файлы помещались в нужное место, если исходные файлы находятся в других каталогах (например, при использовании VPATH; смотрите раздел Поиск пререквизитов по каталогам). Однако, компиляторы в некоторых системах не допускают использования опции`-o' для объектных файлов. Если у вас именно такая система и вы используете VPATH, некоторые скопилированные файлы могут быть помещены в "неверные" каталоги. Для обхода этой проблемы, поместите в переменную OUTPUT_OPTION строку `; mv $*.o $@'.

Используемые в неявных правилах переменные

Команды, содержащиеся во "встроенных" неявных правилах, широко используют некоторые предопределенные переменные. Вы можете изменять эти переменные внутри make-файла, с помощью аргументов, передаваемых программе make или с помощью переменных среды, влияя, таким образом, на работу неявных правил. Переменные, используемые неявными правилами, могут быть "отключены" с помощью опций`-R' или`--no-builtin-variables'.

Например, команда для компиляции исходных текстов на Си выглядит как`$(CC) -c $(CFLAGS) $(CPPFLAGS)'. По умолчанию, первая переменная содержит значение`cc', остальные - пустое значение. В результате, используется команда`cc -c'. Присвоив переменной `CC' значение `ncc', вы заставите make использовать`ncc' для всех компиляций Си-программ, выполняемых предопределенными неявными правилами. Задав переменной `CFLAGS' значение `-g', вы можете включить опцию `-g' для всех выполняемых неявными правилами компиляций. Все неявные правила, выполняющие компиляцию программ на Си, используют переменную `$(CC)'для получения имени используемого компилятора и переменную`$(CFLAGS)' для передачи компилятору требуемых опций.

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

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

AR
Программа работы с архивами; по умолчанию, `ar'.
AS
Ассемблер; по умолчанию, `as'.
CC
Компилятор Си; по умолчанию, `cc'.
CXX
Компилятор C++; по умолчанию, `g++'.
CO
Программа для извлечения файлов из RCS; по умолчанию,`co'.
CPP
Препроцессор языка Си, выдающий результат на стандартный вывод; по умолчанию, `$(CC) -E'.
FC
Препроцессор и компилятор для Фортрана и Ратфора; по умолчанию, `f77'.
GET
Программа для извлечения файлов из SCCS; по умолчанию, `get'.
LEX
Программа для преобразования Lex-грамматики в текст на языках Си или Ратфор; по умолчанию - `lex'.
PC
Компилятор Паскаля; по умолчанию, `pc'.
YACC
Программа для преобразования Yacc-грамматики в текст на Си; по умолчанию - `yacc'.
YACCR
Программа для преобразования Yacc-грамматики в текст на языке Ратфор; по умолчанию - `yacc -r'.
MAKEINFO
Программа для преобразования исходного файла формата Texinfo в файл формата Info; по умолчанию, `makeinfo'.
TEX
Программа для преобразования исходных файлов на TeX в файлы формата DVI; по умолчанию -`tex'.
TEXI2DVI
Программа, преобразующая исходные файлы в формате Texinfo, в DVI-файлы программы TeX; по умолчанию - `texi2dvi'.
WEAVE
Программа, преобразующая текст из формата Web в формат TeX; по умолчанию -`weave'.
CWEAVE
Программа, преобразующая текст на Си-Web в формат TeX; по умолчанию -`cweave'.
TANGLE
Программа, преобразующая текст на Web в Паскаль; по умолчанию -`tangle'.
CTANGLE
Программа, преобразующая текст на Си-Web в текст на Си; по умолчанию -`ctangle'.
RM
Команда удаления файла; по умолчанию, `rm -f'.

Ниже приведена таблица переменных, содержащих дополнительные параметры для перечисленных выше программ. По умолчанию, значением этих переменных является пустая строка (если не указано другое).

ARFLAGS
Опции, передаваемые программе, манипулирующей с архивными файлам; по умолчанию`rv'.
ASFLAGS
Дополнительные параметры, передаваемые ассемблеру (при его явном вызове для файлов `.s' и `.S').
CFLAGS
Дополнительные параметры, передаваемые компилятору Си.
CXXFLAGS
Дополнительные параметры, передаваемые компилятору C++.
COFLAGS
Дополнительные параметры, передаваемые программе co (входящей в систему RCS).
CPPFLAGS
Дополнительные параметры, передаваемые препроцессору языка Си и программам, его использующим (компиляторам Си и Фортрана).
FFLAGS
Дополнительные параметры для компилятора Фортрана.
GFLAGS
Дополнительные параметры, передаваемые программе get (входящей в систему SCCS).
LDFLAGS
Дополнительные параметры, передаваемые компиляторам, когда предполагается вызов компоновщика`ld'.
LFLAGS
Дополнительные параметры, передаваемые программе Lex.
PFLAGS
Дополнительные параметры, передаваемые компилятору Паскаля.
RFLAGS
Дополнительные параметры, передаваемые компилятору Фортрана при компиляции программ на Ратфоре.
YFLAGS
Дополнительные параметры, передаваемые программе Yacc.

"Цепочки" (chains) неявных правил

В некоторых случаях, файл может быть получен путем последовательного применения нескольких неявных правил. Например, файл `n.o' может быть получен из `n.y' с помощью программы Yacc и последующего запуска компилятора cc. Подобная последовательность называется цепочкой (chain).

Если файл `n.c' существует или упоминается в make-файле, то ситуация проста - make "догадается" что объектный файл может быть построен путем компиляции из файла `n.c'; далее, при рассмотрении способа получения `n.c', будет использовано правило для запуска Yacc. В результате, оба файла - `n.c' и `n.o', будут обновлены.

Однако, даже если файл `n.c' не существует и не упоминается в make-файле, make знает, как "восстановить" недостающее звено между `n.o' и `n.y'! В этом случае, `n.c' называется промежуточным (intermediate) файлом. Как только make решит воспользоваться промежуточным файлов, он будет занесен в "базу данных" также, как если бы он упоминался в make-файле. Туда же добавляется неявное правило, описывающее процесс создания промежуточного файла.

Промежуточные файлы порождаются практически также, как и "обычные" файлы. Имеется, однако, два отличия.

Первое отличие проявляется в случае, когда промежуточный файл не существует. Если "обычный" файл b не существует и make рассматривает цель, зависящую от b, всегда сначала будет создан файл b, а затем будет обновлена зависящая от него цель. Однако, если b является промежуточным файлом, make может оставить "все как есть". Она не будет беспокоиться об обновлении b или рассматриваемой цели, если только какой-нибудь из пререквизитов b не являются "более новым", чем цель, или имеются какие-либо другие причины для обновления цели.

Второе отличие состоит в том, что если make создала промежуточный файл b для того, чтобы обновить что-нибудь еще, файл b будет потом удален (когда он станет больше не нужен). Таким образом, если до запуска make промежуточный файл не существовал, его не будет и после завершения работы make. Программа make сообщит вам об удалении, печатая для каждого удаляемого файла соответствующую команду `rm -f'.

Обычно, файл не может считаться промежуточным, если он упоминается в make-файле в качестве цели или пререквизита. Однако, вы можете явно пометить файл как промежуточный, указав его в качестве пререквизита специальной цели .INTERMEDIATE. Это сработает даже в том случае, если рассматриваемый файл тем или иным образом упоминается "явно".

Вы можете предотвратить автоматическое удаление промежуточного файла, пометив его как вторичный (secondary) Для этого, укажите нужный файл в качестве пререквизита специальной цели .SECONDARY. Когда файл считается вторичным, make не будет создавать его без крайней необходимости, и, в тоже время, не будет автоматически удалять его. Помечая файл как вторичный, вы также помечаете его как промежуточный.

Указав шаблон неявного правила (например, `%.o') в качестве пререквизита специальной цели .PRECIOUS, можно предотвратить автоматическое удаление промежуточных файлов, полученных с помощью неявных правил, чьи цели подходят под этот шаблон; смотрите раздел Прерывание или принудительное завершение make.

"Цепочка" может состоять более чем из двух неявных правил. Например, файл `foo' может быть получен из `RCS/foo.y,v' путем последовательного запуска RCS, Yacc и cc. В этом случае, оба файла `foo.y' и `foo.c' считаются промежуточными и будут в конце удалены.

Ни одно из неявных правил не может использоваться в цепочке правил более одного раза. Это, например, означает, что make даже не будет пытаться получить файл `foo' из `foo.o.o' путем двухкратного запуска компоновщика. Помимо всего прочего, это ограничение предотвращает возможное зацикливание в процессе поиска подходящих неявных правил для построения цепочки.

Несколько специальных неявных правил предназначены для оптимизации распространенных случаев, которые, в противном случае, обрабатывались бы с помощью цепочки правил. Например, файл `foo' может быть получен из `foo.c' путем поочередной компиляции и компоновки с использованием отдельных правил, связанных в цепочку (при этом, `foo.o' будет рассматриваться как промежуточный файл). На самом деле, для этого случая существует специальное правило, осуществляющее компиляцию и компоновку за "один шаг", однократным вызовом команды cc. Оптимизированное правило используется вместо цепочки правил, поскольку находится ближе к началу списка правил.

Определение и переопределение шаблонных правил (pattern rules)

Вы можете задать неявное правило, написав шаблонное правило (pattern rule). Шаблонное правило выглядит подобно обычному правилу, за исключением того, что имя его цели содержит специальный шаблонный символ`%' (в точности один). Цель рассматривается как шаблон имени файлов; символ `%' может соответствовать любой непустой подстроке, прочие символы должны совпадать. В именах пререквизитов также используется символ`%', показывающий, как их имена связаны с именем цели.

Так, шаблонное правило `%.o : %.c' показывает, как файлы с именами `основа.o' могут быть получены из соответствующих файлов с именами `основа.c'.

Обратите внимание, что "расширение" символа `%' в шаблонном правиле прозводится после вычисления всех переменных и функций (что имеет место в момент чтения make-файла). Смотрите раздел Использование переменных и раздел Функции преобразования текста.

Введение в шаблонные правила (pattern rules)

Шаблонное правило содержит в имени цели символ `%'(в точности один); в остальном, оно выглядит как обычное правило. Цель является шаблоном, с которым сверяются имена файлов; символ `%' может соответствовать любой непустой строке, другие символы должны в точности совпадать.

Например, шаблону `%.c' удовлетворяют все имена файлов, оканчивающиеся на`.c'. Под шаблон `s.%.c' подходят все имена файлов, которые начинаются с`s.', заканчиваются на `.c' и имеют длину по крайней мере пять символов. (Требуется, по крайней мере, один символ для сопоставления с`%'.) Подстрока, которая соответствует символу`%', называется основой (stem).

Символ `%' в пререквизите шаблонного правила означает ту же основу, которая соответствует символу`%' в имени цели. Для того, чтобы шаблонное правило могло быть применено к рассматриваемому файлу, имя этого файла должно подходить под шаблон цели, а из шаблонов пререквизитов должны получиться имена файлов, которые существуют или могут быть получены. Эти файлы станут пререквизитами рассматриваемого целевого файла.

Таким образом, правило вида

%.o : %.c ; команда...

указывает, как файл `n.o' может быть получен из файла `n.c', являющегося его пререквизитом, при условии, что `n.c' существует или может быть создан.

В шаблонном правиле также могут присутствовать пререквизиты, не использующие шаблонный символ`%'; такие пререквизиты будут добавлены к каждому файлу, полученному с помощью этого шаблонного правила. Такие "константные" пререквизиты иногда могут оказаться полезными.

Шаблонное правило не обязано содержать пререквизитов с `%'. Более того, оно вообще не обязано иметь каких-либо пререквизитов. Такое правило можно рассматривать как "обобщенный" шаблон. Оно будет описывать способ получения любых файлов, подходящих под шаблон цели. Смотрите раздел Определение правил "последнего шанса".

Шаблонные правила могут иметь несколько целей. Однако, в отличие от обычных правил, такой случай не рассматривается как несколько правил с одними и теми же пререквизитами и командами. Наличие в шаблонном правиле нескольких целей, означает для make, что указанные в правиле команды обновляют сразу все перечисленные цели. Команды правила исполняются только один раз, вызывая обновление всех целей. Когда выполняется поиск подходящего шаблонного правила для обрабатываемой цели, прочие присутствующие в правиле шаблоны целей не принимаются во внимание: для make существенны лишь указанные в правиле пререквизиты и команды рассматриваемой цели. Однако, после выполнения команд, обновляющих эту цель, все прочие цели, перечисленные в шаблонном правиле, также помечаются как обновленные.

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

Примеры шаблонных правил

Вот несколько примеров шаблонных правил, в действительности предопределенных в make. Сперва, правило, компилирующее файлы `.c' в файлы`.o':

%.o : %.c
        $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@

С помощью этого правила, любой файл `x.o' может быть получен из соответствующего файла `x.c'. Для того, чтобы при каждом применении этого правила, использовались правильные имена целевого и исходного файлов, его команда использует автоматические переменные`$@' и `$<'(смотрите раздел Автоматические переменные).

Вот другое встроенное правило:

% :: RCS/%,v
        $(CO) $(COFLAGS) $<

С его помощью, любой файл `x' может быть получен из соответствующего файла `x,v', находящегося в подкаталоге `RCS'. Так как в качестве имени цели указан шаблон `%', это правило может быть применено к любому файлу, имеющему подобный пререквизит. Двойное двоеточие определяет это правило как терминальное (terminal), вследствие чего, его пререквизит не может быть промежуточным файлом. (смотрите раздел Шаблонные правила с призвольным соответствием).

Следующее правило имеет две цели:

%.tab.c %.tab.h: %.y
        bison -d $<

Правило говорит о том, что выполнение команды `bison -d x.y' приведет к созданию обоих файлов - `x.tab.c' и `x.tab.h'. Например, если файл `foo' зависит от файлов `parse.tab.o' и `scan.o', а файл `scan.o' зависит от файла `parse.tab.h', то при изменении `parse.y', команда `bison -d parse.y' будет запущена только один раз, в результате чего пререквизиты обоих файлов `parse.tab.o' и `scan.o', будут обновлены. (Предполагается, что файл `parse.tab.o' будет скомпилирован из `parse.tab.c', а файл `scan.o' - из файла `scan.c'. В свою очередь, `foo' компонуется из `parse.tab.o', `scan.o' и прочих, после чего успешно работает.)

Автоматические переменные

Предположим, вы хотите написать шаблонное правило для компиляции файлов `.c' в объектные файлы`.o': каким образом вам задать правильное имя исходного файла для команды `cc'? Вы не можете явно указать имя файла, поскольку это имя будет различным в каждом случае использования данного правила.

Здесь, вам придется воспользоваться так называемыми автоматическими переменными. Значения этих переменных автоматически вычисляются заново для каждого исполняемого правила в зависимости от его целей и пререквизитов. В приведенном выше примере вам следует использовать`$@' в качестве имени объектного файла и`$<' в качестве имени исходного файла.

Вот полный перечень имеющихся автоматических переменных:

$@
Имя файла цели правила. Если цель является элементом архива (archive member), то`$@' обозначает имя архивного файла. В шаблонном правиле с несколькими целями (смотрите раздел Введение в шаблонные правила),`$@' обозначает имя цели, которая вызывала запуск команд данного правила.
$%
Для целей, являющихся элементами архива, обозначает имя этого элемента. Смотрите раздел Использование make для обновления архивов. Например, для цели `foo.a(bar.o)' переменная `$%' принимает значение `bar.o', а переменная`$@' - значение `foo.a'. Если цель не является элементом архива, `$%' имеет пустое значение.
$<
Имя первого пререквизита. В случае, если выполняемые команды относятся к неявному правилу, первым пререквизитом является тот, который был указан в неявном правиле. (смотрите раздел Использование неявных правил).
$?
Имена всех пререквизитов (разделенные пробелами), которые являются "более новыми", чем цель. Для членов архива, используется имя самого элемента (смотрите раздел Использование make для обновления архивов).
$^
Имена всех пререквизитов (разделенные пробелами). Для пререквизитов, которые являются элементами архивов, используются только имена элементов (смотрите раздел Использование make для обновления архивов). Независимого от того, сколько раз конкретный файл был указан в списке пререквизитов, цель будет иметь только одну зависимость от этого файла. Таким образом, если в списке пререквизитов одно и то же имя файла будет фигурировать несколько раз, переменная $^ все равно будет содержать только одну копию этого имени.
$+
Аналогично `$^', но пререквизиты, перечисленные более, чем один раз, также будут продублированы (в том порядке, как они были указаны в make-файле). В основном, эта переменная может быть полезна в командах компоновки, где порядок следования библиотек и их возможное дублирование является существенным.
$*
Основа (stem), с которой было сопоставлено неявное правило (смотрите раздел Процедура сопоставления с шаблоном). Например, для цели `dir/a.foo.b' и шаблона цели `a.%.b', основой будет строка `dir/foo'. Основа имени может быть полезной для конструирования имен взаимосвязанных файлов. В статическом шаблонном правиле, основой является часть имени файла, соотвествующая символу `%'в шаблоне цели. Для явного правила такое определение неприменимо, поэтому`$*' вычисляется по-другому. В случае явного правила, если имя цели имеет один из "известных" суффиксов (смотрите раздел Устаревшие суффиксные правила), в переменную `$*' записывается имя цели без этого суффикса. Например, для цели `foo.c', переменная`$*' будет установлена в `foo', поскольку`.c' является одним из "известных" суффиксов. Программа GNU make поступает столь причудливым образом лишь по соображениям совместимости с другими версиями make. Мы рекомендуем вам избегать использования переменной`$*' где-либо, кроме неявных или статических шаблонных правил. В случае, если цель явного правила не имеет один известных make суффиксов, для данного правила значением переменной`$*' является пустая строка.

Переменная `$?' может оказаться полезна даже в явных правилах, когда вы хотите работать только с пререквизитами, которые были изменены. Представьте, например, что архивный файл `lib' содержит копии некоторых объектных файлов. Следующее правило запишет в архив копии только изменившихся объектных файлов:

lib: foo.o bar.o lose.o win.o
        ar r lib $?

Из всех перечисленных выше переменных, четыре переменные представляют собой одиночные имена файлов, а две переменные - списки имен файлов. Каждая из указанных шести переменных имеет варианты, позволяющие получить вместо полного имени файла только имя каталога, где он расположен, или же только имя файла внутри каталога. Имена этих дополнительных вариантов переменных образуются путем добавления к "основному" имени переменной символов `D' и`F', соответственно. В GNU make эти варианты переменных можно считать устаревшими, поскольку вместо них лучше использовать функции dir и notdir (смотрите раздел Функции для обработки имен файлов). Заметьте, однако что `D'-варианты переменных не содержат конечного '/', который всегда присутствует на выходе функции dir. Вот список дополнительных вариантов автоматических переменных:

`$(@D)'
Часть имени файла, определяющее имя каталога, где он расположен (без конечного символа '/'). Например, если значением`$@' является `dir/foo.o', то `$(@D)'получит значение `dir'. В случае, если `$@' не содержит символов '/', переменная `$(@D)' будет содержать `.'.
`$(@F)'
Имя файла без имени каталога. Например, если значением`$@' является `dir/foo.o', то `$(@F)'будет содержать `foo.o'. Выражение `$(@F)'эквивалентно `$(notdir $@)'.
`$(*D)'
`$(*F)'
Часть основы, определяющая имя каталога и имя файла внутри каталога, соответственно; в данном примере, это будут строки `dir' и `foo'.
`$(%D)'
`$(%F)'
Для целей, являющихся элементами архивов, определяет имя каталога и имя файла элемента архива. Эти переменные имеют смысл только целей, которые являются элементами архива (имеющих форму `архив(элемент)') и полезны только в случае, если элемент может содержать имя каталога. (Смотрите раздел Использование элементов архива в качестве целей.)
`$(<D)'
`$(<F)'
Имя каталога и имя файла (внутри каталога) первого пререквизита.
`$(^D)'
`$(^F)'
Список каталогов и имен файлов всех пререквизитов.
`$(?D)'
`$(?F)'
Список каталогов и имен файлов всех пререквизитов, которые являются "более новыми", чем цель.

Вы можете обратить внимание на то, что при ссылке на автоматические переменные, чьи имена состоят из одного символа, мы используем запись вида$имя_переменной, а не $(имя_переменной), как это практикуется для "обычных" переменных. На самом деле, это лишь ничего не значащее стилистическое соглашение. С тем же успехом, мы могли бы писать `$(<)' вместо `$<'.

Процедура сопоставления с шаблоном

Шаблон цели состоит из символа `%', заключенного между префиксом и суффиксом, каждый из которых (или оба сразу) может быть пустым. Имя файла будет подходить под указанный шаблон только если оно начинается с указанного префикса и заканчивается указанным суффиксом (причем, префикс и суффикс не могут перекрываться). Текст, заключенный между префиксом и суффиксом, называется основой (stem). Таким образом, файл `test.o' удовлетворяет шаблону `%.o' и его основой является строка`test'. Пререквизиты шаблонного правила преобразуются в имена конкретных файлов, путем подстановки основы вместо символа`%'. Так, в приведенном выше примере, из пререквизита`%.c', будет получено имя файла `test.c'.

Если шаблон цели не содержит символа '/' (так, обычно, и происходит), то имя каталога будет удалено из имени рассматриваемого файла, перед тем, как оно будет сравниваться с префиксом и суффиксом шаблона. Далее, после сравнения имени файла с шаблоном, это имя каталога будет опять добавлено к уже сгенерированным именам пререквизитов (имя каталога удалялось лишь для нахождения подходящего неявного правила). Так, имя `src/eat' подойдет под шаблон `e%t', а его основой будет являться`src/a'. Далее, при получении имен пререквизитов, имя каталога, содержащегося в выделенной основе, будет добавляться в начало каждого пререквизита, а оставшаяся часть основы будет подставляться вместо символа`%'. Например, основа `src/a' в комбинации с шаблоном пререквизита `c%r', даст имя файла `src/car'.

Шаблонные правила с призвольным (match-anything) соответствием

Когда в качестве цели шаблонного правила выступает шаблон`%', ему может соответствовать любое имя файла. Такие правила мы называем правилами с произвольным (match-anything) соответствием. Зачастую, они весьма полезны, но, к сожалению, могут требовать очень много времени для своей обработки, поскольку make должна будет рассмотреть возможность их применения к любому файлу, указанному в качестве цели или пререквизита.

Допустим, что в make-файле упоминается имя `foo.c'. Для такой цели make должна будет рассмотреть возможность компоновки ее из объектного файла `foo.c.o', возможность использования компилятора Си для компиляции и компоновки ее из файла `foo.c.c', возможность использования компилятора Паскаля для компиляции и компоновки ее из файла `foo.c.p', и множество других аналогичных возможностей.

Конечно, мы знаем, что подобные сценарии бессмыслены, поскольку `foo.c' является исходным текстом на языке Си, а не исполняемым файлом. В конце концов make также отвергнет подобные возможности, поскольку файлы `foo.c.o' и `foo.c.p' не будут существовать. Однако, из-за большого числа разнообразных возможностей, make придется затратить очень много времени на их проверку.

Для ускорения работы, мы внесли некоторые ограничения в процесс обработки программой make шаблонных правил с произвольным соответствием. Существуют два возможных вида ограничений. Каждый раз, при задании правила с произвольным соответствие, вы должны выбрать один или другой вид ограничения.

Один из вариантов - пометить такое правила как терминальное, задав его с помощью двойного двоеточия. Если правило является терминальным, оно может быть применено только в том случае, когда его пререквизит реально существуют. Случаи, когда пререквизит "может быть получен", не рассматриваются. Иными словами, терминальное правило не может служить "окончанием" цепочки правил.

Например, встроенные неявные правила для извлечения исходных файлов из файлов RCS и SCCS, являются терминальными. В результате, например, при отсутствии файла `foo.c,v', make не будет пытаться получить его из файлов `foo.c,v.o' или `RCS/SCCS/s.foo.c,v'. Как правило, файлы RCS и SCCS являются действительно "исходными", и не могут быть получены из любых других файлов; таким образом, make может сэкономить массу времени, не пытаясь найти способ для их обновления.

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

Так, например, файл `foo.c' подходит под шаблон цели неявного правила`%.c : %.y' (правила для запуска Yacc). Независимо от того, применимо ли в данном случае это правило (это зависит от существования файла `foo.y'), самого факта наличия правила с такой целью, достаточно, чтобы предотвратить попытки применения любых нетерминальных правил с произвольным соответствием к файлу `foo.c'. Таким образом, make даже не будет рассматривать возможность получения файла `foo.c' из таких файлов, как `foo.c.o', `foo.c.c', `foo.c.p' и так далее.

Смысл этого ограничения состоит в том, что нетерминальные правила с произвольным соответствием используются для создания файлов, содержащих определенный вид данных (например, исполняемых файлов), а файлы с "известными" суффиксами содержат какие-то другие специфические виды данных (например, исходные файлы на Си).

На самом деле, make содержит большое число специальных шаблонных правил-"пустышек", единственное назначение которых - распознать определенные имена файлов, дабы нетерминальные правила с произвольным соответствием к таким файлам не применялись. Эти правила-"пустышки" не содержат ни команд, ни пререквизитов, и, будучи "бесполезны", игнорируются во всех других случаях. Так, например, встроенное неявное правило

%.p :

существует только для того, чтобы файлы с исходными текстами на Паскале (например, `foo.p') сопоставлялись с определенным шаблоном цели, и, соответственно, не тратилось время на поиск файлов `foo.p.o', `foo.p.c' и тому подобных.

Аналогичные шаблонные правила-"пустышки" существуются для всех суффиксов, которые используются в суффиксных правилах (смотрите раздел Устаревшие суффиксные правила).

Отмена действия неявных правил

Вы можете "перекрыть" встроенное неявное правило (или ваше собственное правило), задав новое шаблонное правило, имеющее такую же цель и пререквизиты, но другие команды. При определении нового правила, встроенное правило будет заменено. "Позиция" нового правила в списке неявных правил, будет зависеть от месторасположения его определения.

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

%.o : %.s

Определение правил "последнего шанса" (last-resort rules)

Вы можете определить правило "последнего шанса" (last-resort rule), написав терминальное правило с произвольным соответствием, не имеющее пререквизитов (смотрите раздел Шаблонные правила с призвольным соответствием). Такое правило является обычным шаблонным правилом; единственная его особенность заключается в том, что с ним может быть "сопоставлена" любая цель. Таким образом, команды из этого правила будут использованы для всех целей и пререквизитов, не имеющих своих собственных команд и к которым не подходит ни одно из имеющихся неявных правил.

Например, при тестировании работы make-файла, обычно, важен лишь сам факт наличия требуемых исходных файлов, а не их реальное содержимое. Написав, в таком случае, следующее правило:

%::
        touch $@

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

Возможен и другой подход - вы можете задать команды, которые будут использованы для целей, не имеющих подходящих правил (даже правил без команд). Для этого надо задать правило со специальной целью .DEFAULT. Команды из этого правила будут использованы для всех пререквизитов, не имеющих явных правил и к которым не может быть применено ни одно из неявных правил. Естественно, по умолчанию правила с целью .DEFAULT не существует. Такое правило нужно писать самостоятельно.

Правило для цели .DEFAULT, не имеющее пререквизитов и команд:

.DEFAULT:

очищает список команд, ранее определенных для .DEFAULT. Далее, make работает так, как если бы .DEFAULT никогда не определялась.

Если вы не хотите, чтобы для цели были использованы команды из шаблонного правила с произвольным (match-anything) соответствием или из правила для цели .DEFAULT и, в то же время, вы не хотите, чтобы для цели запускались какие-либо команды, вы можете использовать для нее пустые команды (смотрите раздел Пустые команды).

Вы можете использовать правило "последнего шанса" для "перекрытия" части другого make-файла. Смотрите раздел"Перекрытие" части make-файла.

Устаревшие суффиксные правила (suffix rules)

Суффиксные правила (suffix rules) являются устаревшим способом задания неявных (implicit) правил. Поскольку механизм шаблонных (pattern) правил является более "общим" и понятным, суффиксные правила можно считать устаревшими. Программа GNU make поддерживает их только по соображениям совместимости со "старыми" make-файлами. Суффиксные правила разделяются на два вида: с одиночным суффиксом (single-suffix) и с двойным суффиксом (double-suffix).

Правило с двойным суффиксом содержит в себе пару суффиксов: один для цели и один для пререквизита. Под него подходит любая цель, чье имя имеет указанный суффикс цели. Соответствующее имя пререквизита получается путем замены суффикса цели на суффикс пререквизита в имени обрабатываемого файла. Правило с двойным суффиксом, чей суффикс цели `.o' и суффикс пререквизита `.c', эквивалентно шаблонному правилу`%.o : %.c'.

Правило с одиночным суффиксом определяет только суффикс исходного файла. Под это правило может подойти любое имя файла, а имя соответствующего пререквизита получается путем добавления указанного суффикса исходного файла. Так, правило с одиночным суффиксом`.c' эквивалентно шаблонному правилу `% : %.c'.

Суффиксное правило распознается путем сравнения цели каждого правила с определенным в данный момент списком "известных" суффиксов. Когда make видит правило, чья цель является одним из "известных" суффиксов, это правило рассматривается как суффиксное правило с одиночных суффиксом. Если make видит правило, чья цель представляет собой конкатенацию (сцепление) двух "известных" суффиксов, такое правило рассматривается как суффиксное правило с двойным суффиксом.

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

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

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

.c.o: foo.h
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

описывает процесс получения файла `.c.o' из пререквизита `foo.h', а не рассматривается как шаблонное правило:

%.o: %.c foo.h
        $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<

которое задает способ получения файлов `.o'из файлов `.c' и указывает на зависимость всех файлов `.o', полученных с помощью этого шаблонного правила, от файла `foo.h'.

Суффиксные правила без команд также не имеют смысла, поскольку не отменяют действие ранее определенных правил (как это делают шаблонные правила, не имеющие команд; смотрите раздел Отмена действия неявных правил). Такие правила просто добавляют в базу данных свой суффикс (или пару сцепленных суффиксов) в качестве цели.

"Известные суффиксы" являются просто списком пререквизитов специальной цели .SUFFIXES. Вы можете добавить в этот список новые суффиксы, указав их в правиле для цели .SUFFIXES, например:

.SUFFIXES: .hack .win

Здесь, суффиксы `.hack' и `.win' добавляются в конец списка "известных" суффиксов.

Если вы хотите задать свой собственный список суффиксов, а не добавлять свои суффиксы к существующему списку, используйте правило с целью .SUFFIXES, не имеющее пререквизитов. Такое правило обрабатывается специальным образом и очищает список "известных" суффиксов. Далее, вы можете написать еще одно правило для добавления нужных вам суффиксов. Например:

.SUFFIXES:            # Delete the default suffixes
.SUFFIXES: .c .o .h   # Define our suffix list

Задание опций `-r' или `--no-builtin-rules' приводит к тому, что используемый по умолчанию список суффиксов, будет пуст.

Определенный по умолчанию список "известных" суффиксов (который был определен до того, как make начнет обрабатывать make-файлы) заносится в переменную SUFFIXES. Далее, вы можете менять список суффиксов с помощью правил для специальной цели .SUFFIXES, но это не будет отражаться на значении этой переменной.

Алгоритм поиска неявных правил

Ниже приведен алгоритм, которому следует make в процессе поиска подходящего неявного правила для цели t. Эта процедура выполняется для всех правил с двойным двоеточием, у которых нет команд. Она также выполняется для каждой цели обычных правил, если ни в одном из этих правил не указано команд. Этот же алгоритм поиска применяется для всех пререквизитов, не являющихся целями ни одного из правил make-файла, а также рекурсивно выполняется для пререквизитов неявных правил в процессе поиска возможных "цепочек" неявных правил.

Суффиксные правила не упоминаются в этом алгоритме, поскольку преобразуются в эквивалентные им шаблонные правила во время чтения make-файла.

Для целей, которые являются элементами архива (имеют форму`архив(элемент)'), указанный ниже алгоритм применяется дважды; первый раз - с использованием полного имени цели t, и во второй раз - используя`(элемент)' в качестве цели t (если при первом проходе подходящее правило найдено не было).

  1. Разделить имя цели t на две части - имя каталога (d), и остаток строки (без имени каталога) n . Например, если имя t представляет собой строку`src/foo.o', то частью d будет `src/', а частью n - фрагмент `foo.o'.
  2. Составить список шаблонных правил, чьи цели могут быть сопоставлены с t или n. Если шаблон цели содержит символ'/', он будет сравниваться с t; в противном случае, шаблон будет сравниваться с n.
  3. Если хотя бы одно правило из этого списка, не является правилом с произвольным соответствием, удалить из списка все нетерминальные правила с произвольным соответствием.
  4. Удалить из списка все правила, не имеющие команд.
  5. Для каждого шаблонного правила из списка:
    1. Ищется основа s, которая представляет из себя непустую часть t или n, соответствующую символу `%' в шаблоне цели.
    2. Путем подстановки основы s вместо`%', вычисляются имена пререквизитов; Если шаблон цели не содержит символа '/', добавить d в начало имени каждого из пререквизитов.
    3. Проверить, все ли пререквизиты существуют или должны существовать. (Мы говорим, что файл "должен существовать", если он упоминается в make-файле в качестве цели или явно указанного пререквизита.) Если все пререквизиты существуют или должны существовать, или, если в правиле нет пререквизитов, это правило применяется.
  6. Если подходящее шаблонное правило до сих пор не найдено, производится вторая попытка - для каждого шаблонного правила из списка:
    1. Если правило является терминальным, пропустить его и перейти к следующему правилу.
    2. Вычислить имена пререквизитов (также, как это делалось ранее, во время первого прохода).
    3. Проверить, все ли пререквизиты существуют или могут быть созданы.
    4. Рекурсивно используя описываемый алгоритм поиска, для каждого несуществующего пререквизита определить, может ли он быть создан с помощью подходящего неявного правила.
    5. Если все пререквизиты существуют, должны существовать, или могут быть получены с помощью неявных правил, рассматриваемое правило применяется.
  7. Если ни одно из неявных правил не может быть применено, используется правило для цели .DEFAULT (если такое правило существует). В этом случае, для цели t выполняются те же команды, какие указаны для цели .DEFAULT. Иначе, считается, что для цели t нет команд.

Как только подходящее правило будет найдено, для каждого шаблона цели (кроме того, который был сопоставлен с t или n), символ`%' заменяется на s и получившееся имя запоминается до тех пор, пока не будут выполнены команды, обновляющие t. После выполнения этих команд, все запомненные имена файлов добавляются в "базу данных" и помечаются как обновленные (информация о статусе обновления, при этом, заимствуется из файла t).

При выполнении команд шаблонного правила для цели t, автоматические переменные получают значения, соответствующие данной цели и пререквизитам. Смотрите раздел Автоматические переменные.

Использование make для обновления архивов

Архивные файлы представляют из себя файлы, содержащие внутри себя набор файлов. Эти "внутренние" файлы называются элементами (members). Для работы с архивными файлами используется программа ar. Одно из основных применений архивных файлов - хранение библиотеки подпрограмм, используемых при компоновке программы.

Использование элементов архива в качестве целей

Отдельные элементы архивного файла могут быть использованы в качестве целей или пререквизитов. Указать элемент элемент архива архив можно с помощью конструкции:

архив(элемент)

Эту конструкцию можно использовать только в именах целей и пререквизитов, но не в командах! Большинство программ не поддерживают такой синтаксис и не могут "напрямую" работать с элементами архивов. Только программа ar и другие программы, специально спроектированные для работы с архивами, могут это делать. Поэтому, как правило, все команды для обновления цели, являющейся элементом архива, так или иначе будут использовать программу ar. Например, следующее правило создает элемент `hack.o' архива `foolib' путем копирования в архив файла `hack.o':

foolib(hack.o) : hack.o
        ar cr foolib hack.o

На самом деле, практически все цели, являющиеся элементами архивов, обновляются подобным образом; для этого даже существует соответствующее неявное правило. Обратите внимание на необходимость задания для программы ar опции`c' в том случае, если архивный файл пока не существует.

Для задания сразу нескольких элементов одного архива, можно написать имена всех элементов "вместе" внутри скобок. Так, следующий пример:

foolib(hack.o kludge.o)

эквивалентен:

foolib(hack.o) foolib(kludge.o)

При задании имен элементов архивов можно также использовать шаблонные символы "в стиле" командного интерпретатора. Смотрите раздел Использование шаблонных символов в именах файлов. Например, `foolib(*.o)' будет ссылаться на все существующие элементы архива `foolib', чьи имена заканчиваются на`.o'; возможно, это будут элементы`foolib(hack.o) foolib(kludge.o)'.

Неявные правила для целей - элементов архива

Вспомните, что цель вида `a(m)', означает элемент m архивного файла a.

Когда make подбирает подходящее неявное правило для подобной цели, наряду с правилами, которые могут соответствовать цели `a(m)', она рассматривает также и правила, которые могут быть применены к цели `(m)'.

При этом, будет запущено специальное правило с целью `(%)'. Это правило обновляет цель `a(m)' путем копирования файла m в архив. Например, это правило сможет обновить цель `foo.a(bar.o)' путем копирования файла `bar.o' в архив `foo.a' в качестве элемента с именем `bar.o'.

Будучи связанным в цепочку с другими, это правило может сослужить хорошую службу. Так, при наличии файла `bar.c', команды`make "foo.a(bar.o)"' (здесь, кавычки использованы для предотвращения специальной интерпретации символов`(' и `)' интерпретатором командной строки) будет достаточно для запуска такой последовательности команд (при этом, даже не потребуется make-файла):

cc -c bar.c -o bar.o
ar r foo.a bar.o
rm -f bar.o

В этом примере, make использовала файл `bar.o' в качестве промежуточного. Смотрите раздел "Цепочки" неявных правил.

Подобные неявные правила пишутся с использованием автоматической переменной`$%'. Смотрите раздел Автоматические переменные.

Имя каталога не может содержаться в имени элемента архива, но его можно использовать в make-файле для получения аналогичного эффекта. Например, цель `foo.a(dir/file.o)' будет автоматически обновляться make с помощью команды:

ar r foo.a dir/file.o

которая будет копировать файл `dir/file.o' в элемент `file.o' архива foo.a. В подобных случаях, могут быть полезны автоматические переменные %D и %F.

Обновление каталога символов архивного файла

Архивный файл, используемый в качестве библиотеки, как правило, содержит специальный элемент с именем `__.SYMDEF', содержащий каталог всех внешних символов, на которые ссылаются другие элементы этого архива. После обновления любого другого элемента архива, вам потребуется обновить `__.SYMDEF', дабы он содержал актуальную информацию. Это делается путем запуска программы ranlib:

ranlib файл_архива

Обычно, эта команда помещается в правило для архивного файла, пререквизитами которого являются все элементы этого архива. Например,

libfoo.a: libfoo.a(x.o) libfoo.a(y.o) ...
        ranlib libfoo.a

Здесь, при обновлении любого из элементов архива (`x.o', `y.o', и так далее), будет запущена программа ranlib, которая обновит каталог архива - элемент `__.SYMDEF'. В приведенном выше фрагменте, правила, обновляющие элементы архива, не показаны; в большинстве ситуаций, вы можете не указывать их явно, положившись на встроенное неявное правило, копирующее файлы в архив (это правило обсуждалось в предыдущем разделе).

Программа GNU ar автоматически обновляет элемент `__.SYMDEF', вследствие чего, необходимость в подобного рода правилах, отпадает.

Проблемы при использовании архивов

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

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

Суффиксные правила для архивных файлов

Для работы с архивными файлами, вы можете использовать суффиксное правило специального вида. Смотрите раздел Устаревшие суффиксные правила, где подробно обсуждаются суффиксные правила. Суффиксные правила для архивных файлов можно считать устаревшими, поскольку поддерживаемые в GNU make шаблонные правила для архивов являются более "общим" механизмом (смотрите раздел Неявные правила для целей - элементов архива). Однако, суффиксные правила для архивов по-прежнему поддерживаются из соображений совместимости с другими реализациями make.

Суффиксное правило для архивов пишется с использованием целевого суффикса`.a' (это обычный суффикс архивных файлов). Вот пример устаревшей записи - суффиксное правило для обновления библиотеки (которая является архивным файлом) из исходных файлов на языке Си:

.c.a:
        $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
        $(AR) r $@ $*.o
        $(RM) $*.o

Это будет работать аналогично следующему шаблонному првилу:

(%.o): %.c
        $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
        $(AR) r $@ $*.o
        $(RM) $*.o

На самом деле, make именно так и поступает, видя суффиксное правило с целевым суффиксом `.a'. Любое правило с двойным суффиксом вида`.x.a', преобразуется make в соответствующее шаблонное правило с шаблоном цели`(%.o)' и шаблоном пререквизита`%.x'.

Поскольку вы вправе использовать суффикс `.a' для совершенно произвольных файлов (а не только для архивов), make также преобразует подобное суффиксное правило в шаблонное правило и "обычным" способом (смотрите раздел Устаревшие суффиксные правила). Так, суффиксное правило `.x.a'будет преобразовано в два шаблонных правила:`(%.o): %.x' и `%.a: %.x'.

Возможности GNU make

Ниже приведен обзор возможностей программы GNU make в сравнении с другими версиями make и указано, откуда были "позаимствованы" те или иные функции. В качестве "базовой", мы рассматриваем версию make из состава операционной системы BSD 4.2. Если вы стремитесь к написанию "переносимых" make-файлов, вам следует использовать только те возможности make, которые не перечислены здесь, а также в разделе Несовместимость и нереализованные функции.

Многие возможности были позаимствованы из версии программы make, имевшейся в System V.

Следующие возможности "навеяны" различными версиями make. В некоторых случаях, мы затрудняемся сказать, откуда именно были "позаимствованы" те или иные возможности.

Остальные возможности являются нововведениями GNU make:

Несовместимость и нереализованные функции

Не все возможности, имеющиеся в различных версиях make реализованы в GNU make. Однако, среди нет таких, которые требовались бы стандартом POSIX.2 (IEEE Standard 1003.2-1992).

Принятые соглашения для make-файлов

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

Общие соглашения для make-файлов

Каждый make-файл должен содержать строку:

SHELL = /bin/sh

во избежании проблем при работе в системах, где переменная SHELL может быть "унаследована" из операционного окружения. (Для GNU make, однако, это не составляет проблемы.)

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

.SUFFIXES:
.SUFFIXES: .c .o

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

Не следует предполагать, что `.' находится в пути поиска исполняемых команд. Когда вам нужно запустить программу, являющуюся частью вашего пакета, используйте `./' если эта программа строится в ходе обработки make-файла или `$(srcdir)/' если запускаемый файл является "неизменной" частью и его можно отнести к исходному коду. Если нет ни одного из этих префиксов, будет использован текущий путь поиска.

Разница между `./' (директория, где происходит сборка проекта) и `$(srcdir)/' (директория с исходными текстами) существенна, поскольку пользователь может запустить компиляцию в отдельной директории, указав опцию`--srcdir' для `configure'. Например, правило вида:

foo.1 : foo.man sedscript
        sed -e sedscript foo.man > foo.1

не будет работать, если сборка проекта происходит не в директории с исходными файлами, поскольку файлы `foo.man' и `sedscript' находятся именно там.

При использовании GNU make, можно полагаться на `VPATH'при наличии единственного файла пререквизита, поскольку автоматическая переменная `$<' укажет на исходный файл, где бы он ни находился. (Многие версии make устанавливают`$<' только для неявных правил.) Таким образом, для корректной работы `VPATH', вместо

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o

следует писать

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@

При наличии нескольких пререквизитов, проще всего, явно указывать префикс `$(srcdir)'. Так, приведенный выше пример для `foo.1', лучше всего записать следующим образом:

foo.1 : foo.man sedscript
        sed -e $(srcdir)/sedscript $(srcdir)/foo.man > $@

При использовании GNU make, можно полагаться на `VPATH'при наличии единственного файла пререквизита, поскольку автоматическая переменная `$<' укажет на исходный файл, где бы он ни находился. (Многие версии make устанавливают`$<' только для неявных правил.) Таким образом, для корректной работы `VPATH', вместо

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o

следует писать

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@

При наличии нескольких пререквизитов, проще всего, явно указывать префикс `$(srcdir)'. Так, приведенный выше пример для `foo.1', лучше всего записать следующим образом:

foo.1 : foo.man sedscript
        sed -e $(srcdir)/sedscript $(srcdir)/foo.man > $@

Пакеты GNU, обычно, содержат некоторые файлы, не являющиеся исходными, например, файлы в формате Info, выходные файлы программ Autoconf, Automake, Bison или Flex. Поскольку, как правило, эти файлы располагаются в директории с исходными текстами, они и должны всегда располагаться там, а не в директории, где происходит сборка проекта. Таким образом, правила make-файла, обновляющие эти файлы, должны помещать их в директорию с исходными текстами.

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

Желательно, также, попробовать добиться корректной работы make-файла (по крайней мере, для целей сборки и инсталляции) при запуске make в параллельном режиме.

Использование утилит

Команды, указываемые в make-файле (включая скрипты, такие как configure), следует писать в рассчете на интерпретатор sh, а не csh. Не используйте специфические возможности оболочек ksh или bash.

Скрипт configure и указанные в make-файле правила для сборки и инсталляции не должны напрямую использовать никаких утилита, за исключением:

cat cmp cp diff echo egrep expr false grep install-info
ln ls mkdir mv pwd rm rmdir sed sleep sort tar test touch true

В правиле dist, для компрессирования можно использовать программу gzip.

Для этих программ следует пользоваться только "общепринятыми" опциями. Например, не используйте`mkdir -p', поскольку эта опция поддерживается лишь в немногих системах.

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

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

ar bison cc flex install ld ldconfig lex
make makeinfo ranlib texi2dvi yacc

Для запуска этих программ следует использовать следующие переменные make:

$(AR) $(BISON) $(CC) $(FLEX) $(INSTALL) $(LD) $(LDCONFIG) $(LEX)
$(MAKE) $(MAKEINFO) $(RANLIB) $(TEXI2DVI) $(YACC)

Если вы используете программы ranlib или ldconfig, убедитесь, что не произойдет ничего плохо при отсутствии этих программ в системе. Перед выполнением такой команды, выдайте сообщение для пользователя, что отсутствие этих команд не является проблемой, а ошибку, которая может возникнуть при попытке выполнения, проигнорируйте. (Здесь, может помочь макрос `AC_PROG_RANLIB' программы Autoconf.)

При использовании символических ссылок, вы должны предусмотреть "запасной вариант" для систем, где они не поддерживаются.

Вот список дополнительных утилит, которые можно использовать через соответствующие переменные make:

chgrp chmod chown mknod

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

Переменные для имен команд

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

В частности, большинство утилит нужно запускать с помощью соответствующих переменных. Так, при использовании программы Bison, следует использовать переменную BISON, чье значение, по умолчанию, устанавливается как`BISON = bison', и использовать переменную $(BISON) при каждом запуске Bison.

Вызов утилит, манипулирующих с файлами (таких, как ln, rm, mv и им подобных), может производится без использования переменных, поскольку пользователям нет необходимости заменять эти утилиты другими программами.

Для каждой переменной, содержащая имя программы, должна иметься соответствующая переменная для хранения опций, которые будут передаваться этой программе. Для получения имени этой переменной, добавьте `FLAGS' к имени перенной, ссылающейся на соответствующую программу. Так, например, опции для BISON должны храниться в переменной BISONFLAGS. (Имена CFLAGS для компилятора Си, YFLAGS для программы yacc и LFLAGS для lex, являются исключениями, используемыми только в силу их "стандартности".) Используйте CPPFLAGS для любых команд, использующих препроцессор и переменную LDFLAGS во всех командах, производящих компоновку или компиляцию с последующей компоновкой.

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

CFLAGS = -g
ALL_CFLAGS = -I. $(CFLAGS)
.c.o:
        $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<

Напротив, опцию `-g' вполне можно включить в CFLAGS, поскольку она не требуется для успешной компиляции. Ее можно рассматривать как значение по умолчанию, которое лишь рекомендуется. Если, по умолчанию, предполагается, что пакет будет компилироваться с помощью компилятора GCC, в начальное значение CFLAGS можно также включить опцию`-O'.

Помещайте ссылку на CFLAGS в конец строки с командой компиляции, после других переменных, содержащих опции компиляции, дабы пользователь мог использовать CFLAGS для "перекрытия" этих опций.

Переменная CFLAGS должна использоваться при любом вызове компилятора Си (как для компиляции, так и для компоновки).

Каждый make-файл должен определять переменную INSTALL, которая является базовой командой для инсталляции файлов в систему.

Каждый make-файл должен определять переменные INSTALL_PROGRAM и INSTALL_DATA. (По умолчанию, они должны иметь значение $(INSTALL).) Далее, эти переменные должны использоваться для инсталляции, соответственно, исполняемых и неисполняемых файлов. Эти переменные используются примерно таким способом:

$(INSTALL_PROGRAM) foo $(bindir)/foo
$(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a

К имени целевого файла вы можете, дополнительно, добавить значение переменной DESTDIR. Сделав это, вы дадите возможность инсталлятору получить "слепок" инсталляции, который, в дальнейшем, может быть использован для реальной инсталляции в систему. Не пытайтесь установить значение DESTDIR самостоятельно, из своего make-файла. С поддержкой DESTDIR, приведенный выше пример можно переписать так:

$(INSTALL_PROGRAM) foo $(DESTDIR)$(bindir)/foo
$(INSTALL_DATA) libfoo.a $(DESTDIR)$(libdir)/libfoo.a

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

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

Каталоги, куда происходит инсталляция всегда должны именоваться с использованием переменных, дабы пакет легко мог быть установлен в "нестандартное" место. Ниже приведены стандартные имена для таких переменных. Они базируются на "общепринятой" (в Unix) структуре файловой системы; ее варианты используются в SVR4, 4.4BSD, Linux, Ultrix v4 и других современных операционных системах.

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

`prefix'
Префикс, используемый для конструирования значений по умолчанию для перечисленных ниже переменных. По умолчанию, значением prefix должно быть `/usr/local'. При построении полной GNU-системы "с нуля", этот префикс будет содержать пустое значение, а `/usr' будет символической ссылкой на `/'. (При использовании Autoconf, записывается как `@prefix@'.) Запуск `make install' со значением prefix, отличным от того, который использовался для сборки пакета, не должен приводить к перекомпиляции этого пакета.
`exec_prefix'
Префикс, используемый при конструировании значений по умолчанию для некоторых из перечисленных ниже переменных. По умолчанию, значением exec_prefix должно быть $(prefix). (При использовании Autoconf, записывается как`@exec_prefix@'.) В основном, $(exec_prefix) используется для каталогов, содержащих машинно-зависимые файлы (например, исполняемые файлы и файлы библиотек), в то время как для остальных каталогов используется $(prefix). Запуск `make install' со значением exec_prefix, отличным от того, который использовался для сборки пакета, не должен приводить к перекомпиляции этого пакета.

Исполняемые файлы должны инсталлироваться в одну из следующих директорий.

`bindir'
Каталог для инсталляции исполняемых программ, которые могут быть запущены пользователем. Обычно, это `/usr/local/bin', но вам следует использовать запись `$(exec_prefix)/bin'. (При использовании Autoconf, пишется как `@bindir@'.)
`sbindir'
Каталог для инсталляции исполняемых программ, которые могут быть запущены из командного интерпретатора, но полезны, в основном, только для администраторов системы. Обычно, это директория `/usr/local/sbin', но вам следует использовать запись `$(exec_prefix)/sbin'. (При использовании Autoconf, пишется как`@sbindir@'.)
`libexecdir'
Каталог для инсталляции исполняемых программ, которые запускаются не пользователями, а другими программами. Обычно, это каталог `/usr/local/libexec', но вам следует использовать запись `$(exec_prefix)/libexec'. (При использовании Autoconf, записывается как`@libexecdir@'.)

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

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

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

`datadir'
Директория, куда инсталлируются файлы данных, используемые только для чтения и независимые от архитектуры. Обычно, это каталог `/usr/local/share', но вы должны использовать запись `$(prefix)/share'. (При использовании Autoconf, записывается как`@datadir@'.) Ниже рассматривается специальное исключение - каталоги `$(infodir)' и `$(includedir)'.
`sysconfdir'
Каталог, куда инсталлируются файлы с неизменяемыми данных, относящиеся только к конкретной машине (грубо говоря, файлы конфигурации хоста). Примерами могут служить конфигурационные файлы почтовой программы и сетевой поддержки, `/etc/passwd' и тому подобное. Все файлы, помещаемые в эту директорию, должны быть обычными текстовыми ASCII файлами. Как правило, это каталог `/usr/local/etc', но вам следует использовать запись `$(prefix)/etc'. (При использовании Autoconf, пишется как`@sysconfdir@'.) Не помещайте в эту директорию исполняемых файлов (их, скорее всего, следует поместить в `$(libexecdir)' или `$(sbindir)'). Также, не помещайте в этот каталог файлов, которые модефицируются в ходе "обычной" работы (разумеется, мы не рассматриваем случаи использования программ, предназначенных для изменения конфигурационных файлов). Изменяемые файлы следует помещать в `$(localstatedir)'.
`sharedstatedir'
Каталог для инсталляции архитектурно-независимых файлов данных, которые модефицируются в ходе работы пакета. Обычно, это будет `/usr/local/com', но вам следует использовать запись `$(prefix)/com'. (При использовании Autoconf, пишется как `@sharedstatedir@'.)
`localstatedir'
Каталог для инсталляции файлов с модефицируемыми данными, относящимися к конкретной машине. У пользователей не должно возникать необходимости в модефикации файлов из этого каталога для конфигурирования пакета; информацию о конфигурации следует помещать в отдельные файлы, расположенные в каталогах `$(datadir)' или `$(sysconfdir)'. Переменная `$(localstatedir)' обычно будет содержать значение `/usr/local/var', но вам следует использовать запись `$(prefix)/var'. (При использовании Autoconf, записывается как `@localstatedir@'.)
`libdir'
Каталог для размещения объектных файлов и библиотек объектных файлов. Не помещайте сюда исполняемые файлы - инсталлируйте их в директорию `$(libexecdir)'. Как правило, значением libdir будет `/usr/local/lib', но вам следует использовать запись `$(exec_prefix)/lib'. (При использовании Autoconf, пишется как`@libdir@'.)
`infodir'
Каталог, куда будут помещаться Info файлы вашего пакета. По умолчанию, это будет `/usr/local/info', но вам следует использовать запись `$(prefix)/info'. (При использовании Autoconf, записывается как`@infodir@'.)
`lispdir'
Директория, куда помещаются все Lisp-файлы для редактора Emacs, входящие в состав вашего пакета. Как правило, это `/usr/local/share/emacs/site-lisp', но вам следует использовать запись `$(prefix)/share/emacs/site-lisp'. При использовании Autoconf, это записывается как `@lispdir@'. Для того, чтобы запись`@lispdir@' сработала, в вашем `configure.in' должна быть следующая строка:
lispdir='${datadir}/emacs/site-lisp'
AC_SUBST(lispdir)
`includedir'
Каталог, куда будут помещаться заголовочные файлы, предназначенные для включения в пользовательские программы с помощью директивы`#include' препроцессора Си. Обычно, это каталог `/usr/local/include', но вам следует использовать запись `$(prefix)/include'. (При использовании Autoconf, записывается как`@includedir@'.) Кроме GCC, большинство других компиляторов не выполняют поиск заголовочных файлов в каталоге `/usr/local/include', так что помещение их в данный каталог имеет смысл только при использовании компилятора GCC. Зачастую, это не является проблемой, поскольку многие библиотеки ориентированы на работу только с GCC. Однако, некоторые библиотеки могут работать и с другими компиляторами, поэтому их заголовочные файлы следует помещать сразу в два места - каталоги includedir и oldincludedir.
`oldincludedir'
Каталог для заголовочных файлов `#include', предназначенных для компиляторов, отличных от GCC. Обычно, это каталог `/usr/include'. (При использовании Autoconf, записывается как`@oldincludedir@'.) Указанные в make-файле команды инсталляции должны проверять значение oldincludedir. Если это значение пусто, процесс инсталляции не должен пытаться его использовать, а должен отменить "вторую" инсталляцию заголовочных файлов. Пакет не должен замещать заголовочных файлов, находящихся в этой директории, если только они не взяты из этого же пакета. Так, если в пакете Foo имеется заголовочный файл `foo.h', то при инсталляции он должен помещаться в каталог oldincludedir только если (1) там нет файла `foo.h' или (2) файл `foo.h' существует и был ранее установлен пакетом Foo. Для проверки того, что `foo.h' был установлен именно пакетом Foo, поместите в этот файл (как часть комментария) строку с определенной сигнатурой, по которой файл можно будет "опознать" с помощью программы grep.

Файлы помощи в стиле Unix (man-страницы, man pages) должны размещаться в одном из следующих каталогов:

`mandir'
Корневая директория для размещения файлов помощи (если такие имеются) вашего пакета. Обычно, это будет `/usr/local/man', но вам следует использовать запись it as `$(prefix)/man'. (При использовании Autoconf, записывается как `@mandir@'.)
`man1dir'
Каталог для установки man-страниц, относящихся к разделу 1. Следует записывать как `$(mandir)/man1'.
`man2dir'
Директория для man-страниц, относящихся к разделу 2. Следует записывать как `$(mandir)/man2'
`...'
Не используйте формат man-страничек как основной формат документации для программ GNU. Пишите документацию в формате Texinfo. Man-странички пригодны только для людей, использующих программы GNU в Unix-подобных операционных системах.
`manext'
Расширение имени файла для инсталлируемых man-страничек. Оно должно начинаться с точки за которой следует соответствующая цифра; обычно, это будет`.1'.
`man1ext'
Расширение имени файла для инсталляции man-страничек, относящихся к секции 1.
`man2ext'
Расширение имени файла для инсталляции man-страничек, относящихся к секции 2.
`...'
Используйте эти имена вместо `manext', если пакет нуждается в инсталляции man-страничек, относящихся к нескольким секциям.

И, наконец, вы должны установить следующую переменную:

`srcdir'
Каталог с исходными файлами компилируемого пакета. Значение этой переменной, обычно, устанавливается скриптом configure. (При использовании Autconf, используйте запись `srcdir = @srcdir@'.)

Пример:

# Общий префикс для инсталляционных каталогов.
# Примечание: Этот каталог должен существовать еще до начала инсталляции.
prefix = /usr/local
exec_prefix = $(prefix)
# Сюда будет помещаться исполняемый файл команды `gcc'.
bindir = $(exec_prefix)/bin
# Сюда будут помещаться каталоги, используемые компилятором.
libexecdir = $(exec_prefix)/libexec
# Сюда будут помещаться Info-файлы.
infodir = $(prefix)/info

Если ваша программа устанавливает большое количество файлов в один из "стандартных" каталогов, определенных пользователем, можно сгруппировать их в отдельный подкаталог, относящийся к данному пакету. Такие подкаталоги должны создаваться правилом install.

Не следует ожидать, что устанавливаемые пользователем значения указанных выше переменных, будут содержать имена конкретных подкаталогов (соответствующих данному пакету). Смысл наличия "унифицированного" набора имен переменных состоит в том, чтобы пользователь мог задать одинаковые значения для нескольких разных пакетов GNU-программ. Пакеты должны быть спроектированы таким образом, чтобы правильно использовать задаваемые пользователем значения.

Стандартные имена целей для пользователей

Все GNU-программы должны иметь в своем make-файле следующие цели:

`all'
Компиляция всей программы. По умолчанию, именно эта цель должна являться главной целью. Эта цель не должна пересобирать файлы документации; Info-файлы должны иметься в составе дистрибутива, а файлы DVI должны создаваться только по специальному запросу. По умолчанию, компиляция и компоновка должна выполняться с опцией`-g', дабы исполняемые файлы имели отладочную информацию. Пользователи, которые не бояться оказаться в трудной ситуации, могут, при желании, потом убрать эту отладочную информацию.
`install'
Компиляция программы и копирование исполняемых файлов, файлов библиотек и прочих файлов в те места, где они должны, в действительности, располагаться в системе. При наличии какого-нибудь простого теста, проверяющего правильность инсталляции пакета, такой тест должен запускаться. Не убирайте отладочную информацию из исполняемых файлов во время их инсталляции. Озабоченные наличием такой информации пользователи, могут использовать install-strip. Будучи запущенной сразу после `make all', install, по возможности, не должна ничего модефицировать в каталоге, где собиралась программа. Дело в том, что сборка программного пакета и его инсталляция очень часто выполняются под разными именами пользователей. Если каталогов, куда инсталлируются файлы пакета, не существует, они должны создаваться (в том числе и каталоги, указанные в prefix и exec_prefix). Для этого можно использовать правило installdirs (описано ниже). Используйте `-'во всех командах, инсталлирующих man-странички, дабы игнорировать любые ошибки, которые могут возникать в системах, не имеющих документации в формате man-страничек. Файлы Info инсталлируются путем копирования их в каталог `$(infodir)' при помощи $(INSTALL_DATA) (смотрите раздел Переменные для имен команд), с последующим запуском install-info (если эта программа задана). Переменная install-info содержит имя программы, которая редактирует файл `dir' (каталог Info-файлов), добавляя или обновляя записи об инсталлированных Info-файлах; эта программа является частью пакета Texinfo. Вот пример правила для инсталляции Info-файла:
$(DESTDIR)$(infodir)/foo.info: foo.info
        $(POST_INSTALL)
# В каталоге . может находится более новая версия info-файла, чем в srcdir.
        -if test -f foo.info; then d=.; \
         else d=$(srcdir); fi; \
        $(INSTALL_DATA) $$d/foo.info $(DESTDIR)$@; \
# Запускаем install-info только при его наличии.
# Используем `if' вместо начального `-' 
# чтобы не пропустить ошибку, которую может вернуть install-info.
# Мы используем `$(SHELL) -c', поскольку некоторые оболочки
# завершаются не вполне корректно, встретив неизвестную команду.
        if $(SHELL) -c 'install-info --version' \
           >/dev/null 2>&1; then \
          install-info --dir-file=$(DESTDIR)$(infodir)/dir \
                       $(DESTDIR)$(infodir)/foo.info; \
        else true; fi
При описании цели install, вы должны отнести все ее команды к одной из трех категорий: обычные (normal), команды пред-инсталляции (pre-installation) и команды пост-инсталляции (post-installation). Смотрите раздел "Категории" команд инсталляции.
`uninstall'
Удалить все инсталлированные файлы - копии файлов, созданные при выполнении `install'. Это правило не должно модефицировать каталоги, где осуществлялась сборка пакета - можно модефицировать только каталоги с инсталлированными файлами. Команды деинсталляции также, как и команды инсталляции, делятся на три категории. Смотрите раздел "Категории" команд инсталляции.
`install-strip'
Аналогично install, но в процессе инсталляции из исполняемых файлов удаляется отладочная информация. Во многих случаях, определение этой цели может быть очень простым:
install-strip:
        $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \
                install
Обычно, мы не рекомендуем удалять из исполняемых файлов отладочную информацию, если только вы не уверены, что программа не содержит ошибок. Однако, вполне разумно инсталлировать исполняемые файлы без отладочной информации, сохранив где-нибудь (на случай ошибки) их "оригинальные" версии с отладочной информацией.
`clean'
Удалить из текущей директории все файлы, созданные в ходе сборки программы. Файлы с конфигурацией, при этом, удаляться не должны. Не должны также удаляться файлы, которые, хотя и могут быть созданы заново, но, как правило, не создаются, так как имеются в пакете уже в "готовом виде". Напротив, файлы `.dvi' следует удалить, если только они не в входят в дистрибутив пакета.
`distclean'
Удаляет все файлы из текущей директории, созданные в процессе конфигурировании или сборки пакета. Если вы распаковали исходные файлы и собрали программу, не создавая никаких дополнительных файлов, после команды `make distclean', в каталоге должны остаться только файлы, входящие в исходный дистрибутив пакета.
`mostlyclean'
Подобно `clean', но может воздержаться от удаления некоторых файлов, которые, обычно, "нежелательно" перекомпилировать. Так, например,`mostlyclean' для компилятора GCC не удаляет файл `libgcc.a', поскольку необходимость в его перекомпиляции возникает редко, а занимает она много времени.
`maintainer-clean'
Удаляет из текущей директории практически все, что может быть построено с помощью make-файла. В этот список, обычно, входят все файлы, удаляемые с помощью distclean, а также: Си-программы, полученные с помощью Bison, таблицы тегов, Info-файлы и тому подобное. Мы сказали "практически все", потому что команда`make maintainer-clean' не должна удалять скрипт `configure', даже если если для него имеется правило в make-файле, с помощью которого `configure' может быть создан заново. В общем, команда `make maintainer-clean' не должна удалять ничего, что необходимо для запуска `configure' и последующей сборки пакет. Это и является единственным исключением; все остальные файлы, которые могут быть построены заново, команда maintainer-clean должна удалять. Предполагается, что `maintainer-clean' будет использоваться только лицом, сопровождающим данный пакет, а не обычными пользователями. Вполне возможно, что для получения некоторых файлов, удаленных при помощи`make maintainer-clean', могут потребоваться какие-то специальные программы, не включенные в состав дистрибутива. Поскольку, все нужные для сборки пакета файлы входят в дистрибутив, нам нет смысла беспокоиться о том, насколько прост процесс их создания. Так что, если после команды `make maintainer-clean' окажется, что для сборки пакета вам придется заново распаковывать дистрибутив - не жалуйтесь. Для того, чтобы предупредить пользователя о возможных проблемах, правило для цели maintainer-clean должно начинаться следующими командами:
@echo 'This command is intended for maintainers to use; it'
@echo 'deletes files that may need special tools to rebuild.'
('Эта команда предназначена для использования только лицом, сопровождающим данный пакет; она удаляет некоторые файлы, для создания которых требуются специальные программы.')
`TAGS'
Обновляет таблицу тегов (tags table) для программы.
`info'
Сгенерировать все необходимые Info-файлы. Один из лучших способов определить подобное правило - использовать запись, наподобие:
info: foo.info

foo.info: foo.texi chap1.texi chap2.texi
        $(MAKEINFO) $(srcdir)/foo.texi
В make-файле вы должны определить переменную MAKEINFO. Она должна запускать программу makeinfo, входящую в состав пакета Texinfo. Как правило, пакеты программ GNU имеют в своем дистрибутиве все необходимые Info-файлы, а это означает, что Info-файлы находятся в каталоге с исходными файлами. Таким образом, команды, обновляющие info-файлы, должны обновлять их в директории с исходными файлами. Обычно, при сборке пользователем пакета программ, обновления Info-файлов не происходит, поскольку в дистрибутиве они находятся в "готовом виде" и не нуждаются в обновлении.
`dvi'
Сгенерировать DVI-файлы для всей документации в формате Texinfo. Например:
dvi: foo.dvi

foo.dvi: foo.texi chap1.texi chap2.texi
        $(TEXI2DVI) $(srcdir)/foo.texi
В make-файле вы должны определить переменную TEXI2DVI. Она должна запускать программу texi2dvi, которая входит в состав пакета Texinfo. (3) Как альтернатива, в правиле можно перечислить только пререквизиты, предоставив GNU make возможность самостоятельно выполнить нужные команды.
`dist'
Создать дистрибутивный tar-файл для этой программы. Tar-файл должен быть построен таким образом, чтобы имена содержащихся в нем файлов начинались с имени каталога, отражающим название пакета, для которого предназначается данный дистрибутив. Это имя может включать в себя номер версии пакета. Например, дистрибутивный tar-файл компилятора GCC версии 1.40 распаковывается в подкаталог с именем `gcc-1.40'. Проще всего это сделать, создав подкаталог с нужным именем и поместить туда нужные файлы с помощью ln или cp. Далее, для этого каталога надо выполнить команду tar и сжать полученный архивный файл программой gzip. Например, дистрибутивный файл для GCC версии 1.40 называется `gcc-1.40.tar.gz'. Цель dist должна иметь явные зависимости от всех файлов, которые не являются исходными, но, вместе с тем, должны входить в дистрибутив. В этом случае, будет уверенность, что все такие файлы имеют самую свежую версию и попадут в состав дистрибутива. Смотрите раздел `Making Releases' документа GNU Coding Standards.
`check'
Выполнить самотестирование программы (если оно предусмотрено). Перед запуском тестов, пользователь должен осуществить сборку программы, но не обязан ее инсталлировать; вы должны писать тесты таким образом, чтобы для своей работы они не требовали инсталляции проверяемого пакета.

Там, где это уместно, рекомендуется использовать цели со следующими именами:

installcheck
Проверить правильность инсталляции (если подобный тест предусмотрен). Перед запуском теста, пользователь должен собрать и инсталлировать пакет. Не следует предполагать, что каталог `$(bindir)' находится в пути поиска.
installdirs
В make-файле полезно иметь цель `installdirs', создающую все каталоги (включая и родительские), которые используются для инсталляции файлов пакета. В составе пакета Texinfo имеется скрипт `mkinstalldirs', который удобно использовать для подобной цели. Используя этот скрипт, соответствующее правило можно записать так:
# Убедиться в том, что все требуемые для инсталляции каталоги (например, $(bindir)) 
# действительно существуют и, при необходимости, создать их.
installdirs: mkinstalldirs
        $(srcdir)/mkinstalldirs $(bindir) $(datadir) \
                                $(libdir) $(infodir) \
                                $(mandir)
Подобное правило не должно модефицировать каталогов, где осуществлялась сборка пакета. Это правило не должно делать ничего, кроме создания каталогов для инсталляции.

"Категории" команд инсталляции

При описании цели install, вы должны отнести указываемые команды к одной из трех категорий: обычные (normal) команды, команды пред-инсталляции (pre-installation) и команды пост-инсталляции (post-installation).

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

Команды пред-инсталляции и пост-инсталляции могут изменять другие файлы; в частности, модефицировать "глобальные" конфигурационные файлы или файлы записей.

Обычно, команды пред-инсталляции исполняются до "обычных" команд инсталляции, а команды пост-инсталляции - после "обычных" команд.

Чаще всего, команды пост-инсталляции используются для запуска install-info. Для этого не могут быть использованы обычные команды, поскольку при этом изменяется содержимое файла (Info-директории), который не является частью инсталлируемого пакета. Для этого нужно использовать команды пост-инсталляции, потому что подобное действие должно выполняться после завершения работы "обычных" команд, которые инсталлируют необходимые Info-файлы пакета.

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

Для того, чтобы отнести команды правила install к одной из трех возможных категорий, перед ними надо вставить соответствующую строку с именем категории (category lines). Эта строка задаст категорию для следующих за нею команд.

Строка с указанием категории состоит из символа табуляции, за которым следует ссылка на специальную переменную; в конце строки может находится комментарий. Всего существует три таких специальных переменных - по одной на каждую категорию команд; каждое имя указывает свою категорию. При "обычном" исполнении, строки с категориями не выполняют никаких операций, поскольку соответствующие переменные, обычно, не определены (и вы не должны определять их в своем make-файле).

Ниже перечислены все три возможных категории:

        $(PRE_INSTALL)     # Далее следуют команды пред-инсталляции.
        $(POST_INSTALL)    # Далее следуют команды пост-инсталляции.
        $(NORMAL_INSTALL)  # Далее следуют "обычные" команды.

При отсутствии строки с категорией в начале правила install, все командные строки от начала правила до первой строки с категорией, будут рассматриваться как "обычные". При отсутствии каких-либо строк с категориями, все команды правила будут рассматриваться как "обычные".

Аналогично, имеется три категории команд для правила uninstall:

        $(PRE_UNINSTALL)     # Далее следуют команды пред-деинсталляции.
        $(POST_UNINSTALL)    # Далее следуют команды пост-деинсталляции.
        $(NORMAL_UNINSTALL)  # Далее следуют "обычные" команды.

Обычно, команды пред-деинсталляции используются для удаления записей (о деинсталлируемых Info-файлах) из Info-директории.

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

Команды пред-инсталляции и пост-инсталляции не должны запускать каких-либо программ, кроме:

[ basename bash cat chgrp chmod chown cmp cp dd diff echo
egrep expand expr false fgrep find getopt grep gunzip gzip
hostname install install-info kill ldconfig ln ls md5sum
mkdir mkfifo mknod mv printenv pwd rm rmdir sed sort tee
test touch true uname xargs yes

Необходимость разделения команд на категории возникает из-за необходимости уметь инсталлировать "бинарные" дистрибутивы пакетов. Как правило, такой пакет содержит все необходимые файлы (в том числе и исполняемые) в готовом виде и использует свой собственный метод их инсталляции. Таким образом, ему не требуется запускать "обычные" команды инсталляции. Однако, при инсталляции бинарного пакета, нужно выполнить команды пред-инсталляции и пост-инсталляции.

Программы для сборки бинарных пакетов работают, "извлекая" команды пред-инсталляции и пост-инсталляции. Вот один из возможных способов извлечения команд пред-инсталляции:

make -n install -o all \
      PRE_INSTALL=pre-install \
      POST_INSTALL=post-install \
      NORMAL_INSTALL=normal-install \
  | gawk -f pre-install.awk

Здесь, файл `pre-install.awk' может содержать что-нибудь, наподобие:

$0 ~ /^\t[ \t]*(normal_install|post_install)[ \t]*$/ {on = 0}
on {print $0}
$0 ~ /^\t[ \t]*pre_install[ \t]*$/ {on = 1}

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

Справочник

В данном приложении перечислены все директивы, функции и специальные переменные, распознаваемые программой GNU make. Смотрите также разделы Имена специальных целей, Перечень имеющихся неявных правил, и Обзор опций.

Вот перечень директив, распознаваемых GNU make:

define имя_переменной
endef
Определить многострочную, рекурсивно-вычисляемую переменную.
Смотрите раздел Именованные командные последовательности.
ifdef переменная
ifndef переменная
ifeq (a,b)
ifeq "a" "b"
ifeq 'a' 'b'
ifneq (a,b)
ifneq "a" "b"
ifneq 'a' 'b'
else
endif
Условно обработать часть make-файла.
Смотрите раздел Условные части make-файла.
include файл
-include файл
sinclude файл
Подключить другой make-файл.
Смотрите раздел Подключение других make-файлов.
override имя_переменной = значение
override имя_переменной := значение
override имя_переменной += значение
override имя_переменной ?= значение
override define имя_переменной
endef
Определить переменную с "перекрытием" предыдущего ее определения (в том числе и заданного с помощью командной строки).
Смотрите раздел Директива override.
export
Инструктирует make экспортировать, по умолчанию, все переменные в дочерние процессы.
Смотрите раздел Связь с make "нижнего уровня" через переменные.
export переменная
export переменная = значение
export переменная := значение
export переменная += значение
export переменная ?= значение
unexport переменная
Включить или отключить экспорт конкретной переменной в дочерние процессы.
Смотрите раздел Связь с make "нижнего уровня" через переменные
vpath шаблон путь
Задать путь поиска для файлов, подходящих под указанный шаблон (с символом%).
Смотрите раздел Директива vpath.
vpath шаблон
Удалить все пути поиска, заданные ранее для указанного шаблона.
vpath
Удалить все пути поиска, заданные ранее с помощью директив vpath.

Далее приведен список функций, манипулирующих с текстом (смотрите раздел Функции преобразования текста):

$(subst исходная_строка,конечная_строка,текст)
Заменить исходную_строку на конечную_строку в указанном тексте.
Смотрите раздел Функции анализа и подстановки строк.
$(patsubst шаблон,замена,текст)
Заменить все слова, подходящие под шаблон, на замену в указанном тексте.
Смотрите раздел Функции анализа и подстановки строк.
$(strip строка)
Удалить из указанной строки избыточные пробелы.
Смотрите раздел Функции анализа и подстановки строк.
$(findstring искомая_строка,текст)
Найти искомую_строку в указанном тексте.
Смотрите раздел Функции анализа и подстановки строк.
$(filter шаблон...,текст)
Выбрать из указанного текста все слова, подходящие под шаблон(ы).
Смотрите раздел Функции анализа и подстановки строк.
$(filter-out шаблон...,текст)
Выбрать из текста слова, не подходящие ни под один из указанных шаблонов.
Смотрите раздел Функции анализа и подстановки строк.
$(sort список)
Отсортировать слова из списка в лексикографическом порядке, удалив дубликаты.
Смотрите раздел Функции анализа и подстановки строк.
$(dir имена...)
Из указанных имен файлов выделяет части, определяющие имена каталогов.
Смотрите раздел Функции для обработки имен файлов.
$(notdir имена...)
Из каждого указанного имени файла выделить часть, которая не является именем каталога.
Смотрите раздел Функции для обработки имен файлов.
$(suffix имена...)
Из каждого имени файла выделить суффикс (последний `.' и следующие за ним символы).
Смотрите раздел Функции для обработки имен файлов.
$(basename имена...)
Выделяет "базовое имя" (часть имени без суффикса) из каждого имени файла.
Смотрите раздел Функции для обработки имен файлов.
$(addsuffix суффикс,имена...)
Добавляет суффикс к каждому из указанных имен.
Смотрите раздел Функции для обработки имен файлов.
$(addprefix префикс,имена...)
Предваряет префиксом каждое из указанных имен.
Смотрите раздел Функции для обработки имен файлов.
$(join список1,список2)
Объединяет два "параллельных" списка слов.
Смотрите раздел Функции для обработки имен файлов.
$(word n,текст)
Выделяет n-ное слово (счет начинается с единицы) из указанного текста.
Смотрите раздел Функции для обработки имен файлов.
$(words текст)
Подсчитывает количество слов в указанном тексте.
Смотрите раздел Функции для обработки имен файлов.
$(wordlist от,до,текст)
Возвращает список слов из указанного текста с номерами от и до.
Смотрите раздел Функции для обработки имен файлов.
$(firstword имена...)
Выделяет первое слово из указанного списка имен.
Смотрите раздел Функции для обработки имен файлов.
$(wildcard шаблон...)
Получить список файлов, чьи имена подходят под указанный шаблон (шаблон записывает в формате интерпретатора командной строки, а не`%'-шаблона).
Смотрите раздел Функция wildcard.
$(error сообщение...)
При вычислении этой функции, make генерирует фатальную ошибку с указанным сообщением.
Смотрите раздел Функции управления сборкой.
$(warning сообщение...)
При вычислении этой функции, make выдает предупреждение (warning) с указанным сообщением.
Смотрите раздел Функции управления сборкой.
$(shell команда)
Выполнить команду оболочки и возвратить выведенную ей информацию.
Смотрите раздел Функция shell.
$(origin переменная)
Вернуть строку, описывающую, каким образом была определена переменная make переменная.
Смотрите раздел Функция origin.
$(foreach переменная-аргумент,слова,текст)
Вычислить значение текста, поочередно подставляя в переменную-аргумент слова из списка слова, и объединить полученные результаты.
Смотрите раздел Функция foreach.
$(call переменная,параметр,...)
Вычислить и вернуть значение переменной, заменяя ссылки $(1), $(2) на значения первого, второго и так далее параметров.
Смотрите раздел Функция call.

Вот список имеющихся автоматических переменных. Смотрите раздел Автоматические переменные, где они описаны подробно.

$@
Имя файла цели.
$%
Имя элемента для целей, являющихся элементами архива.
$<
Имя первого пререквизита из списка пререквизитов
$?
Имена всех пререквизитов (разделенные пробелами), которые являются более новыми, чем цель. Для пререквизитов, являющихся элементами архивов, используются только имена элементов (смотрите раздел Использование make для обновления архивов).
$^
$+
Имена всех пререквизитов, разделенные пробелами. Для пререквизитов, являющихся элементами архивов, используются только имена элементов (смотрите раздел Использование make для обновления архивов). Значение переменной $^ не содержит дубликатов пререквизитов, в то время как $+ сохраняет дубликаты и "оригинальный" порядок следования пререквизитов.
$*
Основа имени (stem), с которой было сопоставлено неявное правило (смотрите раздел Процедура сопоставления с шаблоном).
$(@D)
$(@F)
Части имени $@, которые представляют собой имя каталога и имя файла внутри каталога, соответственно.
$(*D)
$(*F)
Части имени $*, которые представляют собой имя каталога и имя файла внутри каталога, соответственно.
$(%D)
$(%F)
Части имени $%, которые представляют собой имя каталога и имя файла внутри каталога, соответственно.
$(<D)
$(<F)
Части имени $<, которые представляют собой имя каталога и имя файла внутри каталога, соответственно.
$(^D)
$(^F)
Части имени $^, которые представляют собой имя каталога и имя файла внутри каталога, соответственно.
$(+D)
$(+F)
Части имени $+, которые представляют собой имя каталога и имя файла внутри каталога, соответственно.
$(?D)
$(?F)
Части имени $?, которые представляют собой имя каталога и имя файла внутри каталога, соответственно.

Следующие переменные GNU make использует специальным образом:

MAKEFILES
Make-файлы, которые будут считываться при каждом вызове make.
Смотрите раздел Переменная MAKEFILES.
VPATH
Путь поиска для файлов, которые не могут быть найдены в текущем каталоге.
Смотрите раздел Переменная VPATH: список каталогов для поиска пререквизитов.
SHELL
Имя используемого по умолчанию командного интерпретатора, обычно `/bin/sh'. В своем make-файле вы можете установить для переменной SHELL новое значение, изменив, тем самым, командный интерпретатор, который будет использоваться для вызова команд. Смотрите раздел Исполнение команд.
MAKESHELL
Используется только при работе в системе MS-DOS и содержит имя командного интерпретатора, который будет использоваться make. Это значение имеет приоритет перед значением переменной SHELL. Смотрите раздел Исполнение команд.
MAKE
Имя, с помощью которого была вызвана make. Использование этой переменной в командах имеет специальное значение. Смотрите раздел Как работает переменная MAKE.
MAKELEVEL
Текущий "уровень вложенности" make при рекурсивном вызове.
Смотрите раздел Связь с make "нижнего уровня" через переменные.
MAKEFLAGS
Опции, заданные для make. Вы можете установить эту переменную из операционной среды или присвоить ей нужное значение внутри make-файла.
Смотрите раздел Передача опций в make "нижнего уровня". Никогда не задавайте значение MAKEFLAGS непосредственно в командной строке: в командный интерпретатор это значение может быть передано некорректно. Никогда не препятствуйте рекурсивно вызванным экземплярам make в получении значения этой переменной через операционную среду.
MAKECMDGOALS
Цели, заданные make в командной строке. Присваивание этой переменной другого значения не влияет на работу make.
Смотрите раздел Аргументы для задания главной цели.
CURDIR
Имя текущего рабочего каталога (после того, как были обработаны все опции -C, если такие были заданы). Присваивание этой переменной другого значения, не влияет на работу make.
Смотрите раздел Рекурсивный вызов make.
SUFFIXES
Список используемых по умолчанию (до того, как make начнет интерпретировать make-файлы) суффиксов для суффиксных правил.
.LIBPATTERNS
Определяет способ именования и порядок следования библиотек, поиск которых проводит make.
Смотрите раздел Поиск в каталогах для подключаемых библиотек.

Сообщения об ошибках

Далее, приведен список наиболее распространенных ошибок, выдаваемых программой make, с информации о том, что они означают, и как их можно исправить.

Иногда, ошибки make не являются фатальными, особенно при наличии префикса - в командах или опции -k в аргументах командной строки. Ошибки, являющиеся фатальными, предваряются строчкой ***.

Сообщения об ошибки также предваряются именем программы (обычно,`make'), или, если ошибка произошла в конкретном make-файле, то именем этого файла и номером строки, где была обнаружена ошибка.

В приведенной ниже таблице такого рода общие "префиксы" опущены.

`[foo] Error NN'
`[foo] описание сигнала'
Эти ошибки не являются ошибками make. Они означают, что программа, запущенная make в качестве команды, вернула ненулевой код возврата (`Error NN'), который интерпретируется make как ошибка, либо эта программа была аварийно завершена (например, получив соответствующий сигнал). Смотрите раздел Ошибки при исполнении команд. Отсутствие в начале сообщения об ошибке строки *** означает, что make игнорировала данную ошибку из-за наличия в команде префикса -.
`missing separator. Stop.'
`missing separator (did you mean TAB instead of 8 spaces?). Stop.'
Данные сообщения означают, что make не смогла разобраться в "типе" очередной считанное строки. Для определения типа очередной строки, GNU make проверяет наличие в ней нескольких возможных разделителей (:, =, символ табуляции и так далее). Данное сообщение означает, что не найден ни один из возможных разделителей. Зачастую, появление таких ошибок связано с использованием текстовых редакторов, которые, при выравнивании строк, вместо символа табуляции используют последовательность пробелов (этим отличаются многие текстовые редакторы для MS-Windows). В таких случаях make будет использовать второй вариант сообщения об ошибке. Помните, что каждая команда в make-файле должна начинаться с символа табуляции. Восемь пробелов не заменяют один символ табуляции. Смотрите раздел Синтаксис правил.
`commands commence before first target. Stop.'
`missing rule before commands. Stop.'
Это означает, что make-файл, похоже, начинается с командных строк: в начале идет символ табуляции, а следующая за ним конструкция не является допустимой командой make (такой, например, как оператор присваивания). Командные строки всегда должны относиться к какой-то цели. Второй вариант сообщения об ошибке используется в том случае, когда первым непробельным символом в строке является двоеточие; make интерпретирует эту ситуацию как отсутствие левой части правила "цель: пререквизит". Смотрите раздел Синтаксис правил.
`No rule to make target `xxx'.'
`No rule to make target `xxx', needed by `yyy'.'
Это означает, что программа make решила обновить указанную цель, но не может найти никаких подходящих для этого правил (ни явных, ни неявных, включая встроенные неявные правила). Если вы хотите, чтобы этот файл был создан, вам нужно добавить в make-файл соответствующее правило, описывающее процесс достижения подобной цели. Зачастую, такая ошибка является следствием простой описки (неправильно записанного имени файла) или повреждения каталога с исходными файлами (когда make попытается построить недостающие исходные файлы).
`No targets specified and no makefile found. Stop.'
`No targets. Stop.'
Первое сообщение означает, что вы не задали никаких целей в командной строке и make не может найти ни одного make-файла для обработки. Второе сообщение означает, что был найден некоторый make-файл, однако он не содержит ни одной цели, которую можно было бы выбрать по умолчанию, а в командной строке вы тоже не указали ни одной цели. В такой ситуации GNU make не может сделать ничего полезного. Смотрите раздел Аргументы для задания make-файла.
`Makefile `xxx' was not found.'
`Included makefile `xxx' was not found.'
Программа make не может найти make-файл, указанный в командной строке (сообщение первого вида), или подключаемый make-файл (сообщение второго вида).
`warning: overriding commands for target `xxx''
`warning: ignoring old commands for target `xxx''
Для каждой цели, GNU make позволяет задать лишь один набор команд (исключением являются правила с двойным двоеточием). Такое предупреждающее сообщение выдается при попытке задать команды для цели, которая ранее уже была определена как имеющая команды; при этом, первый набор команд будет "перекрыт" вторым заданным набором. Смотрите раздел Несколько правил с одной целью.
`Circular xxx <- yyy dependency dropped.'
Это означает, что make обнаружила циклическую зависимость: пререквизит yyy цели xxx (возможно, через цепочку других пререквизитов) опять зависит от цели xxx.
`Recursive variable `xxx' references itself (eventually). Stop.'
Означает, что вы определили обычную (рекурсивно вычисляемую) переменную xxx, которая, при попытке ее вычисления, ссылается на саму себя (xxx). Это является ошибкой; вам нужно использовать либо упрощенно-вычисляемую переменную (:=), либо оператор добавления (+=). Смотрите раздел Использование переменных.
`Unterminated variable reference. Stop.'
Означает, что вы забыли указать закрывающиеся круглые или фигурные скобки при ссылке на переменную или функцию.
`insufficient arguments to function `xxx'. Stop.'
Это означает, что вы не задали необходимого числа параметров для указанной функции. Смотрите документацию на эту функцию, где указан список требуемых аргументов. Смотрите раздел Функции преобразования текста.
`missing target pattern. Stop.'
`multiple target patterns. Stop.'
`target pattern contains no `%'. Stop.'
Эти ошибки возникают при неправильном составлении статических шаблонных правил. Первая ошибка означает, что в правиле нет шаблона цели. Вторая ошибка означает, что в разделе целей указано сразу несколько шаблонов. Третья ошибка означает, что имя цели не содержит шаблонного символа (%). Смотрите раздел Синтаксис статических шаблонных правил.
`warning: -jN forced in submake: disabling jobserver mode.'
Это и описанное ниже сообщение генерируется в том случае, если make обнаруживает проблему, связанную с "параллельным" режимом работы в системе, где такой режим поддерживается и make "нижнего уровня" могут "общаться" между собой (смотрите раздел Передача опций в make "нижнего уровня"). Данное предупреждение генерируется в том случае, если make "нижнего уровня" была запущена с аргументом `-jN' (где N больше единицы). Такое может произойти, например, если вы самостоятельно установите переменную среды MAKE и присвоите ей значение`make -j2'. В этом случае, рекурсивно вызванные копии make не будут пытаться "связаться" с другими копиями make, а будут работать исходя из того, что они могут запускать не более двух заданий одновременно.
`warning: jobserver unavailable: using -j1. Add `+' to parent make rule.'
Для того, чтобы запущенные копии make могли "общаться" между собой, родительская копия передает в дочернюю копию некоторую дополнительную информацию. Это может вызвать проблемы, если дочерний процесс не является, на самом деле, программой make. Поэтому, родительский процесс make передает эту дополнительную информацию в дочерний процесс, если только он уверен, что дочерний процесс действительно является программой make. Для этого используется "обычный" алгоритм (смотрите раздел Как работает переменная MAKE). Если make-файл построен таким образом, что родительская копия make не уверена, что дочерний процесс является программой make, в дочерний процесс будет передана лишь часть необходимой информации. В этом случае, дочерний процесс выдает предупреждающее сообщение и выполняет работу в "последовательном" режиме.

Пример "сложного" make-файла

Вот пример make-файла, используемого для сборки программы GNU tar. Это - относительно сложный make-файл.

По умолчанию, главной целью становится первая цель `all'. Интересной особенностью данного make-файла является то, что исходный файл `testpad.h' автоматически создается программой testpad, которая, в свою очередь, компилируется из `testpad.c'.

При выполнении команды `make' или `make all', будет создан исполняемый файл `tar', демон `rmt', обеспечивающий удаленный доступ и Info-файл `tar.info'.

При выполнении команды `make install', make не только создаст файлы `tar', `rmt', и `tar.info', но и инсталлирует их в систему.

При выполнении `make clean', make удаляет все файлы `.o', а также файлы `tar', `rmt', `testpad', `testpad.h', и `core'.

При выполнении команды `make distclean', помимо файлов, удаляемых в `make clean', make также удалит файлы `TAGS', `Makefile', и `config.status'. (В данном случае, make-файл (и файл `config.status') генерируется пользователем с помощью программы configure, которая входит в дистрибутив tar. Эта программа здесь не показана.)

При выполнении `make realclean', наряду с файлами, удаляемыми по команде `make distclean', make также удаляет Info-файлы, полученные из `tar.texinfo'.

В make-файле также имеются две цели для создания дистрибутивов: shar и dist.

# Сгенерирован автоматически из Makefile.in с помощью configure.
# Un*x make-файл для программы GNU tar.
# Copyright (C) 1991 Free Software Foundation, Inc.

# This program is free software; you can redistribute
# it and/or modify it under the terms of the GNU
# General Public License ...
...
...

SHELL = /bin/sh

#### Начало раздела конфигурации. ####

srcdir = .

# При использовании gcc, вы должны либо запустить скрипт
# fixincludes, поставляемый с этим компилятором, либо использовать
# gcc с опцией -traditional.  Иначе, вызов ioctl
# может быть неправильно скомпилирован в некоторых системах.
CC = gcc -O
YACC = bison -y
INSTALL = /usr/local/bin/install -c
INSTALLDATA = /usr/local/bin/install -c -m 644

#  Опции, которые можно задать для DEFS:
# -DSTDC_HEADERS        Если у вас имеются стандартные ANSI C заголовочные
#                       файлы и библиотеки.
# -DPOSIX               Если у вас имеются стандартные POSIX.1 заголовочные
#                       файлы и библиотеке.
# -DBSD42               Если у вас имеется sys/dir.h (кроме случаев,
#                       когда вы используете -DPOSIX), sys/file.h,
#                       и st_blocks в `struct stat'.
# -DUSG                 Если у имеются System V/ANSI C
#                       функции для работы со строками и памятью,
#                       соответствующие заголовочные файлы, sys/sysmacros.h,
#                       fcntl.h, getcwd, нет valloc 
#                       и есть ndir.h (если вы только не 
#                       используете -DDIRENT).
# -DNO_MEMORY_H         В случаях, когда USG или STDC_HEADERS, но 
#                       не включать файл memory.h.
# -DDIRENT              В случае USG, но вместо ndir.h у вас 
#                       имеется dirent.h.
# -DSIGTYPE=int         Если ваши обработчики сигналов
#                       возвращают int, а не void.
# -DNO_MTIO             Если у вас нет sys/mtio.h
#                       (ioctl для магнитной ленты).
# -DNO_REMOTE           Если у вас нет удаленной оболочки или
#                       rexec.
# -DUSE_REXEC           Использовать rexec для удаленных операций с
#                       лентой вместо запуска
#                       rsh или remsh через fork.
# -DVPRINTF_MISSING     Если ваша система не имеет функции vprintf
#                       (но имеет _doprnt).
# -DDOPRNT_MISSING      Если ваша система не имеет функции _doprnt.
#                       Надо также определить
#                       -DVPRINTF_MISSING.
# -DFTIME_MISSING       Если ваша система не поддерживает системный вызов ftime.
# -DSTRSTR_MISSING      Если ваша система не имеет функции strstr.
# -DVALLOC_MISSING      Если ваша система не имеет функции valloc.
# -DMKDIR_MISSING       Если ваша система не поддерживает системых вызовов mkdir
#                       и rmdir.
# -DRENAME_MISSING      Если ваша система не поддерживает системный вызов rename.
# -DFTRUNCATE_MISSING   Если система не поддерживает системный вызов ftruncate. 
# -DV7                  Для Version 7 Unix (давно не
#                       тестировалось).
# -DEMUL_OPEN3          Если у вас нет версии open с тремя аргументами
#                       и вы хотите, чтобы эта функция эмулировалась  
#                       с помощью имеющихся у вас системных вызовов.
# -DNO_OPEN3            Если у вас нет версии open с тремя аргументами
#                       и вы хотите отключить опцию tar -k  
#                       вместо того, чтобы эмулировать нужную функцию open.
# -DXENIX               Если у вас имеется sys/inode.h
#                       и нужно, чтобы он был 94 для своего подключения.

DEFS =  -DSIGTYPE=int -DDIRENT -DSTRSTR_MISSING \
        -DVPRINTF_MISSING -DBSD42
# Установите для этой переменной значение rtapelib.o или, если вы определили NO_REMOTE,
# установите для нее пустое значение.
RTAPELIB = rtapelib.o
LIBS =
DEF_AR_FILE = /dev/rmt8
DEFBLOCKING = 20

CDEBUG = -g
CFLAGS = $(CDEBUG) -I. -I$(srcdir) $(DEFS) \
        -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" \
        -DDEFBLOCKING=$(DEFBLOCKING)
LDFLAGS = -g

prefix = /usr/local
# Префикс для каждой инсталлируемой программы,
# обычно пустой или содержит `g'.
binprefix =

# Каталог, куда будет инсталлироваться программа tar.
bindir = $(prefix)/bin

# Каталог, куда будут инсталлироваться Info-файлы.
infodir = $(prefix)/info

#### Конец раздела конфигурации. ####

SRC1 =  tar.c create.c extract.c buffer.c \
        getoldopt.c update.c gnu.c mangle.c
SRC2 =  version.c list.c names.c diffarch.c \
        port.c wildmat.c getopt.c
SRC3 =  getopt1.c regex.c getdate.y
SRCS =  $(SRC1) $(SRC2) $(SRC3)
OBJ1 =  tar.o create.o extract.o buffer.o \
        getoldopt.o update.o gnu.o mangle.o
OBJ2 =  version.o list.o names.o diffarch.o \
        port.o wildmat.o getopt.o
OBJ3 =  getopt1.o regex.o getdate.o $(RTAPELIB)
OBJS =  $(OBJ1) $(OBJ2) $(OBJ3)
AUX =   README COPYING ChangeLog Makefile.in  \
        makefile.pc configure configure.in \
        tar.texinfo tar.info* texinfo.tex \
        tar.h port.h open3.h getopt.h regex.h \
        rmt.h rmt.c rtapelib.c alloca.c \
        msd_dir.h msd_dir.c tcexparg.c \
        level-0 level-1 backup-specs testpad.c

all:    tar rmt tar.info

tar:    $(OBJS)
        $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

rmt:    rmt.c
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ rmt.c

tar.info: tar.texinfo
        makeinfo tar.texinfo

install: all
        $(INSTALL) tar $(bindir)/$(binprefix)tar
        -test ! -f rmt || $(INSTALL) rmt /etc/rmt
        $(INSTALLDATA) $(srcdir)/tar.info* $(infodir)

$(OBJS): tar.h port.h testpad.h
regex.o buffer.o tar.o: regex.h
# getdate.y has 8 shift/reduce conflicts.

testpad.h: testpad
        ./testpad

testpad: testpad.o
        $(CC) -o $@ testpad.o

TAGS:   $(SRCS)
        etags $(SRCS)

clean:
        rm -f *.o tar rmt testpad testpad.h core

distclean: clean
        rm -f TAGS Makefile config.status

realclean: distclean
        rm -f tar.info*

shar: $(SRCS) $(AUX)
        shar $(SRCS) $(AUX) | compress \
          > tar-`sed -e '/version_string/!d' \
                     -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
                     -e q
                     version.c`.shar.Z

dist: $(SRCS) $(AUX)
        echo tar-`sed \
             -e '/version_string/!d' \
             -e 's/[^0-9.]*\([0-9.]*\).*/\1/' \
             -e q
             version.c` > .fname
        -rm -rf `cat .fname`
        mkdir `cat .fname`
        ln $(SRCS) $(AUX) `cat .fname`
        tar chZf `cat .fname`.tar.Z `cat .fname`
        -rm -rf `cat .fname` .fname

tar.zoo: $(SRCS) $(AUX)
        -rm -rf tmp.dir
        -mkdir tmp.dir
        -rm tar.zoo
        for X in $(SRCS) $(AUX) ; do \
            echo $$X ; \
            sed 's/$$/^M/' $$X \
            > tmp.dir/$$X ; done
        cd tmp.dir ; zoo aM ../tar.zoo *
        -rm -rf tmp.dir

Индекс

#

  • # (комментарий), в командах
  • # (комментарий), в make-файле
  • #include
  • $

  • $, при вызове функции
  • $, в правилах
  • $, в имени переменной
  • $, в ссылке на переменную
  • %

  • %, в шаблонных правилах
  • %, отмена специального значения символа в статическом шаблоне
  • %, отмена специального значения символа в функции patsubst
  • %, отмена специального значения символа в директиве vpath
  • %, отмена специального значения символа с помощью \, %, отмена специального значения символа с помощью \, %, отмена специального значения символа с помощью \
  • *

  • * (шаблонный символ)
  • +

  • +, и define
  • +=
  • +=, вычисление, +=, вычисление
  • ,

  • ,v (расширение имени RCS-файла)
  • -

  • - (в командах)
  • -, и define
  • --assume-new, --assume-new
  • --assume-new, и рекурсия
  • --assume-old, --assume-old
  • --assume-old, и рекурсия
  • --debug
  • --directory, --directory
  • --directory, и рекурсия
  • --directory, и --print-directory
  • --dry-run, --dry-run, --dry-run
  • --environment-overrides
  • --file, --file, --file
  • --file, и рекурсия
  • --help
  • --ignore-errors, --ignore-errors
  • --include-dir, --include-dir
  • --jobs, --jobs
  • --jobs, и рекурсия
  • --just-print, --just-print, --just-print
  • --keep-going, --keep-going, --keep-going
  • --load-average, --load-average
  • --makefile, --makefile, --makefile
  • --max-load, --max-load
  • --new-file, --new-file
  • --new-file, и рекурсия
  • --no-builtin-rules
  • --no-builtin-variables
  • --no-keep-going
  • --no-print-directory, --no-print-directory
  • --old-file, --old-file
  • --old-file, и рекурсия
  • --print-data-base
  • --print-directory
  • --print-directory, и рекурсия
  • --print-directory, отключение
  • --print-directory, и --directory
  • --question, --question
  • --quiet, --quiet
  • --recon, --recon, --recon
  • --silent, --silent
  • --stop
  • --touch, --touch
  • --touch, и рекурсия
  • --version
  • --warn-undefined-variables
  • --what-if, --what-if
  • -b
  • -C, -C
  • -C, и рекурсия
  • -C, и -w
  • -d
  • -e
  • -e (опция командной оболочки)
  • -f, -f, -f
  • -f, и рекурсия
  • -h
  • -I, -I
  • -i, -i
  • -j, -j
  • -j, и обновление архива
  • -j, и рекурсия
  • -k, -k, -k
  • -l
  • -l (поиск библиотек)
  • -l (средняя загрузка)
  • -m
  • -M (для компилятора)
  • -MM (для компилятора GNU)
  • -n, -n, -n
  • -o, -o
  • -o, и рекурсия
  • -p
  • -q, -q
  • -R
  • -r
  • -S
  • -s, -s
  • -t, -t
  • -t, и рекурсия
  • -v
  • -W, -W
  • -w
  • -W, и рекурсия
  • -w, и рекурсия
  • -w, отключение
  • -w, и -C
  • .

  • .a (архивы)
  • .C
  • .c
  • .cc
  • .ch
  • .d
  • .def
  • .dvi
  • .F
  • .f
  • .info
  • .l
  • .LIBPATTERNS, и подключаемые библиотеки
  • .ln
  • .mod
  • .o, .o
  • .p
  • .PRECIOUS промежуточные файлы
  • .r
  • .S
  • .s
  • .sh
  • .sym
  • .tex
  • .texi
  • .texinfo
  • .txinfo
  • .w
  • .web
  • .y
  • :

  • :: правила (с двойным двоеточием)
  • :=, :=
  • =

  • =, =
  • =, вычисление
  • ?

  • ? (шаблонный символ)
  • ?=, ?=
  • ?=, вычисление
  • @

  • @ (в командах)
  • @, и define
  • [

  • [...] (шаблонные символы)
  • \

  • \, для сцепления строк
  • \, в командах
  • \, для отключения специального значения %, \, для отключения специального значения %, \, для отключения специального значения %
  • _

  • __.SYMDEF
  • a

  • algorithm for directory search (алгоритм поиска в каталогах)
  • all (стандартная цель)
  • appending to variables (добавление значения к переменной)
  • ar
  • archive (архив)
  • archive member targets (элемент архива)
  • archive symbol directory updating (обновление каталога символов архивного файла)
  • archive (архив), и -j
  • archive (архив), и параллельное выполнение
  • archive (архив), суффиксное правило для архивов
  • Arg list too long (список аргументов слишком велик)
  • arguments of functions (аргументы функций)
  • as, as
  • assembly (ассемблирование), правило для запуска ассемблера
  • automatic generation of prerequisites (автоматическая генерация пререквизитов), automatic generation of prerequisites (автоматическая генерация пререквизитов)
  • automatic variables (автоматические переменные)
  • b

  • backquotes
  • backslash (\), для сцепления строк
  • backslash (\), в командах
  • backslash (\), для отмены специального значения %, backslash (\), для отмены специального значения %, backslash (\), для отмены специального значения %
  • backslashes in pathnames and wildcard expansion (символы \ в именах файлов и расширение шаблонных символов)
  • basename (базовое имя)
  • binary packages (бинарный пакет)
  • broken pipe (нарушение канала обмена)
  • bugs (ошибки), сообщение о
  • built-in special targets (встроенные специальные цели)
  • c

  • C++, правило для компиляции
  • C, правило для компиляции
  • cc, cc
  • cd (команда оболочки), cd (команда оболочки)
  • chains of rules (цепочки правил)
  • check (стандартная цель)
  • clean (стандартная цель)
  • clean цель, clean цель
  • cleaning up (очистка)
  • clobber (стандартная цель)
  • co, co
  • combining rules by dependency (комбинирование правил по их пререквизитам)
  • command line variable definitions, and recursion (определение переменных с помощью командной строки и рекурсия)
  • command line variables (переменные, определенные в командной строке)
  • commands (команды)
  • commands (команды), символ \ в командах
  • commands (команды), комментарии в командах
  • commands (команды), отображение
  • commands (команды), пустые
  • commands (команды), ошибки в командах
  • commands (команды), исполнение
  • commands (команды), параллельное исполнение
  • commands (команды), расширение
  • commands (команды), написание
  • commands (команды), вместо исполнения
  • commands (команды), введение в
  • commands (команды), разбиение на строки
  • commands (команды), последовательности
  • comments (комментарии), в командах
  • comments (комментарии), в make-файле
  • compatibility (совместимость)
  • compatibility in exporting (совместимость при экспортировании переменных)
  • compilation (компиляция), проверка компиляции
  • computed variable name (вычисляемые имена переменных)
  • conditional expansion (условное вычисление)
  • conditional variable assignment (условное присваивание переменной)
  • conditionals (условные конструкции)
  • continuation lines (сцепление строк)
  • controlling make (управление работой make)
  • conventions for makefiles (соглашения для make-файлов)
  • ctangle, ctangle
  • cweave, cweave
  • d

  • data base of make rules (база данных правил)
  • deducing commands (сокращение команд с помощью неявных правил)
  • default directries for included makefiles (поиск включаемых файлов в каталогах)
  • default goal (главная цель по умолчанию), default goal (главная цель по умолчанию)
  • default makefile name (имя make-файла по умолчанию)
  • default rules (правила по умолчанию), правила "последнего шанса"
  • define, вычисление
  • defining variables verbatim (определение многострочной переменной)
  • deletion of target files (удаление целевых файлов), deletion of target files (удаление целевых файлов)
  • directive (директива)
  • directories (каталоги), печать каталогов
  • directories (каталоги), обновление каталога символов архива
  • directory part (каталог - часть имени файла)
  • directory search (VPATH) (поиск в каталогах)
  • directory search (VPATH) (поиск в каталогах), и неявные правила
  • directory search (VPATH) (поиск в каталогах), и библиотеки
  • directory search (VPATH) (поиск в каталогах), и команды оболочки
  • directory search algorithm (алгоритм поиска по каталогам)
  • directory search (поиск в каталогах), традиционный
  • dist (стандартная цель)
  • distclean (стандартная цель)
  • dollar sign ($) (символ доллара), в вызове функции
  • dollar sign ($) (символ доллара), в правилах
  • dollar sign ($) (символ доллара), в имени переменной
  • dollar sign ($) (символ доллара), в ссылке на переменную
  • double-colon rules (правила с двойным двоеточием)
  • duplicate words (дублирующиеся слова), удаление
  • e

  • E2BIG
  • echoing of commands (отображение команд)
  • editor (редактор)
  • Emacs (M-x компиляция)
  • empty commands (пустые команды)
  • empty targets (пустые цели)
  • environment (операционное окружение)
  • environment (операционное окружение), и рекурсия
  • environment (операционное окружение), переменная SHELL в операционном окружении
  • error (ошибка), остановка при возникновении ошибки
  • errors (ошибки, в командах)
  • errors with wildcards (ошибки при использовании шаблонов)
  • execution (выполнение), параллельное
  • execution (исполнение), вместо исполнения
  • execution (исполнение), команд
  • exit status (код возврата)
  • explicit rule (явное правило), определение
  • explicit rule (явное правило), обработка
  • exporting variables (экспортирование переменных)
  • f

  • f77, f77
  • features of GNU make (возможности GNU make)
  • features (возможности), не реализованные
  • file name functions (функции для работы с именами файлов)
  • file name of makefile (имя make-файла)
  • file name of makefile (имя make-файла), как указать
  • file name prefix (префикс имени файла), добавление
  • file name suffix (суффикс имени файла)
  • file name suffix (суффикс имени файла), добавление
  • file name with wildcards (имя файла с шаблонными символами)
  • file name (имя файла), основа имени файла
  • file name (имя файла), часть имени файла - имя каталога
  • file name (имя файла), часть имени файла кроме имени каталога
  • files (файлы), предполагать "новыми"
  • files (файлы), предполагать "старыми"
  • files (файлы), избежание перекомпиляции
  • files (файлы), промежуточные
  • filtering out words (отфильтровывание слов)
  • filtering words (фильтрация слов)
  • finding strings (нахождение строк)
  • flags (опции)
  • flags for compilers (опции компилятора)
  • flavors of variables (разновидности переменных)
  • FORCE
  • force targets (принудительное обновление целей)
  • Fortran (Фортран), правило для компиляции
  • functions (функции)
  • functions, for controlling make functions (функции), управляющие процессом сборки
  • functions (функции), для манипуляций с именами файлов
  • functions (функции), для манипуляции с текстом
  • functions (функции), синтаксис
  • functions (функции), определенные пользователем
  • g

  • g++, g++
  • gcc
  • generating prerequisites automatically (автоматическая генерация пререквизитов), generating prerequisites automatically (автоматическая генерация пререквизитов)
  • get, get
  • globbing (шаблоны)
  • goal (главная цель)
  • goal (главная цель), по умолчанию, goal (главная цель), по умолчанию
  • goal (главная цель), задание
  • h

  • home directory (домашний каталог)
  • i

  • IEEE Standard 1003.2
  • ifdef, обработка
  • ifeq, обработка
  • ifndef, обработка
  • ifneq, обработка
  • implicit rule (неявное правило)
  • implicit rule (неявное правило), и поиск по каталогам
  • implicit rule (неявное правило), и VPATH
  • implicit rule (неявное правило), определение
  • implicit rule (неявное правило), обработка
  • implicit rule (неявное правило), использование
  • implicit rule (неявное правило), введение
  • implicit rule (неявное правило), предопределенное
  • implicit rule (неявное правило), алгоритм поиска
  • included makefiles (подключаемые make-файлы), каталоги по умолчанию
  • including (включение других файлов и переменная MAKEFILES)
  • including other makefiles (включение других make-файлов)
  • incompatibilities (несовместимости)
  • Info, правило для форматирования
  • install (стандартная цель)
  • intermediate files (промежуточные файлы)
  • intermediate files (промежуточные файлы), сохранение
  • intermediate targets (промежуточные цели), явные
  • interrupt (прерывание)
  • j

  • job slots (слоты заданий)
  • job slots (слоты заданий), и рекурсия
  • jobs (задание), ограничения количества в зависимости от загрузки
  • joining lists of words (объединение списков слов)
  • k

  • killing (принудительное завершение)
  • l

  • last-resort default rules (используемые по умолчанию правила "последнего шанса")
  • ld
  • lex, lex
  • Lex, правило для запуска
  • libraries for linking (библиотеки для компоновки), поиск в каталогах
  • library archive (библиотечный архив), суффиксное правило для
  • limiting jobs based on load (ограничения числа заданий в зависимости от загрузки)
  • link libraries (компонуемые библиотеки), и поиск в каталогах
  • link libraries (компонуемые библиотеки), соответствие шаблону
  • linking (компоновка), предопределенное правило для компоновки
  • lint
  • lint, правило для запуска
  • list of all prerequisites (список всех пререквизитов)
  • list of changed prerequisites (список модефицированных пререквизитов)
  • load average (средняя загрузка)
  • loops in variable expansion (зацикливание при вычислении переменной)
  • lpr (команда оболочки), lpr (команда оболочки)
  • m

  • m2c
  • macro
  • make depend
  • MAKECMDGOALS
  • makefile (make-файл)
  • makefile name (имя make-файла)
  • makefile name (имя make-файла), задание
  • makefile rule parts (правила make-файла)
  • makefile (make-файл), и переменная MAKEFILES
  • makefile (make-файл), принятые соглашения
  • makefile (make-файл), обработка
  • makefile (make-файл), написание
  • makefile (make-файл), включение
  • makefile (make-файл), "перекрытие"
  • makefile (make-файл), интерпретация
  • makefile (make-файл), обновление
  • makefile (make-файл), простой
  • makeinfo, makeinfo
  • match-anything rule (правило с произвольным соответствием)
  • match-anything rule (правило с произвольным соответствием), используемое для "перекрытия"
  • missing features (отсутствующая возможность)
  • mistakes with wildcards (ошибки при использовании шаблонов)
  • modified variable reference (модефицированные варианты ссылки на переменную)
  • Modula-2, правило для компиляции
  • mostlyclean (стандартная цель)
  • multiple rules for one target (несколько правил с одной целью)
  • multiple rules (::) for one target (несколько правил с двойным двоеточием для одной цели)
  • multiple targets (несколько целей)
  • multiple targets (несколько целей), в шаблонном правиле
  • n

  • name of makefile (имя make-файла)
  • name of makefile (имя make-файла), как указать
  • nested variable reference (вложенная ссылка на переменную)
  • newline (перевод строки), "подавление", в командах
  • newline (перевод строки), "подавление" в make-файле
  • nondirectory part (часть имени файла кроме имени каталога)
  • o

  • OBJ
  • obj
  • OBJECTS
  • objects
  • OBJS
  • objs
  • old-fashioned suffix rules (устаревшие суффиксные правила)
  • options (опции)
  • options (опции), и рекурсия
  • options (опции), установка из операционной среды
  • options (опции), установка в make-файле
  • order of pattern rules (порядок следования шаблонных правил)
  • origin of variable ("происхождение" переменной)
  • overriding makefiles ("перекрытие" make-файла)
  • overriding variables with arguments ("перекрытие" переменных с помощью аргументов командной строки)
  • overriding with override ("перекрытие" с помощью override)
  • p

  • parallel execution (параллельное выполнение)
  • parallel execution (параллельное выполнение), и обновление архивов
  • parallel execution (параллельное выполнение), перекрытие
  • parts of makefile rule (часть make-файла - правила)
  • Pascal (Паскаль), правило для компиляции
  • pattern rule (шаблонное правило)
  • pattern rule (шаблонные правила), обработка
  • pattern rules (шаблонные правила), порядок следования
  • pattern rules (шаблонные правила), статические
  • pattern rules (шаблонные правила), статические, синтаксис
  • pattern-specific variables (шаблонно-зависимые значения переменных)
  • pc, pc
  • phony targets (абстрактные цели)
  • pitfalls of wildcards (проблемы при использовании шаблонов)
  • portability (переносимость)
  • POSIX
  • POSIX.2
  • post-installation commands (команды пост-инсталляции)
  • pre-installation commands (команды пред-инсталляции)
  • precious (сохраняемые) цели
  • predefined rules and variables (предопределенные правила и переменные), печать
  • prefix (префикс), добавление
  • prerequisite (пререквизит)
  • prerequisite pattern (шаблон пререквизита), неявный
  • prerequisite pattern (шаблон пререквизита), статический
  • prerequisite (пререквизит), обработка
  • prerequisites (пререквизиты)
  • prerequisites (пререквизиты), автоматическая генерация, prerequisites (пререквизиты), автоматическая генерация
  • prerequisites (пререквизиты), введение
  • prerequisites (пререквизиты), список всех
  • prerequisites (пререквизиты), список измененных
  • prerequisites (пререквизиты), варьирование в статических шаблонах
  • preserving intermediate files (сохранение промежуточных файлов)
  • preserving (сохранение) с помощью .PRECIOUS, preserving (сохранение) с помощью .PRECIOUS
  • preserving (сохранение) с помощью .SECONDARY
  • print (стандартная цель)
  • print, цель , print, цель
  • printing directories (печать каталогов)
  • printing of commands (печать команд)
  • printing user warnings (вывод "пользовательских" предупреждений)
  • problems and bugs (проблемы и ошибки), сообщение
  • problems with wildcards (проблемы при использовании шаблонов)
  • processing a makefile (обработка make-файла)
  • q

  • question mode (режим проверки)
  • quoting (отключение специального значения) %, в статических шаблонах
  • quoting (отключение специального значения) %, в patsubst
  • quoting (отключение специального значения) %, в vpath
  • quoting ("отключение" перевода строки), в командах
  • quoting ("отключение" перевода строки), в make-файле
  • r

  • Ratfor (Ратфор), правило для компиляции
  • RCS, правило для извлечения
  • reading makefiles (чтение make-файла)
  • README
  • realclean (стандартная цель)
  • recompilation (перекомпиляция)
  • recompilation (перекомпиляция), избежание
  • recording events with empty targets (фиксация событий с помощью пустых целей)
  • recursion (рекурсия)
  • recursion (рекурсия), и -C
  • recursion (рекурсия), и -f
  • recursion (рекурсия), и -j
  • recursion (рекурсия), и -o
  • recursion (рекурсия), и -t
  • recursion (рекурсия), и -W
  • recursion (рекурсия), и -w
  • recursion (рекурсия), и определения переменных, заданные в командной строке
  • recursion (рекурсия), и операционная среда
  • recursion (рекурсия), и переменная MAKE
  • recursion (рекурсия), и переменная MAKEFILES
  • recursion (рекурсия), и опции
  • recursion (рекурсия), и печать каталогов
  • recursion (рекурсия), и переменные
  • recursion (рекурсия), уровень "вложенности"
  • recursive variable expansion (рекурсивное вычисление переменной), recursive variable expansion (рекурсивное вычисление переменной)
  • recursively expanded variables (рекурсивно вычисляемая переменная)
  • reference to variables (ссылка на переменную), reference to variables (ссылка на переменную)
  • relinking (перекомпоновка)
  • remaking makefiles (обновление make-файлов)
  • removal of target files (удаление целевых файлов), removal of target files (удаление целевых файлов)
  • removing duplicate words (удаление дубликатов слов)
  • removing targets on failure (удаление целей при возникновении ошибки)
  • removing (удаление), для очистки
  • reporting bugs (сообщение об ошибках)
  • rm
  • rm (команда оболочки), rm (команда оболочки), rm (команда оболочки), rm (команда оболочки)
  • rule commands (команды правила)
  • rule prerequisites (пререквизиты правила)
  • rule syntax (синтаксис правила)
  • rule targets (цели правила)
  • rule (правила), и $
  • rule (правило), с двойным двоеточием (::)
  • rule (правило), явное, задание
  • rule (правило), написание
  • rule (правило), неявное
  • rule (правило), неявное, и поиск в каталогах
  • rule (правило), неявное, и VPATH
  • rule (правила), неявные, цепочки
  • rule (правило), неявное, задание
  • rule (правила), неявные, использование
  • rule (правила), неявные, введение в
  • rule (правило), неявное, предопределенное
  • rule (правила), введение в
  • rule (правила), несколько правил с одной целью
  • rule (правило), без команд и пререквизитов
  • rule (правило), шаблонное
  • rule (правила), статическое шаблонное
  • rule (правила), сравнение статических шаблонных правил и неявных правил
  • rule (правило), с несколькими целями
  • s

  • s. (префикс файлов SCCS)
  • SCCS, правило для извлечения
  • search algorithm (алгоритм поиска), неявных правил
  • search path for prerequisites (путь поиска для пререквизитов - VPATH)
  • search path for prerequisites (путь поиска для пререквизитов - VPATH), и неявные правила
  • search path for prerequisites (путь поиска для пререквизитов - VPATH), и подключаемые библиотеки
  • searching for strings (поиск строк)
  • secondary files (вторичные файлы)
  • secondary targets (вторичные цели)
  • sed (команда оболочки)
  • selecting a word (выборка слова)
  • selecting word lists (выборка списка слов)
  • sequences of commands (последовательность команд)
  • setting options from environment (установка опций из операционной среды)
  • setting options in makefiles (установка опций в make-файле)
  • setting variables (установка переменных)
  • several rules for one target (несколько правил для одной цели)
  • several targets in a rule (несколько целей в правиле)
  • shar (стандартная цель)
  • shell command (команда оболочки)
  • shell command (команды оболочки), и поиск в каталогах
  • shell command (команда оболочки), выполнение
  • shell command (команда оболочки), функция для вызова команд оболочки
  • shell file name pattern (шаблоны имен файлов в include)
  • shell wildcards (шаблоны в include)
  • SHELL, MS-DOS специфика
  • signal (сигнал)
  • silent operation (отключение отображения)
  • simple makefile (простой make-файл)
  • simple variable expansion (простое расширение переменной)
  • simplifying with variables (упрощение с помощью переменных)
  • simply expanded variables (упрощенно вычисляемые переменные)
  • sorting words (сортировка слов)
  • spaces (пробелы), в значении переменной
  • spaces (пробелы), удаление
  • special targets (специальные цели)
  • specifying makefile name (задание имени make-файла)
  • standard input (стандартный ввод)
  • standards conformance (соответствие стандартам)
  • standards for makefiles (стандарты для make-файлов)
  • static pattern rule (статическое шаблонное правило)
  • static pattern rule (статическое шаблонное правило), синтаксис
  • static pattern rule (статическое шаблонное правило), сравнение с неявными правилами
  • stem (основа имени), stem (основа имени)
  • stem (основа имени), переменная для основы имени
  • stopping make (остановка сборки)
  • strings (строки), поиск
  • stripping whitespace (удаление пробелов)
  • sub-make (make "нижнего" уровня при рекурсивном вызове
  • subdirectories (подкаталоги), рекурсия
  • substitution variable reference (ссылка на переменную с заменой)
  • suffix rule (суффиксное правило)
  • suffix rule (суффиксное правило), для архивов
  • suffix (суффикс), добавление
  • suffix (суффикс), функция для поиска
  • suffix (суффикс), подстановка в переменных
  • switches (опции)
  • symbol directories (каталог символов), обновление в архивах
  • syntax of rules (синтаксис правил)
  • t

  • tab character (символ табуляции в командах)
  • tabs in rules (символы табуляции в правилах)
  • TAGS (стандартная цель)
  • tangle, tangle
  • tar (стандартная цель)
  • target (цель)
  • target pattern (шаблон цели), в неявных правилах
  • target pattern, static (not implicit) target pattern (шаблон цели), в статическом правиле
  • target (цель), удаление при возникновении ошибок
  • target (цель), удаление при прерывании работы
  • target (цель), обработка
  • target (цель), несколько целей в шаблонном правиле
  • target (цель), несколько правил для одной цели
  • target (цель), обновление времени модефикации (touching)
  • target-specific variables (целе-зависимые переменные)
  • targets (цели)
  • targets without a file (цели, не ссылающиеся на файлы)
  • targets (цели), специальные встроенные
  • targets (цели), пустые
  • targets (цели), принудительное обновление
  • targets (цели), введение в
  • targets (цели), несколько
  • targets (цели), абстрактная (phony)
  • terminal rule (терминальное правило)
  • test (стандартная цель)
  • testing compilation (проверка компиляции)
  • tex, tex
  • TeX, правило для запуска
  • texi2dvi, texi2dvi
  • Texinfo, правило для форматирования
  • tilde (~)
  • touch (команда оболочки), touch (команда оболочки)
  • touching files (обновление времени модефикации файлов)
  • traditional directory search (традиционная схема поиска в каталогах)
  • u

  • undefined variables (неопределенные переменные), предупреждающее сообщение
  • updating archive symbol directories (обновление каталога символов архивного файла)
  • updating makefiles (обновление make-файлов)
  • user defined functions (определенная пользователем функция)
  • v

  • value (значение)
  • value (значение), как переменные получают значения
  • variable (переменная)
  • variable definition (определение переменной)
  • variables (переменные)
  • variables (переменные), символ `$' в именах
  • variables (переменные), и неявные правила
  • variables (переменные), добавление значения
  • variables (переменные), автоматические
  • variables (переменные), заданные в командной строке
  • variables (переменные), заданные в командной строке, и рекурсия
  • variables (переменные), вычисляемые имена
  • variables (переменные), условное присваивание
  • variables (переменные), определение многострочных переменных
  • variables (переменные), из операционной среды, variables (переменные), из операционной среды
  • variables (переменные), экспорт
  • variables (переменные), разновидности
  • variables (переменные), как переменные получают значения
  • variables (переменные), как сослаться на переменную
  • variables (переменные), зацикливание при вычислении
  • variables (переменные), модефицированные варианты ссылки
  • variables (переменные), вложенные ссылки
  • variables (переменные), "происхождение"
  • variables (переменные), "перекрытие"
  • variables (переменные), "перекрытие" с помощью аргументов командной строки
  • variables (переменные), шаблонно-зависимые
  • variables (переменные), рекурсивно вычисляемые
  • variables (переменные), установка
  • variables (переменные), упрощенно вычисляемые
  • variables (переменные), пробелы внутри значения
  • variables (переменные), подстановка суффикса
  • variables (переменные), ссылка с подстановкой
  • variables (переменные), целе-зависимые
  • variables (переменные), предупреждение для неопределенных
  • varying prerequisites (вариация пререквизитов)
  • verbatim variable definition (определения многострочных переменных)
  • vpath
  • VPATH, и неявные правила
  • VPATH, и компоновка библиотек
  • w

  • warnings (предупреждения), вывод
  • weave, weave
  • Web, правило для запуска
  • what if (что, если)
  • whitespace (пробелы), в значениях переменной
  • whitespace (пробелы), удаление
  • wildcard (шаблонный символ)
  • wildcard pitfalls (проблемы при использовании шаблонов)
  • wildcard, функция
  • wildcard (щаблонные символы), в элементах архива
  • wildcard (щаблонные символы), в include
  • wildcards and MS-DOS/MS-Windows backslashes (шаблоны и символы '\' в MS-DOS/MS-Windows
  • word (слово), выборка
  • words (слова), выборка начальных
  • words (слова), фильтрация
  • words (слова), отфильтровывание
  • words (слова), определение количества
  • words (слова), итерация по списку
  • words (слова), объединение списков
  • words (слова), удаление дубликатов
  • words (слова), выборка списка
  • writing rule commands (написание команд правила)
  • writing rules (составление правил)
  • y

  • yacc
  • yacc, yacc
  • Yacc, правило для запуска
  • ~

  • ~ (тильда)
  • Индекс: функции, переменные и директивы

    $

  • $%
  • $(%D)
  • $(%F)
  • $(*D)
  • $(*F)
  • $(<D)
  • $(<F)
  • $(?D)
  • $(?F)
  • $(@D)
  • $(@F)
  • $(^D)
  • $(^F)
  • $*
  • $*, и статические шаблоны
  • $+
  • $<
  • $?
  • $@
  • $^
  • %

  • % (автоматическая переменная)
  • %D (автоматическая переменная)
  • %F (автоматическая переменная)
  • *

  • * (автоматическая переменная)
  • * (автоматическая переменная), "странный", неподдерживаемый способ использования
  • *D (автоматическая переменная)
  • *F (автоматическая переменная)
  • +

  • + (автоматическая переменная)
  • .

  • .DEFAULT, .DEFAULT
  • .DEFAULT, и пустые команды
  • .DELETE_ON_ERROR, .DELETE_ON_ERROR
  • .EXPORT_ALL_VARIABLES, .EXPORT_ALL_VARIABLES
  • .IGNORE, .IGNORE
  • .INTERMEDIATE
  • .LIBPATTERNS
  • .NOTPARALLEL
  • .PHONY, .PHONY
  • .POSIX
  • .PRECIOUS, .PRECIOUS
  • .SECONDARY
  • .SILENT, .SILENT
  • .SUFFIXES, .SUFFIXES
  • /

  • /usr/gnu/include
  • /usr/include
  • /usr/local/include
  • <

  • < (автоматическая переменная)
  • <D (автоматическая переменная)
  • <F (автоматическая переменная)
  • ?

  • ? (автоматическая переменная)
  • ?D (автоматическая переменная)
  • ?F (автоматическая переменная)
  • @

  • @ (автоматическая переменная)
  • @D (автоматическая переменная)
  • @F (автоматическая переменная)
  • ^

  • ^ (автоматическая переменная)
  • ^D (автоматическая переменная)
  • ^F (автоматическая переменная)
  • a

  • addprefix
  • addsuffix
  • AR
  • ARFLAGS
  • AS
  • ASFLAGS
  • b

  • basename
  • c

  • call
  • CC
  • CFLAGS
  • CO
  • COFLAGS
  • COMSPEC
  • CPP
  • CPPFLAGS
  • CTANGLE
  • CWEAVE
  • CXX
  • CXXFLAGS
  • d

  • define
  • dir
  • e

  • else
  • endef
  • endif
  • error
  • export
  • f

  • FC
  • FFLAGS
  • filter
  • filter-out
  • findstring
  • firstword
  • foreach
  • g

  • GET
  • GFLAGS
  • GNUmakefile
  • GPATH
  • i

  • if
  • ifdef
  • ifeq
  • ifndef
  • ifneq
  • include
  • j

  • join
  • l

  • LDFLAGS
  • LEX
  • LFLAGS
  • m

  • MAKE, MAKE
  • MAKECMDGOALS
  • Makefile
  • makefile
  • MAKEFILES, MAKEFILES
  • MAKEFLAGS
  • MAKEINFO
  • MAKELEVEL, MAKELEVEL
  • MAKEOVERRIDES
  • MFLAGS
  • n

  • notdir
  • o

  • origin
  • OUTPUT_OPTION
  • override
  • p

  • patsubst, patsubst
  • PC
  • PFLAGS
  • r

  • RFLAGS
  • RM
  • s

  • shell
  • SHELL
  • SHELL (исполнение команд)
  • sort
  • strip
  • subst, subst
  • suffix
  • SUFFIXES
  • t

  • TANGLE
  • TEX
  • TEXI2DVI
  • u

  • unexport
  • v

  • VPATH, VPATH
  • vpath, vpath
  • w

  • warning
  • WEAVE
  • wildcard, wildcard
  • word
  • wordlist
  • words
  • y

  • YACC
  • YACCR
  • YFLAGS

  • Примечания

    (1)

    Программа GNU Make, скомпилированная для работы в системах MS-DOS и MS-Windows, ведет себя так, как если бы prefix являлся корневым каталогом компилятора DJGPP.

    (2)

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

    (3)

    Для выполнения "реальной" работы по форматированию, программа texi2dvi использует TeX. TeX не входит в состав дистрибутива Texinfo.


    This document was generated on 19 July 2000 using the texi2html