Этот раздел описывает соглашения по написанию Make-файлов для программ GNU.
Каждый Makefile должен включать строку
SHELL = /bin/sh
для того, чтобы избежать проблем на системах, в которых
переменная SHELL может быть унаследована из окружения. (Подобные
сложности отсутствуют при использовании утилиты GNU make).
Не следует предполагать, что '.' входит в путь для поиска исполнимых программ. Когда Вам нужно запускать программы, которые являются частью Вашего пакета, во время работы 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 '$<' представляет имя исходного файла, где бы он ни находился. (Многие версии make воспринимают '$<' только в неявных правилахю) Фрагмент Make-файла типа
foo.o: bar.c
$(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.c
должен быть записан следующим образом:
foo.c: bar.c
$(CC) $(CFLAGS) $< -o $@
для того, чтобы VPATH мог бы быть правильно использован. Когда
цель имеет несколько зависимостей, следует явно использовать
$(srcdir). Например, приведенное выше в качестве примера правило для
цели foo.1 следует записать следующим образом:
foo.1: foo.man sedscript
sed -s $(srcdir)/sedscript $(srcdir)/foo.man > foo.1
Команды, которые пишутся в 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 или скриптах, которые предназначены только для использования в данной конкретной системе, и для которых Вы уверены в их существовании.
Все программы в GNU должны иметь следующие цели в своих Makefile'ах.
Компиляция всей программой. Эта цель должна быть целью по умолчанию. Эта цель не должна перестраивать никакие файлы документации; info-файлы должны включаться в поставку, DVI файлы должны формироваться только по явному запросу.
Компиляция программы и копирование исполнымых файлов, библиотек и т.д. туда, где они должны располагаться для их обычного использования. Если возможно, по этой цели должна выполняться простая проверка того, что программа была правильно установлена.
Команды должны создать все каталоги, в которых файлы будут установлены, если эти каталоги уже не существуют. Сюда входят каталоги, указанные как значения переменных 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
Выполняется удаление всех установленных файлов, созданных при исполнении цели 'install' (но не тех файлов, которые создаются при исполнении цели 'all').
Выполняется удаление тех файлов из текущего каталога, которые были созданы при построении программы. Не удаляются файлы, в которых сохранена конфигурация. Так же сохраняются файлы, которые могут быть получены при построении, но которые тем не менее входят в поставку. Следует удалять .dvi файлы, если они не являются частью поставки.
Удаляются все файлы из текущего каталога, которые были созданы при конфигурировании или построении программы. Если Вы распакуете исходные тексты программ, после чего построите программу не создавая самостоятельно каких-либо файлов, то 'make distclean' должно оставить только те файлы, которые входили в поставку.
Работает так же, как и clean, но оставляет неудаленными некоторые файлы, которые обычно нежелательно перекомпилировать. Например, цель 'mostyclean' для GCC не удаляет файл 'libgcc.a', поскольку его перекомпиляция редко когда бывает нужна, и к тому же занимает много времени.
Выполняется удаление из текущего каталога всего, что может быть построено с помощью Makefile. Обычно это включает в себя все то, что удаляется по distclean, исходные файлы на C, полученные с помощью построителя синтаксических анализаторов Bison, таблицу тегов, info-файлы и т.д.
Имеется одно исключение: 'make realclean' не должен удалять 'configure', даже если 'configure' может быть построен используя правило в Makefile. Более того, 'make realclean' не должен удалять ничего из того, чье существование требуется для выполнения 'configure' и начального исполнения программы.
Обновляет таблицу тегов для программы.
Выполняется построение всех требуемых info-файлов. Лучший всего написать правила по следующему образцу:
info: foo.info
foo.info: foo.texi chap1.texi chap2.texi
$(MAKEINFO) $(srcdir)/foo.texi
Вы должны определить в Makefile переменную MAKEINFO. Она должна
запускать программу makeinfo, которая входит в поставку пакета
Texinfo.
Выполняется построение DVI-файлов для всей TeXinfo-документации. Пример правил:
dvi: foo.dvi
foo.dvi: foo.texi chap1.texi chap2.texi
$(TEXI2DVI) $(srcdir)/foo.texi
Вы должны определить переменную TEXI2DVI в Makefile. Она должна
запускать программу texi2dvi, которая является частью поставки пакета
Texinfo. Можно указать просто зависимости, тогда GNU Make сам
предоставит эту команду.
Выполняется создание tar-файла, содержащего дистрибутивную
поставку этой программы. tar-файл должен быть создан таким образом,
чтобы имена файлов в нем начинались с подкаталога, имя которого
являлось бы именем поставляемого пакета. Имя может включать в себя
номер версии.
<p>
Например, поставка дистрибутивного архива для GCC версии 1.40
должна распаковываться в каталог с именем 'gcc-1.40'.
<p>
Простейший способ выполнить это состоит в создании названного
таким образом каталога, и использовании ln или cp для установки
соответствующих файлов в него. После чего необходимо выполнить tar для
этого подкаталога.
<p>
Цель dist должна явно зависеть от всех файлов, которые не
являются исходными, но должны входить в поставку, для того, чтобы
убедиться в их актуальности. Смотри раздел "Издание версий".
<tag/'check' /
<p> Выполняет самотестирование (если предусмотрено). Пользователь
должен построить программу перед запуском тестов, но не должен
устанавливать программу; Вы должны написать тесты таким образом, чтобы
они работали когда программа построена, но не установлена.
<p>
Следующие цели в тех программах, в которых они нужны, должны
иметь следующие стандартные имена.
<tag/'installcheck' /
<p> Выполняет проверку правильности установки (если соответствующие
тесты предусмотрены). Пользователь должен построить и установить
программу перед запуском этих тестов. Вы не должны считать, что
$(bindir) входит в путь поиска программ.
<tag/'installdirs' /
<p> Полезно добавить цель с именем 'installdirs' для создания
структуры каталогов, в которых будут установлены файлы. Имеется
скрипт, названный 'mkinstalldirs', который подходит для этой цели. Он
находится в пакете Texinfo. Вы можете написать правило по следующему
образцу:
<tscreen><verb># Make sure all installation directories (e.g. $(bindir))
# actually exists by making them if necessary.
installdirs: mkinstalldirs
$(srcdir)/mkinstalldirs $(bindir) $(datadir) \
$(libdir) $(infodir) \
$(mandir)
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
Следует всегда указывать в качестве второго аргумента имя файла
(не имя каталога). Надо использовать отдельную команду для каждого
устанавливаемого файла.
Каталоги для установки должны всегда именоваться посредством переменных, поскольку это упрощает установку программы в нестандартное место. Стандартные имена для таких переменных следующие:
Префикс, используемый для построения умолчательных значений для переменных, перечисленных ниже. Значение по умолчанию для переменной prefix должно быть '/usr/local' (по крайней мере сейчас).
Префикс, используемый при построении значений по умолчанию для некоторых переменных, перечисленных ниже. Значение по умолчанию для переменной exec_prefix должно быть $(prefix).
Как правило, $(prefix) используется для каталогов, которые содержат машиннозависимые файлы (такие, как исполнимые файлы и библиотеки процедур), в то время как $(prefix) используется для остальных каталогов.
Каталог для установки исполняемых файлов программ, которые могут быть запущены пользователем. Обычно, это '/usr/local/bin', но должно быть записано как '$(exec_prefix)/bin'
Каталог для установки исполняемых файлов, которые будут запускаться другими программами, а не пользователем. Объектные файлы и библиотеки объектного кода должны так же попадать в этот каталог. Идея состоит в том, что этот каталог используется для файлов, которые зависят от конкретной архитектуры машины, но не должны находится в пути для команд. Значение для libdir обычно '/usr/local/lib', но должно быть записано как '$(exec_prefix)/lib'.
Каталог для установки файлов с неизменяемыми данными, которые используются программами во время их работы. Этот каталог используется для файлов, которые не зависят от используемого типа машины. Значение этой переменной обычно '/usr/local/lib', но должно быть записано как '$(prefix)/lib'.
Каталог для установки файлов с данными, которые программы могут изменять в процессе своей работы. Эти файлы должны быть независимыми от типа используемой машины, и должны допускать разделение их между машинами при сетевой установке. Значение этой переменной обычно '/usr/local/lib', но должно быть записано как '$(prefix)/lib'
Каталог для установки заголовочных файлов (header-файлов), которые могут быть включены другими пользовательскими программами с помощью директивы препроцессора '#include'. Значение этой переменной обычно '/usr/local/include', но должно быть записано как '$prefix/include'.
Большинство компиляторов отличных от GCC не выполняют поиск заголовочных файлов в '/usr/local/include', поэтому установка заголовочных файлов в этот каталог целесообразна только для GCC. Иногда это не представляет из себя проблему, так как некоторые библиотеки предназначены для использования исключительно с GCC. Но имеются так же и библиотеки, предназначенные для работы и с другими компиляторами. Они должны устанавливать свои включаемые файлы в два места, одно из которых определено переменной includedir, а другое oldincludedir.
Каталог для установки заголовочных файлов для использования с компиляторами, отличными от GCC. Значение этой переменной обычно
usr/include'. /
Команды Makefile должны проверить, не пусто ли значение переменной oldincludedir. Если оно пусто, они не должны пытаться использовать ее и выполнять повторную установку включаемых файлов.
Пакет не должен замещать существующие заголовочные файлы в этом каталоге, в случае, если заголовочный файл пришел не из того же пакета. Так, если Ваш пакет Foo предоставляет заголовочный файл 'foo.h', то он должне установить заголовочный файл в каталог, заданный oldincludedir, если (1) foo.h не существует, или (2) foo.h существует и пришел из пакета Foo.
Для того, чтобы проверить, что foo.h пришел из пакета Foo, поместите специальную строку в этот файл - часть комментария - и проверьте наличие этой строки с помощью команды grep.
Каталог для установки man-страниц (если они есть) для этого пакета. Переменная должна включать суффикс для соответсвующей секции руководства - обычно '1' для утилит. Обычно значение этой переменной '/usr/local/man/man1', но должно быть записано как '$(prefix)/man/man1'
Каталог для установки в раздел 1 man-страниц.
Каталог для установки в раздел 2 man-страниц.
Используйте переменные такого рода вместо 'mandir', если пакет должен устанавливать man-страницы более чем в один раздел.
Расширение для имени файла для устанавливаемых man-страниц. Переменная должна содержать точку, за которой следует соответствующая цифра, обычно '.1'.
Расширение имени файла для установки в раздел 1 man-страниц.
Расширение имени файла для установки в раздел 2 man-страниц.
Используйте переменные такого рода вместо 'manext', если пакет должен устанавливать man-страницы более чем в один раздел.
Переменная должна содержать имя каталога для установки info-файлов для данного пакета. По умолчанию, ее значение должно быть '/usr/local/info', но должно быть записано как '$(prefix)/info'.
В этой переменной должно находится имя каталога, содержащего компилируемые исходные тексты. Значение этой переменной обычно вставляется скриптом 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-пакетов. Для того, чтобы это было полезным, все пакеты должны быть разработаны таким образом, чтобы они правильно использовали значения переменных.