5 авг. 2008 г.

Создаём пакет для Ubuntu. Часть 2. Общие соглашения о Makefile'ах

Вы, я думаю, поняли основную идею configure файла. Здесь я постараюсь раскрыть структуру Makefile, воспользовавшись тем же документом что и раньше, GNU Coding Standards.

Вы, если увлекаетесь программированием, или компилируя чужие исходные коды, в процессе своей компьютерной жизнедеятельности должны были столкнуться с "мейкфайлами" (Makefile). В чем заключается их смысл? Их назначение состоит в том, чтобы автоматизировать процесс сборки вашего проекта. Как вы знаете простая программа может быть скомпилирована с помощью одной лишь строчки gcc main.cpp. На выходе вы получите файл a.out который потом можете запустить или переименовать.

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

Каждый Makefile должен содержать эту строку:

SHELL = /bin/sh

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

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

.SUFFIXES:
.SUFFIXES: .c .o

Первая линия очищает существующий список суффиксов, вторая показывает все суффиксы, которые могут являться предметом для неявных правил (я счтиаю, что здесь разговор идёт в первую очередь о том, что множество промежуточных объектов, файлов и прочего оканчиваются по-разному: *.c, *.cpp, *.cc, *.o, *.obj Поэтому чтобы компилятор не путался мы ограничиваем этот список)

Не делайте предположения о том, что '.' является путём для вызова команды. Когда вам требуется запустить программы, являющиеся частью вашего пакета в процессе работы make, убедитесь, что она использует путь './' (если программа собирается как часть make), или '$(srcdir)/' (если файл - не изменяющаяся часть исходного кода). Без этих префиксов используется текущий путь поиска (ну то, есть по всем /usr/bin и прочим пробежится, а не там где надо).

Различие между './' (директория, где собирается программа) и '$(srcdir)/' (директория с иходными файлами) важно, так как пользователи могут собирать программу в отдельный каталог, используя '--srcdir' опцию configure скрипта. Следующее правило:

foo.1 : foo.man sedscript
        sed -e sedscript foo.man > foo.1

будет ошибочным если директория сборки будет отличаться от директории с исходными файлами, так как 'foo.man' и 'sedscript' располагаются в каталоге с исходниками (то есть видите что перед ними нет никаких приставок с абсолютными значениями пути?).

При использовании GNU make, полагаясь на то, что 'VPATH' укажет на исходный файл и компиляция будет работать, только в случае единичного файла. Для этого существует автоматическая переменная '$<', представляющая сам исходный файл (что-то вроде псевдонима). Много версий make устанавливают '$<' только в неявных правилах. Цель Makefile вида

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o

должна быть переписана как

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@

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

foo.1 : foo.man sedscript
        sed -e $(srcdir)/sedscript $(srcdir)/foo.man > $@

Дистрибутивы GNU обычно содержат некоторые файлы, которые не являются исходными файлами: info файлы, вывод из Autoconf, Automake, Bision или Flex. Эти файлы обычно появляются в директории с исходными файлами, и потому они должны всегда появляться там, а не в каталоге сборки. Поэтому правила Makfile обновляющие их должны класть их в исходный каталог.

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

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

Комментариев нет: