Wiki

Стандарт кодирования GNU - 5. Соглашения, касающиеся Make-файлов (Makefile)

Этот раздел описывает соглашения по написанию Make-файлов для программ GNU.

5.1 Общие соглашения для Makefile
Каждый 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 $&commat;   

для того, чтобы VPATH мог бы быть правильно использован. Когда цель имеет несколько зависимостей, следует явно использовать $(srcdir). Например, приведенное выше в качестве примера правило для цели foo.1 следует записать следующим образом:
foo.1: foo.man sedscript   
        sed -s $(srcdir)/sedscript $(srcdir)/foo.man > foo.1   

5.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 или скриптах, которые предназначены только для использования в данной конкретной системе, и для которых Вы уверены в их существовании.

5.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 $&commat;; \   
 # 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 должна явно зависеть от всех файлов, которые не являются исходными, но должны входить в поставку, для того, чтобы убедиться в их актуальности. Смотри раздел "Издание версий".

5.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-пакетов. Для того, чтобы это было полезным, все пакеты должны быть разработаны таким образом, чтобы они правильно использовали значения переменных.