Программа, у которой есть несколько файлов исходного кода или для которой необходимы необычные параметры компиляции, слишком неудобна для компиляции вручную. Эта проблема возникает на протяжении многих лет, и традиционным средством Unix для управления компиляцией является утилита make. Вам следует узнать немного об этой утилите, если вы работаете в системе Unix, поскольку системные утилиты иногда опираются на нее в своей работе. Однако данная глава является лишь верхушкой айсберга. Утилите make посвящены целые книги, например
Главной идеей утилиты make является
Чтобы собрать цель, утилита make следует какому-либо правилу, например, определяющему, как перейти от исходного файла .c к объектному файлу .o. Утилите make уже известны некоторые правила, но вы можете изменить их, а также создать собственные.
15.2.1. Пример файл Makefile
Следующий очень простой файл Makefile собирает программу myprog из файлов aux.c
# object files
OBJS=aux.o main.o
all: myprog
myprog: $(OBJS)
$(CC) -o myprog $(OBJS)
Символ # в первой строке этого файла означает комментарий.
Следующая строка является всего лишь макроопределением; она задает для переменной OBJS два имени объектных файлов. Это будет важно в дальнейшем. Сейчас обратите внимание на то, как записывается макроопределение и как на него ссылаются далее ( ($(OBJS) ).
Следующий элемент файла Makefile содержит первую цель, all. Первая цель всегда является целью по умолчанию, утилита make будет собирать ее, если вы запустите команду make в командной строке саму по себе.
Правило сборки цели следует после двоеточия. Для цели all в этом файле Makefile сказано, что вам необходимо удовлетворить чему-то по имени myprog. Это первая зависимость в данном файле; цель all зависит от myprog. Заметьте, что myprog может быть реальным файлом или целью другого правила. В данном случае оно является и тем и другим (правилом для цели all и целью для OBJS).
Чтобы собрать программу myprog, этот файл Makefile использует макроопределение $(OBJS) в зависимостях. Макроопределение развертывается в имена aux.o и main.o, поэтому программа myprog зависит от этих двух файлов (они должны быть реальными файлами, поскольку нигде в файле Makefile нет целей с такими именами).
Данный файл Makefile предполагает, что у вас есть два файла с исходным кодом на языке C: aux.c
$ make
cc -c -o aux.o aux.c
cc -c -o main.o main.c
cc -o myprog aux.o main.o
Схема зависимостей приведена на рис. 15.1.
Рис. 15.1. Зависимости в файле Makefile
15.2.2. Встроенные правила
Каким же образом утилита make узнает о том, как перейти от файла aux.c к файлу aux.o? Ведь файла aux.c нет внутри файла Makefile. Ответ такой: утилита make следует встроенным правилам. Она знает о том, что следует искать файл .c, если вам необходим файл .o, и, более того, она знает, как запустить команду cc -c для этого файла .c, чтобы добиться цели — создать файл .o.
15.2.3. Окончательная сборка программы
Последний шаг при получении программы myprog довольно хитрый, но идея достаточно ясная. Когда у вас появятся два объектных файла в макроопределении $(OBJS), можно запустить компилятор C в соответствии со следующей строкой (здесь переменная $(CC) развертывается в имя компилятора):
$(CC) -o myprog $(OBJS)
Отступ перед переменной $(CC) является табуляцией. Вы
Остерегайтесь следующего сообщения:
Makefile:7: *** missing separator. Stop.
Подобная ошибка означает, что файл Makefile не в порядке. Табуляция является разделителем, и, если она отсутствует или есть какая-либо другая помеха, вы увидите такую ошибку.
15.2.4. Поддержание актуальных версий файлов