Привет, я штудировал доки по Make (уже второй раз за несколько лет) и пожалел о том, что в прошлый раз не составил небольшой конспект. Оставлю здесь на случай, когда потребуется освежить память, может и ещё кто сочтёт полезным.
1. include / -include - включить Makefile, дупускаются shell
шаблоны. С / без ошибки при отсутствии файла. После прочтения всего
Makefile, имена файлов, которые указаны директиве, проверяются на
возможность обновления рецептами. В случае обновления включаются
заново (основа для автоматической генерации зависимостей).
2. Secondary expansion - после чтения Makefile и перед фазой
обновления целей, производится второй проход по списку
пререквизитов. Доступны автоматические переменные.
.SECONDEXPANSION:
main_OBJS := main.o try.o test.o
lib_OBJS := lib.o api.o
main lib: $$($$@_OBJS)
3. Order-only пререквизиты - цель не будет считаться устаревшей при
выполнении рецепта такого пререквизита
targets : normal_prereq | order_only_prereq.
4. Переменная VPATH - пути поиска всего. Директива vpath - пути поиска
для определённого класса файлов.
5. .PHONY : target - цель target всегда устаревшая. Для target не
производится поиск неявных правил.
6. Если в качестве пререквизита -lname, то поиск библиотеки в
следующих местах: в текущей директории, vpath и VPATH, /lib,
/usr/lib, prefix/lib.
7. Если существуют несколько правил с одним двоеточием для одной цели,
то все они объединяются в одно правило. Рецепт может быть указан
лишь однажды, если его нет, то поиск среди неявных правил.
8. Если существуют несколько правил с двумя двоеточием для одной цели,
то каждое правило независимо от другого. Каждое правило может иметь
свой рецепт иначе поиск среди неявных правил. Могут выполниться все
рецепты, ни одного не выполниться, выполниться лишь часть рецептов.
9. target : ; пустой рецепт, не будет производиться поиск неявного
правила.
10. Static pattern rule
targets : target-pattern : prereq-pattern
recipe
${objects} : %.o : %.c
Часть имени соответствующая % - stem.
11. Каждая строка рецепта исполняется в своей shell (в одной есле
.ONESHELL). Shell, которая используется, хранится в SHELL, опции в
.SHELLFLAGS. Значение SHELL не наследуется из окружения make.
Exit-status shell, выполняющей команду, содержится в .SHELLSTATUS.
12. В рецепте (в начале строки):
@ - отключает печать команды (-n и --just-print всё равно
печатают такие команды);
+ - выполнить даже если заданы -n или --just-print;
- - игнорировать ошибки при исполнении команды.
13. В рецепте: обращение к make переменной ${var}, к shell переменной
$${var}.
14. При рекурсивном вызове make использовать переменную ${MAKE}
$(MAKE) -C subdir
15. [override] undefine var - удалить переменную.
16. export / unexport var [=val] - экспортировать / не экспортировать
переменную в sub-make. Одинокий export / unexport - экспортировать
/ не экспортировать все переменные.
17. var = val - ссылка;
var := val - обычная переменная;
var += val - ссылка ли, зависит от типа val;
var ?= val - присвоить значение если var не объявлена;
var != cmd - выполнить cmd в shell;
${foo:.o=.c} - заменить .o в конце слов на .c;
${foo:%.o=%.c}
18. Иерархия переменных:
1. объявлянные внутри Makefile с override (дальнейшая
модификация возможно только с override);
2. переданные через командную строку;
3. объявленные внутри Makefile без override;
4. из окружения, где запускается make.
Экспортируются переменные в sub-make:
1. из окружения, где запускается make (редактирование внутри
Makefile не влияет);
2. переданные через командную строку (если Makefile редактирует
с override, то в sub-make приходит значение из командной
строки);
3. объявленные внутри Makefile с export.
19. MAKEFLAGS - содержит флаги переданные при запуске make +
переменные со значениями переданными через командрую строку, но не
содержит цели. В переменную можно добавить флаги внутри Makefile
или в окружении, в котором запускается make).
20. MAKELEVEL - содержит целое число, которое указывает на глубину
рекурсии. 0 для главного make.
21. MAKECMDGOALS - содержит цели заданные при запуске make.
22. Target-specific переменные
prog : [private] CFLAGS=-g
prog : prog.o foo.o bar.o
recipe
задаёт CFLAGS в рецептах для prog, prog.o, foo.o, bar.o. Если
private стоит, то пререквизиты не наследуют CFLAGS. Если
переменная объявлена private на глобальном уровне, то она не
будет видна ни в одно рецепте.
23. Pattern-specific переменные
%.o : CFLAGS=-g
24. Match-anything pattern rule (цель одинокий %). Бывают:
1. терминальные (%::pregeq) - prereq должен существовать, не
может быть создан посредством другого правила.
2. иначе - правило будет рассмотрено только если нет других
неявных правил , чья цель совпадает с искомой.
25. Last-resort default rule
1. %::
2. .DEFAULT: # если рецепт не указан, то текущее правило
будет удалено
26. Отмена неявного правила
%.o:%.s
указать ту же цель и те же пререквизиты, рецепт не указывать.
27. Архивы:
1. при использовании нотации со скобками ( libname(objs) ) не
допускать параллельного запуска make (-j опция).
2. внутри архива содержится таблица символов (__.SYMDEF), ranlib
lib.a её обновляет. GNU ar не требует запуска вручную,
запускает её автоматически.
28. Договорённости:
* Каждый Makefile должен содержать
SHELL = /bin/sh
для избежания проблем на системах, где SHELL может быть
унаследована из окружения.
* Не плохо задать суффиксы для которых будет производиться поиск
неявных правил
.SUFFIXES: # удаляет все раннее установленные
.SUFFIXES: .c .o
* ar bison cc flex install ld ldconfig lex make makeinfo ranlib
texi2dvi yacc chgrp chmod chown mknod - вызывать через
переменные ${AR}, ... . Для каждой переменной-команды
переменная с опциями образуется добавлением FLAGS к имени
(исключение - CFLAGS, YFLAGS, LFLAGS).
* команды, которые следует использовать напраямую (без
переменных): awk cat cmp cp diff echo egrep expr false grep
install-info ln ls mkdir mv printf pwd rm rmdir sed sleep
sort tar test touch tr true gzip.
* каждый Makefile должен задавать переменные: INSTALL,
INSTALL_PROGRAM (дефолтно ${INSTALL}), INSTALL_DATA (дефолтно
${INSTALL} -m 644).
* staged install - для целей install и uninstall поддерживать
переменную DESTDIR
$(INSTALL_PROGRAM) foo $(DESTDIR)$(bindir)/foo
$(INSTALL_DATA) libfoo.a $(DESTDIR)$(libdir)/libfoo.a
* установка info и man страниц в цели install.
* Разбивка install на $(PRE_INSTALL), $(POST_INSTALL),
$(NORMAL_INSTALL). Разбивка uninstall на $(PRE_UNINSTALL),
$(POST_UNINSTALL), $(NORMAL_UNINSTALL).
Господа, у меня вот ещё какой вопрос имеется: вот написал я какую-нибудь софтину, как мне определиться с именами файлов и всего проекта? Т.е. чтобы небыло конфликтов имён с другим софтом при make install. К тому же если сегодня конфликтов нет, то завтра у меня нет никаких гарантий, что такой софт не появится. Как тут правильно поступать? Каждый проект должен писать какие-то проверки на конфликты имён? Если так, то делает ли это автоматом autoconf+automake? cmake?