Это утилита юникс-систем(есть версия линкуса и бсд), которая помагает собирать приложения восновном на языке си. Каталог с исходниками приложенения должен содержать специальный файл(возможные имена: GNUmakefile, Makefile, makefile) в котором описаны связи между отдельными файлами, по которому утилита компилирует исходиники в обьектные файлы, а потом их компонует линковщик.
Обычно простейшая программа на си выглядит примерно так:
На последний файл имееют ссылки вида #include два предыдущих.
Чтобы откомпилировать приложение мы пользлуемся утилитой сс:
Обычно простейшая программа на си выглядит примерно так:
main.c lib.c defines.h
На последний файл имееют ссылки вида #include
Чтобы откомпилировать приложение мы пользлуемся утилитой сс:
cc -c main.c cc -c lib.c cc -o program main.o lib.o
Сначала мы создали два обьектных файла(исходные тексты переведены в двоизный формат, понятный для процессора). А потом с этих файлов скомпоновали один исполняемый, который и является приложением.
Если приложение состоит из многих файлов, и при этом они сложно взаимосвязанны, а мы сделали изменения в нескольких, то утилита мейк помагает отследить нам эти сложные связи, а также сориентироваться по последним датам правок файлов и перекомпилировать только нужные, а потом скомпоновать обьектные файлы в исполняемый(приложение или библиотеку).
Чтобы утилита заработала, мы должны указать в мейкфайле, что от чего зависимо. На основе этой информации утилита:
- собирает из этой информации правильную последовательность команд для получения требуемых результирующих файлов;
- и инициирует создание требуемого файла только в случае, если такого файла не существует, или он старше, чем файлы от которых он зависит.
Вот какой мейкфайл мы должны определить:
program: main.o lib.o
cc -o program main.o lib.o
main.o lib.o: defines.hМейкфайл состоит из правил и переменных. Вот структура правила:
цель1 [цель2 ...]: [реквизит1 реквизит2 ...]
[<TAB>команда1]
.
.
.
[<TAB>командаN]
Цели -- это результирующие файлы, а реквизиты -- это файлы от которых зависят цели. При этом не нужно указывать, что *.o-файлы зависят от *.c-файлов, это мейк знает сам, и знает какую команду нужно выполнять дле решения этой зависимости(cc -c main.c). Поэтому, когда утилита подходит к строке где встречается обьектный файл, первое, что она делает, так этом проверку не являтся ли *.o-файл старше *.c-файла, если так и есть, то сначала перекомпилируется обьетный файл на основании обновленного исходника.А вот резюме самой комманды:
make [ -f makefile ] [ options ] ... [ targets ] ...
Вот стандартные цели для сборки дистрибутивов GNU:
- all - выполнить компиляцию пакета(цель поумолчанию)
- install - установить пакет из дистрибутива(копируются исполняемые файлы, библиотеки и документация в системные директории)
- uninstall -удалить пакет(удаляются исполнаяемые файлы, библиотеки и документация из системных директорий)
- clean - удаляются в дистрибутиве обьектные и исполняемые файлы, созданные в процессе компиляции
- distclean - клин+ удаляются файлы созданные скриптом ./configure(процесс натройки компиляции дистрибутива)
А вот эта цель характерна для BSD:
- depend - выполняется компиляция/выстраивание зависимостей
А вот тот же наш пример, но при этом в нем используются кроме правил еще и переменные, это нам позволяет в одном месте производить изменения мейкфайла по мере роста исходных файлов приложения:
OBJ = main.o lib.o
program: $(OBJ)
cc -o program $(OBJ)
$(OBJ): defines.hЕсли при запуске make явно не указать цель, то будет обрабатываться первая цель в make-файле, имя которой не начинается с символа «.».
Важный момент мейк-файла это ложные цели. Это цели, которые не создают файл, но при этом выполняют, что-то важное. Это например:
all: foo clean: rm -f bar.o bar.c foo.o foo.c .PHONY: all clean
Метка .PHONY указывает явно, что наши цели "ложные", на случай если в каталоге вдруг окажутся файлы с такими именами, как
all и clean.В обработку мейк-файлов можно сделать более гибкой:
Пускай у нас есть скриптик snozzle, который конвертирует наш специфичный язык(удобный для нас) в язык Си. Мы делаем себе мейк-фал:
%.c: %.snoz snozzle $< -o $@
Пояснения предопределенных макросов:
% -- означает один и более символов.
$^ -- означает полный список зависимостей(реквизитов)
$< -- означает первый в списке зависимостей(реквизитов)
$@ -- означает первый в списке целей(имеется ввиду целей и зависимостей ближайших сверху)
В результате:
$ ls Makefile foo.snoz $ make snozzle foo.snoz -o foo.c cc -c -o foo.o foo.c echo 'char *builddate="' `date` '"' >bar.c cc -c -o bar.o bar.c cc foo.o bar.o -o foo rm foo.c
А вот применяемые переменные среды ОС в мейк-файлах, их можно определять также внутри мейк-файла. Вот их список:
- CPPFLAGS command line flags to cpp
- CFLAGS command line flags to cc
- CXXFLAGS command line flags to c++
- LDFLAGS command line flags to ld
- ASFLAGS command line flags to as
А вот пример мейк-файла приложения написанного в этом контексте:
CXXFLAGS=-g
sim: car.o road.o sim.o event.o
g++ $(LDFLAGS) sim.o car.o road.o event.o -lm -o sim
car.o: car.cc car.h sim.h event.h road.h Makefile
sim.o: sim.cc sim.h car.h road.h event.h Makefile
road.o: road.cc road.h sim.h event.h car.h Makefile
event.o: event.cc event.h sim.h Makefile
Комментариев нет:
Отправить комментарий