Утилита make автоматически определяет, какие части программы должны быть перекомпилированы и вызывает команды для их перекомпиляции. Наиболее часто make используется для компиляции C-программ и содержит особенности, ориентированные именно на такие задачи, но можно использовать make с любым языком программирования. Более того, применение утилиты make не ограничивается программами. Можно использовать еe для автоматизации любой задачи, где некоторые файлы должны автоматически порождаться из других.
Прежде чем использовать make, необходимо создать файл, называемый make-файлом, который описывает отношения зависимости между исходными и результирующими файлами и содержит команды для пересборки результирующих файлов. В C++ исполняемый файл зависит от объектных файлов, которые, в свою очередь, зависят от исходных файлов и файлов заголовков.
Для make-файлов зарезервированы имена GNUmakefile, makefile и Makefile, причем поиск идет в указанном порядке. Если необходимо использовать нестандартное имя, то его можно передать явно через опцию -f.
Когда make-файл уже написан, для сборки проекта достаточно выполнить в каталоге, где он находится, команду make.
Простой make-файл состоит из правил (инструкций) следующего вида:
ПЕРЕМЕННАЯ = ЗНАЧЕНИЕ
ЦЕЛЬ1 ... : [ЗАВИСИМОСТЬ ...]
КОМАНДА 1
КОМАНДА 2
ЦЕЛЬ2 ... : [ЗАВИСИМОСТЬ ...]
КОМАНДА 1
КОМАНДА 2
...
Синтаксис:
make [Опции] [Переменная='abc'] [Цель]
Квадратные скобки означают необязательность присутствия данной части.
Опции:
Для автоматической генерации зависимостей от файлов заголовков в языках C и C++ можно использовать команду gcc -M file.c или gcc -MM file.c. Второй вариант отличается тем, что не генерирует зависимости от системных заголовочных файлов.
В КОМАНДАХ можно использовать автоматические переменные. Эти переменные заново вычисляются для каждого выполняемого правила на основе цели и зависимостей правила.
Автоматическая переменная | Назначение |
$@ | Имя файла цели правила. В шаблонном правиле с несколькими целями,имя той цели, которая вызвала выполнение команд правила. |
$< | Имя первой зависимости. Если цель получила свои команды из неявного правила, то это будет первая зависимость, добавленная неявным правилом. |
$? | Имена всех зависимостей, которые являются более новыми, чем цель, с пробелами между ними. |
$^ | Имена всех зависимостей, с пробелами между ними. Если Вы для цели неоднократно укажете одну и ту же зависимость, значение переменной '$^' будет содержать только одну копию ее имени. |
$+ | Эта переменная аналогична переменной '$^', только зависимости, указанные неоднократно дублируются в том порядке, в котором они указаны в make-файле. Это в первую очередь полезно для использования в командах компоновки, где является существенным повторение имен библиотек в определенном порядке |
$* | База с которой сопоставляется неявное правило (см. ниже). В шаблонном правиле база представляет собой часть имени файла, которая сопоставляется символу '%' в шаблоне цели. Если целью является файл 'dir/a.foo.b', а шаблон цели - 'a.%.b', то базой будет 'dir/foo'. База полезна для создания имен файлов, связанных с правилом. В явных правилах база не определена как имя файла без расширения,если такое расширение можно выделить. Не рекомендуется использовать эту переменную в явных правилах |
Неявные правила определены для многих языков программирования и применяются в соответствии с расширением исходного файла. По умолчанию в gnu make список расширений такой : .out, .a, .ln, .o, .c, .cc, .C, cpp, .p, .f, .F, .r, .y, .l, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch, .web, .sh, .elc, .el. При использовании неявных правил используются переменные, переопределяя которые можно управлять процессом преобразования файлов, например, указывать нестандартный компилятор или передавать ему опции.
Исходный файл | Порожденный файл | Команда |
Компиляция C-программ 'file.c' | 'file.o' | $(CC) -c $(CPPFLAGS) $(CFLAGS) file.c |
Компиляция программ на языке C++ 'file.cc' или 'file.C' |
'file.o' | $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) file .cc |
Компиляция программ на Фортране 'file.f' |
'file.o' | $(FC) -c $(FFLAGS) file .f |
# Цель по умолчанию - исполняемый edit
edit : main.o kbd.o command.o display.o
cc -o edit main.o kbd.o command.o display.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
clean :
rm edit main.o kbd.o command.o display.o
По умолчанию, make начинает с первой цели (не считая целей начинающихся с точки). Это цель по умолчанию. В нашем случае это цель edit. Если файл edit новее чем файлы, от которых он зависит, то ничего не произойдет. Зависимости вычисляются рекурсивно для всех файлов, от которых зависит edit. Перекомпиляция и сборка должна быть проведена, если исходный файл или любой из заголовочных файлов, упомянутых среди зависимостей, обновлен позднее, чем объектный файл, или если объектный файл не существует.
Правилу clean не соответствует никакого создаваемого файла и, соответственно, clean ни от чего не зависит и само не входит в список зависимостей. При запуске по умолчанию clean вызываться не будет. Для его выполнения необходимо явно указать цель при запуске make: make clean
Для сокращения записи можно использовать переменные и действия по умолчанию (неявные правила)
.PHONY : all clean
all: edit
objects = main.o kbd.o command.o display.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
clean :
rm edit $(objects)
Переменная objects позволила использовать единожды написанный список объектных файлов, а для объектных файлов в make встроено неявное правило по умолчанию
file.c: file.o $(CC) -c file.c
Специальная цель .PHONY является встроенной в make и определяет свои зависимости как цели-имена, которым нет соответствия в виде файлов. Если данное правило пропустить, то создание в текущем каталоге файла с именем clean заблокирует выполнение make clean. Использование правил по умолчанию позволяет изменить стиль записей зависимостей:
objects = main.o kbd.o command.o display.o
edit : $(objects)
cc -o edit $(objects)
$(objects) : defs.h
kbd.o command.o : command.h
display.o : buffer.h
Данная запись указывает, что все объектные файлы зависят от заголовочного файла defs.h, но для некоторых из них проверяются дополнительные зависимости.