Что такое Makefile? Makefile - это сценарий для утилиты make. Эта утилита помогает автоматизировать процесс компиляции проекта (проектов):
- позволяет компилировать большие проекты, состоящие из большого количества библиотек;
- определяет, что нужно компилировать (если файлы не изменялись, то не компилируются при очередной сборке проекта);
- указывает необходимые опции компилятора (например, пути к файлам заголовков, оптимизация и т.д.);
- выполняет дополнительный команды (например, удаление файлов);
- поддерживает различными платформами и средами разработки.
По умолчанию утилита make считает, что файл сценариев называется Makefile, поэтому компиляцию можно запустить простым вызовом make в одной директории в Makefile. Если же имя файла сценария отличается, то нужно использовать явное указание его имени и ключ -f:
make -f prjmake.nmk
Makefile состоит из нескольких основных частей:
- правила;
- директивы;
- переменные;
- комментарии.
Начнем рассмотрение в обратном порядке списка - от простого к сложному.
Комментарии.
Комментарий обозначается символом '#'. Если нужно использовать символ '#' в другом контексте, то необходимо добавить обратный слэш: '\#'.
Перменные.
Сделать файл сценариев более простым и читабельным можно используя переменные. В терминологии make-файлов, переменные являются синонимами макроопределений. Создать переменную очень просто:
LIB = lib1.o lib2.o lib3.o
Название переменной задается в верхнем регистре (по негласному соглашению). Для получения параметров переменной используется смпользуются скобки и символ '
$(PATH)
Значение переменной может вычисляться рекурсивно:
PATH=$(PATH)/trunc
Либо можно использовать другую форму записи:
PATH+=/trunc
Некоторые переменные являются стандартыми константами, для них нельзя вычислять значение рекусивно. Такими перменными являются: CC (имя компилятора С), СХХ (имя компилятора С++), CFLAGS (параметры С компилятора), CXXFLAGS (параметры С++ компилятора).
Помимо переменных, определенных "писателем" файла, Make-файл предполагает использование автоматических переменных, значения которых вычисляются в контексте использования таких переменных (вычисление основывается на цели и зависимости правила - о целях и зависимостях ниже):
- $@ - имя цели;
- $$@ - имя цели, если его необходимо ввести в строке описания зависимости справа от двоеточия;
- $< - имя первой зависомости;
- $? - имена всех зависимостей (с пробелами) которые новее, чем цель;
- $^ - имена всез зависимостей с пробелами;
- $* - имя текущего предусловия за вычетом суффикса;
- $% - имя соответствующего .о файла, если текущей целью является файл библиотеки;
- $** - только для nmake - внутри правила обозначаются все зависимости, оказавшиеся справа от двоеточия;
- D - часть имени внутренних макроопределений, описывающая директорию файла (допустимые варианты применения: $(@D), $$(@D), $(
- F - часть имени внутренних макоопределений, описывающая собственно имя файла (допустимые варианты прменения: $(@F), $$(@F), $(
- B - часть имени внутренних макроопределений, описывающая базовое имя файла (без диска, директориии и расширения);
- R - часть имени внутренних макроопределений, описывающая полный путь к файлу за вычетом расширения.
Директивы.
Директива - это команда для make с указанием, что делать в процессе чтения make-файла. Может выполнять такие действия:
- подключать другие make-файлы;
- принимать решение какие части файла использовать, а какие игнорировать (в зависимости от значения переменных);
- определение значений переменных.
Поключать другие make-файлы можно директивой include. Она указвает утилите make, что нужно приостановить чтение текущего файла и прочитать указанные файлы:
include filenames...
Если фала не существует - выводиться ошибка. Для отключения сообщени об ошибке, к директиве добавлятеся префикс '-':
-include file1
Решение о том, какие части make-файла использовать, а какие игнорировать, примается на основе условий, синтаксис которого имеет вид:
Например:
Определить значение перенной можно при помощи дериктив define... endef:
В этом случает значение переменной two-lines = echo foo; echo $(bar)
Правила.
Правила объясняют make, что и как нужно пересобирать. В общем виде структура выглядит так:
Здесь targets - имена файлов-результатов, разделенные пробелами; так же может быть действие не связанное с процессом компиляции, например, clean. prerequisites - зависимости, то, от чего зависит создание targets. command - комманда, которая выполняется для получения targets; может быть не одна; перед командой обязательно ставиться табуляция.
Существуют несколько фиктивных целей:
- all - выполнение работы по достижению всех частных целей, перечисленных ниже;
- build - компиляция и сборка всех устаренших (невыполненных) целей/файлов;
- clean - удаление всех файлов, кроме исходных;
- docs - подготовка документации и размещение таких файлов в соответствующих системных директориях;
- examples - компиляция и сборка примеров;
- install - работа, по размещению всех готовых частей проекта в соответствующих директориях.
В именах файлов могут использоваться wildcards:
objects = *.o
Пример использования правил:
Помимо обычных правил, можно создавать шаблонные правила - правила, применимые к группе файлов. Такие правила имеют суффиксную форму записи:
Если бы в предыдущем примере mytest зависел от нескольких o-файлов, то шаблонное правило можно было бы записать так:
Некоторый ключи компилятора:
-I"path/to/include" - директория со списком хидеров.
-Wall-Werror - вывод варнингов.
-O1, -O2, -O3 - оптимизация.
Некоторые ключи сборки:
-llibrary - указывает линковшику использовать библиотеку library при сборке программы.
-s - не включает симольные таблицы и информацию о размещении функций в испольняемый файл. Использование этого ключа позволяет существенно ужать исполняемые файлы.
-L"path/to/libs" - директория с библиотеками.
-static - статическая компоновка библиотек.
Больше почитать о Makefile можно здесь: Writing Makefiles
Об опциях компилятора можно почитать здесь.
4 комментария:
# # все o-файлы зависят от cpp-файлов
# .cpp.o:
# gcc -c $^
1. naverno .cpp:.o ?
2. t.e. compilit (-c) obektnie file?
>> 1. naverno .cpp:.o ?
Нет, именно .cpp.o:
Это называется суффиксные правила. Пусть есть make-файл:
#1
mytest: lib.o map.o vector.o
#2
    gcc $^ -o $@
#3
.cpp.o:
#4
    gcc -c $^
#1 означает, что для того, что бы получить mytest, нужно иметь 3 объектных файла (условие, для нормального выполнения комманды #2). Если эти файлы еще не созданны, make ищет, нет ли указания, как их создать. Если явного указания нету (когда объектный файл указан как цель; явное указание более приоритетное, чем суффиксное), то make считает, что объектный файл пожно получить из .c или .cpp файла с таким же именем (lib.o из lib.cpp). #3 показывает, как получить .о из .срр (если используетяс асм, то суффиксное правило будет .s.o и т.д.). По сути, если комманда простая, типа #4, то ее вообще можно не писать, make умный, он сам догадается. Но если необходимо указать, например, что .cpp файлы лежат в какой-то особенно дирректории, то можно создать правило #3.
>> 2. t.e. compilit (-c) obektnie file?
Да, объектные файлы, которые нужны для создания mytest. Выполняется примерно так:
1. Проверяются зависимости #1.
2. Если зависимости не созданы, проверяется #3.
3. Выполняется #4 (создаются объектные файлы).
4. Выполняется #2 (создается mytest).
Добрый день!
имеется Makefile:
____
CMD = cmdA cmdB cmdC
all: msg compile
msg:
@echo "Test msg"
compile:
@for X in $(CMD); do echo "$$X"; done
cmdA: override CMD = cmdA
cmdA: compile
cmdB: override CMD = cmdB
cmdB: compile
cmdC: override CMD = cmdC
cmdC: compile
____
вопрос - как заставить выполниться следующее: "make cmdB cmdA" ("make" - работает и "make cmd" - тоже)?
Отправить комментарий