Информация, указывающая программе make, как перекомпилировать систему, получается из специального make-файла.
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'.
Директива 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 <имя файла> ...
Эта директива действует так, что от нее не будет сообщений об
ошибке (даже предупреждений, если любой из указанных файлов не
существует).
Если определена переменная окружения 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-файлов])
Иногда 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'.
Иногда полезно иметь 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' и был бы создан цикл зависимости.