Очень часто используются определенные стандартные способы порождения заново целевых файлов. Например, одним из типичных способов порождения объектного файла является порождение его из исходного 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 [Устаревшие суффиксные правила].
Чтобы дать возможность программе 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 [Определение пустых команд]).
Вот перечень предопределенных неявных правил, которые всегда доступны, если 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 [Устаревшие суффиксные правила], где где во всех деталях описаны суффиксные правила.
'n.o' автоматически порождается из 'n.c' при помощи команды в форме '$(CC) -c $(CPPFLAGS) $(CFLAGS)'.
'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)'.
'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'-файла в качестве промежуточного, но быстрее сделать компиляцию и компоновку за один шаг, поэтому именно так и делается.
'n.c' автоматически порождается из 'n.y' путем запуска программы Yacc при помощи команды '$(YACC) $(YFLAGS)'.
'n.c' автоматически порождается из 'n.l' путем запуска программы Lex. При этом используется такая команда: '$(LEX) $(LFLAGS)'.
'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 ...
'n.ln' порождается из 'n.c' путем запуска программы lint. Точный вид команды такой : '$(LINT) $(LINTFLAGS) $(CPPFLAGS) -i'. Такая же команда используется для работы с C-кодом, полученным из 'n.y' или 'n.l'.
'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)'.
'n.dvi' порождается из 'n.texinfo', 'n.texi' или 'n.txinfo' при помощи команды '$(TEXI2DVI) $(TEXI2DVI_FLAGS)'. 'n.info' порождается из 'n.texinfo', 'n.texi' или 'n.txinfo' при помощи команды '$(MAKEINFO) $(MAKEINFO_FLAGS)'.
Любой файл 'n' извлекается, если это необходимо, из RCS-файла с именем либо 'n,v' or 'RCS/n,v'. Точный вид используемой команды такой: '$(CO) $(COFLAGS)'. Если файл 'n' уже существует, то он не будет извлекаться из RCS-файла, даже если RCS-файл является более новым. Правила для RCS-файлов являются терминальными (смотрите раздел 10.5.5 [Шаблонные правила с произвольным соответствием]), поэтому RCS-файлы не могут быть сгенерированы из какого-нибудь еще источника - они должны реально существовать.
Любой файл '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 $@ '.
Команды во встроенных неявных правилах обильно используют некоторое переменные с предопределенными значениями. Вы можете изменять эти переменные в make-файле, при помощи аргументов программы make или же в командной среде для то, чтобы изменить работу неявных правил, не переопределяя самих правил.
Например, команда, используемая для компиляции исходного C-файла в действительности выглядит так: '$(CC) -c $(CFLAGS) $(CPPFLAGS)'. По умолчанию значение перененной CC является 'cc', значениями остальных используемых здесь переменных является пустое значение, в результате чего получается команда 'cc -c'. С помощью переопределения переменной CC в значение 'ncc' вы могли бы сделать так, чтобы для всех C-компиляций, выполняемых в результате работы неявных правил, мспользовался компилятор 'ncc'. С помощью переопределения переменной CFLAGS в значение '-g', вы могли бы передать в каждом сеансе компиляции опцию '-g'. Все неявные правила, выполняющие C-компиляцию, используют ссылку на переменную '$(CC)' для определения имени программы- компилятора, и все они среди аргументов , передаваемых компилятору, содержат ссылку на переменную '$(CFLAGS)'.
Переменные, используемые в неявных правилах, разделяются на два класса: переменные, являющиеся именами программ (такие, как CC) и переменные, содержащие аргументы для программы (такие, как CFLAGS). ("Имя программы" может также содержать некоторые аргументы командной строки, но оно должно начинаться с имени реальной исполняемой программы.) Если значение переменной содержит более, чем один аргумент, разделяйте их при помощи пробелов.
Вот список переменных, используемых в качестве имен программ во встроенных правилах:
Поддерживающая архивы программа, по умолчанию 'ar'.
Программа для выполнения ассемблирования, по умолчанию 'as'.
Программа для компиляции C-программ, по умолчанию 'cc'.
Программа для компиляции программ на языке C++, по умолчанию 'g++'.
Программа для извлечения файлов из RCS, по умолчанию 'co'.
Программа для запуска C-препроцессора, с выдачей результатов на стандартный выход, по умолчанию '$(CC) -E'.
Программа для компиляции или обработки препроцессором программ на языке Фортран или Ратфор, по умолчанию 'f77'.
Программа для извлечения файлов из SCCS, по умолчанию 'get'.
Программа, используемая для преобразования Lex-грамматик в программы на языке C или Ратфор, по умолчанию 'lex'.
Программа для компиляции программ на языке Паскаль, по умолчанию 'pc'.
Программа, используемая для преобразования Yacc-грамматик в C-программы, по умолчанию 'yacc'.
Программа, используемая для преобразования Yacc-грамматик в программы на языке Ратфор, по умолчанию 'yacc -r'.
Программа для проеобразования исходного Texinfo-файла в Info-файл, по умолчанию 'makeinfo'.
Программа для создания dvi-файлов из исходных Тех-файлов, по умолчанию 'tex'.
Программа для создания dvi-файлов из исходных Texinfo-файлов, по умолчанию 'texi2dvi'.
Программа для перевода из Web-формата в TeX-формат, по умолчанию 'weave'.
Программа для перевода из C-Web-формата в TeX-формат, по умолчанию 'cweave'.
Программа для перевода из Web-формата в программу на языке Паскаль, по умолчанию 'tangle'.
Программа для перевода из Web-формата в C-программу, по умолчанию 'tangle'.
Команда для удаления файла, по умолчанию 'rm -f'.
Вот список переменных, значения которых являются дополнительными аргументами для приведенных выше программ. По умолчанию значениями всех из них является пустая строка, если не указано другого.
Опции, передаваемые поддердивающей архивы программе, по умолчанию 'rv'.
Дополнительные опции, передаваемые ассемблеру ( когда он явно вызывается для файла, имя которого оканчивается на '.s' или '.S').
Дополнительные опции, передаваемые C-компилятору.
Дополнительные опции, передаваемые компилятору с языка C++.
Дополнительные опции, передаваемые программе co, входящей в систему RCS.
Дополнительные опции, передаваемые C-препроцессору и программам, которые его используют (компиляторам с языков C и Фортран).
Дополниттельные опции, передаваемые компилятору с языка Фортран.
Дополнительные опции, передаваемые программе get, входящей в систему SCCS.
Дополнительные параметры, передаваемые компиляторам, когда преполагается вызов из них компоновщика, 'ld'.
Дополнительные опции, передаваемые программе Lex.
Дополнительные опции, передаваемые компилятору с языка Паскаль.
Дополнительные опции, передаваемые компилятору с языка Фортран для использования с программами на языке Ратфор.
Дополнительные опции, передаваемые программе Yacc.
Иногда файл может быть порожден с помощью последовательности неявных правил. Например, файл '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. Использование оптимизированного правила дает преимущество перед использованием пошаговой цепочки поскольку нем ускоряется выполнение правил.
Вы определяете неявное правило с помощью записи шаблонного правила. Шаблонное правило похоже на обычное правило, за исключением того, что его цель содержит символ '%' (ровно один). Цель рассматривается как шаблон для сопоставления с ним имен файлов - символу '%' может соответствовать любая непустая подстрока, в то время как любому другому символу соответствует только он сам. Зависимости также используют символ '%', чтобы показать как их имена соотносятся с именем цели.
Таким образом, шаблонное правило '%.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 , опускается. Ниже приводится список
вариантов:
Часть имени файла цели, определяющая каталог, с удаленным конечным символом '/'. Если значением переменной '$@' является 'dir/foo.o', то значением переменной '$(@D)' является 'dir'. Этим значением является '.', если значение переменной '$@' не содержит символа '/'.
Часть имени файла цели, определяющая файл внутри каталога. Если значением переменной '$@' является 'dir/foo.o', то значением переменной '$(@F)' является 'foo.c'. Переменная '$(@F)' эквивалентна вызову функции '$(@)'.
Часть основы, определяющая, соответственно, каталог и файл внутри каталога - 'dir' и 'foo' в этом примере.
Часть имени целевого элемента архива, определяющая, соответственно, каталог и файл внутри каталога. Это имеет смысл только для целей, являющихся элементами архива, и имеющих форму 'АРХИВ(ЭЛЕМЕНТ)', и полезно только когда ЭЛЕМЕНТ может содержать имя каталога. (Смотрите раздел 11.1 [Элементы архива в качестве целей].)
Часть имени первой зависимости, определяющая, соответственно, каталог и файл внутри каталога.
Списки частей имен всех зависимостей, определяющих, соответственно, каталоги и файлы внутри каталогов.
Списки частей имен всех зависимостей, которые являются более новыми, чем цель, определяющих, соответственно, каталоги и файлы внутри каталогов.
Шаблон цели состоит из символа '%', заключенного между префиксом и суффиксом, один из которых или оба сразу могут быть пустыми. Имя файла сопоставимо с шаблоном только в том случае, если оно начинается с указанного префикса и заканчивается указанным суффиксом, без перекрытия. Фрагмент текста, расположенный между префиксом и суффиксом, называется основой. Таким образом, если образцу '%.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.5.5 [Шаблонные правила с произвольным соответствием]). Оно во всем аналогично любому другому шаблонному правилу, единственное, что специфично для него - это то, что с ним будет сопоставляться любая цель. Таким образом, команды такого правила используются для всех целей и зависимостей, которые не имеют своих собственных команд и к которым неприменимо ни одно другое неявное правило.
Например, при тестировании make-файла, вы могли бы заботиться не о том, содержат ли исходные файлы реальные данные, а только о том, что они существуют. В таком случае вы могли бы сделать следующее:
%::
touch $@
что привело бы к тому, что все требуемые (как зависимости) файлы были
созданы автоматически.
Кроме того, вы можете определить команды, которые будут использованы для целей, у которых совсем нет правил, даже тех, которые не определяют команды. Это делается при помощи правила для цели .DEFAULT. Команды этого правила используются для всех зависимостей, которые не появляются в роли целей ни в одном явном правиле, и для которых неприменимо ни одно неявное правило. Естественно, правила для цели .DEFAULT не будет, если вы не его не напишете.
Если вы используете .DEFAULT без команд и зависимостей, как показано ниже:
.DEFAULT:
то команды, ранее запомненные как соответствующие цели .DEFAULT ,
очищаются. После этого программа make действует так, как будто вы совсем
никогда не определяли правило для цели .DEFAULT.
Если вы не хотите, чтобы цель получала команды из шаблонного правила с произвольным соответствием и из правила для цели .DEFAULT, но при этом вы не хотите, чтобы для этой цели запускалась какая-либо команда, вы можете определить для нее пустую команду (смотрите раздел 5.8 [Определение пустых команд]).
Вы можете использовать правило последней возможности для перекрытия части другого make-файла. Смотрите раздел 3.6 [Перекрытие части другого make-файла].
Суффиксные правила представляют собой устареший способ определения неявных правил для программы 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.
Здесь приведена последовательность действий, которую использует программа make при поиске неявного правила для цели t. Эта последовательность действий вступает в действие для каждого правила с двойным двоеточием, у которого нет команд, для каждой цели из обычных правил, ни одно из которых не имеет команд и для каждой зависимости, которая не является целью никакого правила. Кроме того, программа make рекурсивно следует этой последовательности действий при обработке зависимостей, которые происходят из неявных правил, в ходе поиска цепочки правил.
Суффиксные правила не упоминаются в этом алгоритме, поскольку суффиксные правила преобразуются в эквивалентные шаблонные правила, как только программа make считывает их.
Для цели, являющейся элементом архива и представленной в форме 'АРХИВ(ЭЛЕМЕНТ)', данный алгоритм выполняется дважды, сначала с использованием полного имени цели t, а затем с использованием на месте цели t '(ЭЛЕМЕНТА)', если в первом проходе не было найдено ни одного правила.
Если все зависимости существуют или должны существовать, или же зависимостей нет, то это правило применяется.
Как только находится применимое правило, для каждого шаблона цели, отличного от шаблона, которому соответствует t или n, каждое вхождение в шаблон символа '%' заменяется на основу s, и полученное имя файла запоминается до тех пор, пока не будут выполняться команды для порождения заново целевого файла t. После того, как эти команды выполнятся, каждый из тех запомненных имен файлов вводится в базу данных и помечается как обновленный и имеющий такое же время обновления, как и файл t.
Когда для обновления цели t выполняются команды шаблонного правила, автоматические переменные устанавливаются в соответствие с целью и зависимостями. Смотрите раздел 10.5.3 [Автоматические переменные].