Richard M. Stallman и Roland McGrath / Make :
Richard M. Stallman и Roland McGrath
Архив исходников к этой главе можно получить
тут .
Make может использоваться не только для сборки программ , но и для других задач ,
где одни файлы должны автоматически обновляться при изменении других файлов.
Перед тем, как использовать make, вы должны создать так называемый make-файл (makefile).
Простой команды :
make
будет достаточно для выполнения всех необходимых перекомпиляций если какие-либо из исходных файлов программы были изменены.
Простой make-файл состоит из "правил" (rules) следующего вида:
цель ... : пререквизит ...
команда
Цель (target) представляет собой имя файла - обьектного или исполняемого , а также имя действия -
например 'clean' .
Пререквизит (prerequisite) - это используемый файл либо несколько файлов .
Команда - это действие или несколько действий .
Важное замечание: строки, содержащие команды обязательно должны начинаться с символа табуляции!
Символ табуляции является единственным символом , по которому make отличает
строки с командами от прочих строк .
Вот пример makefile для проекта , который лежит в каталоге example_1 архива :
iEdit: main.o Editor.o TextLine.o
cc -o iEdit main.o Editor.o TextLine.o
main.o: main.cpp main.h Editor.h TextLine.h
cc -c main.cpp
Editor.o: Editor.cpp Editor.h TextLine.h
cc -c Editor.cpp
TextLine.o: TextLine.cpp TextLine.h
cc -c TextLine.cpp
В данном примере 3 строки , в которых есть команда cc , должны еачинаться с символа табуляции .
Целью является исполняемый файл iEdit , пререквизитами являются 3 обьектных файла .
По умолчанию , make первую встреченую цель делает главной .
Теперь упростим наш makefile с использованием дополнительной переменной objects :
objects = main.o Editor.o TextLine.o
iEdit: $(objects)
cc -o iEdit $(objects)
main.o: main.cpp main.h Editor.h TextLine.h
cc -c main.cpp
Editor.o: Editor.cpp Editor.h TextLine.h
cc -c Editor.cpp
TextLine.o: TextLine.cpp TextLine.h
cc -c TextLine.cpp
Применение objects := $(patsubst %.cpp,%.o,$(wildcard *.cpp))
более универсально и будет иметь аналогичный результат : в текущем каталоге будут откомпилированы
все файлы с расширением .cpp , а затем и скомпонованы .
Если нам нужно просто удалить все обьектные файлы , допишем в конец правило :
clean :
-rm edit $(objects)
и выполним команду make с аргументом :
make clean
Make-файл может состоять из конструкций пяти видов:
1. Явные правила
здесь перечисляются файлы а также задаются команды
2. Неявные правила
описывает, как нужно обновлять некоторую группу файлов,
3. Определения переменных
4. Директивы
а. Чтение другого make-файла
б. Решение об использовании части make-файла
в.Определение многострочной переменной
5. Комментарии
По умолчанию, когда make ищет make-файл для обработки, она поочередно пробует найти файлы
со следующими именами (в указанном порядке): `GNUmakefile', `makefile' и `Makefile'.
При желании использовать нестандартное имя нужно использовать префикс -f .
Встретив в make-файле директиву include, make приостанавливает чтение текущего make-файла
и, прежде чем продолжить работу, прочитывает один или несколько указанных в этой директиве make-файлов.
Если указанное в директиве имя начинается не с символа '/' и файл с таким именем отсутствует в текущей директории,
производится его поиск в каталогах, которые были указаны в командной строке с помощью опций `-I' и `--include-dir'
Затем, поиск производится поочередно в следующих директориях : `/usr/gnu/include',
`/usr/local/include', `/usr/include'.
Программа make работает по двухпроходной схеме. На первом строится граф зависимостей для всех целей
и их пререквизитов , на втором нужные цели обновляются .
Значение переменной VPATH указывает утилите make список директорий.
Если файл не найден в текущем каталоге, make предпримет попытку найти его в VPATH.
Имена каталогов отделяются двоеточием .
Например, следующая запись:
VPATH = src:../headers
указывает, что путь поиска состоит из двух каталогов, `src' и `../headers'.
Существует также директива vpath.
Например, запись
vpath %.h ../headers
инструктирует make производить поиск пререквизитов с расширением `.h' в каталоге `../headers',
если они не могут быть найдены в текущей директории.
Поиск в каталогах может производиться специальным образом для файлов, являющихся библиотеками.
Имя имеет специальную форму `-lимя', например :
foo : foo.c -lcurses
cc $^ -o $@
что фактически будет означать выполнение команды
cc foo.c /usr/lib/libcurses.a -o foo
Абстрактная цель (phony target) - это цель, которая не является именем файла.
.PHONY : clean
clean:
rm *.o temp
Следующая цель показывает , как обрабатывать подкаталоги :
SUBDIRS = foo bar baz
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $
foo: baz
Задаются 3 подкаталога - foo , bar , baz . Они будут откомпилированы
в порядке : bar baz foo .
Специальные цели :
.PHONY
.SUFFIXES - расширения имен файлов
.DEFAULT - команды по умолчанию
.PRECIOUS - специальные цели
.INTERMEDIATE - промежуточные файлы
.SECONDARY - промежуточные файлы
.IGNORE - игнорирование ошибок
.EXPORT_ALL_VARIABLES
.NOTPARALLEL
Статические шаблонные правила (static pattern rules) - это правила с несколькими целями, и возможностью автоматически создавать список пререквизитов
для каждой цели, используя ее имя.
Обычно, в каждом шаблоне содержится по одному символу `%',
которое может быть отменено с помощью предшествующего ему символа `\'.
Вот пример, где объектные файлы `foo.o' `bar.o' компилируются из соответствующих им исходных файлов с расширением `.c':
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
Автоматическая переменные `$<' и `$@' содержат, соответственно, имя пререквизита и имя цели .
Если у вас имеется список файлов, лишь некоторые из которых удовлетворяют шаблону, вы можете удалить неподходящие имена с помощью функции filter :
files = foo.elc bar.o lose.o
$(filter %.o,$(files)): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
$(filter %.elc,$(files)): %.elc: %.el
emacs -f batch-byte-compile $<
В этом примере, результатом `$(filter %.o,$(files))' является `bar.o lose.o',
и первое статическое правило вызывает компиляцию этих объектных файлов из соответствующих
им исходных файлов. Результатом выражения `$(filter %.elc,$(files))' является `foo.elc', и этот файл получается из `foo.el'.
|