У вас, вероятно, появился вопрос: можно ли не компилировать эти файлы по отдельности, а собрать сразу всю программу одной командой? Можно.

gcc calculate.c main.c -o kalkul -lm

Вы скажете, что это удобно? Удобно для нашей программы, потому что она состоит всего из двух c-файлов. Однако профессиональная программа может состоять из нескольких десятков таких файлов. Каждый раз набирать названия их всех в одной строке было бы делом чрезмерно утомительным. Но есть возможность решить эту проблему. Названия всех исходных файлов и все команды для сборки программы можно поместить в отдельный текстовый файл. А потом считывать их оттуда одной короткой командой.

Давайте создадим такой текстовый файл и воспользуемся им. В каталоге проекта kalkul2 удалите все файлы, кроме calculate.h, calculate.c, main.c. Затем создайте в этом же каталоге новый файл, назовите его Makefile (без расширений). Поместите туда следующий текст.

Kalkul: calculate.o main.o gcc calculate.o main.o -o kalkul -lm calculate.o: calculate.c calculate.h gcc -c calculate.c main.o: main.c calculate.h gcc -c main.c clean: rm -f kalkul calculate.o main.o install: cp kalkul /usr/local/bin/kalkul uninstall: rm -f /usr/local/bin/kalkul

Обратите внимание на строки, введённые с отступом от левого края. Этот отступ получен с помощью клавиши Tab. Только так его и надо делать! Если будете использовать клавишу «Пробел», команды не будут исполняться.

Затем дадим команду, состоящую всего из одного слова:

И сразу же в нашем проекте появляются и объектные файлы и запускаемый. Программа make как раз и предназначена для интерпретации команд, находящихся в файле со стандартным названием Makefile. Рассмотрим его структуру.

Makefile является списком правил. Каждое правило начинается с указателя, называемого «Цель». После него стоит двоеточие, а далее через пробел указываются зависимости. В нашем случае ясно, что конечный файл kalkul зависит от объектных файлов calculate.o и main.o. Поэтому они должны быть собраны прежде сборки kalkul. После зависимостей пишутся команды. Каждая команда должна находиться на отдельной строке, и отделяться от начала строки клавишей Tab. Структура правила Makefile может быть очень сложной. Там могут присутствовать переменные, конструкции ветвления, цикла. Этот вопрос требует отдельного подробного изучения.

Если мы посмотрим на три первых правила, то они нам хорошо понятны. Там те же самые команды, которыми мы уже пользовались. А что же означают правила clean, install и uninstall?

В правиле clean стоит команда rm, удаляющая исполняемый и объектные файлы. Флаг -f означает, что, если удаляемый файл отсутствует, программа должна это проигнорировать, не выдавая никаких сообщений. Итак, правило clean предназначено для «очистки» проекта, приведения его к такому состоянию, в каком он был до команды make.

Запустите

Появились объектные файлы и исполняемый. Теперь

Объектные и исполняемый файлы исчезли. Остались только c-файлы, h-файл и сам Makefile. То есть, проект «очистился» от результатов команды make.

Правило install помещает исполняемый файл в каталог /usr/local/bin - стандартный каталог размещения пользовательских программ. Это значит, что её можно будет вызывать из любого места простым набором её имени. Но помещать что-либо в этот каталог можно только, зайдя в систему под «суперпользователем». Для этого надо дать команду su и набрать пароль «суперпользователя». В противном случае система укажет, что вам отказано в доступе. Выход из «суперпользователя» осуществляется командой exit. Итак,

Теперь вы можете запустить это программу просто, введя имя программы, без прописывания пути.

Можете открыть каталог /usr/local/bin. Там должен появиться файл с названием kalkul.

Давайте теперь «уберём за собой», не будем засорять систему.

Посмотритекаталог /usr/local/bin. Файл kalkul исчез. Итак, правило uninstall удаляет программу из системного каталога.

Дмитрий Пантелеичев (dimanix2006 at rambler dot ru) - Make-файлы

Утилита автоматически определяет, какие части большой программы должны быть перекомпилированы и команды для их перекомпиляции. Наиболее часто make используется для компиляции C-программ и содержит особенности ориентированные именно на такие задачи, но можно использовать make с любым языком программирования. Более того, применение утилиты make не ограничивается программами. Можно использовать еe для описания любой задачи, где некоторые файлы должны автоматически порождаться из других всегда, когда те изменяются.

make-file

Прежде чем использовать make , необходимо создать файл, называемый make-файлом , который описывает отношения между файлами Вашей программы и содержит команды для обновления каждого файла. Обычно исполняемый файл зависит от объектных файлов, которые, в свою очередь, зависят от исходных файлов и файлов заголовков. Для имени make-файла рекомендуется название GNUmakefile , makefile или Makefile , причем поиск идет именно в указанном порядке. Если необходимо использовать нестандартное имя, то его можно передать явно через опцию -f .
Когда make-файл уже написан, достаточно выполнить в каталоге в котором он находится команду make . Простой make-файл состоит из правил(инструкций) следующего вида:


ПЕРЕМЕННАЯ = ЗНАЧЕНИЕ...
ЦЕЛЬ... : ЗАВИСИМОСТЬ...
КОМАНДА 1
КОМАНДА 2
ПЕРЕМЕННАЯ = ЗНАЧЕНИЕ...
ЦЕЛЬ... : ЗАВИСИМОСТЬ...
КОМАНДА 1
КОМАНДА 2

и т.д.

ЦЕЛЬ обычно представляет собой имя файла, генерируемого программой make ; примерами целей являются исполняемые или объектные файлы. Цель может также быть именем выполняемого действия, как, например, "clean ".
ЗАВИСИМОСТЬ - это файл, изменение которого служит признаком необходимости цели. Часто цель зависит от нескольких файлов.
КОМАНДА - это действие, которое выполняет make . Правило может иметь более чем одну команду - каждую на своей собственной строке. Важное замечание: необходимо начинать каждую строку, содержащую команды, с символа табуляции. Длинные строки разбиваются на несколько с использованием обратного слэша, за которым следует перевод строки. Знак диез # является началом комментария. Строка с # до конца игнорируется. Комментарии могут переноситься на несколько строк с помощью обратного слэша в конце строки.

Пример makefile

Использование действий по умолчанию


#default target - file edit
edit: main.o kbd.o command.o display.o \
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.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
insert.o: insert.c defs.h buffer.h
cc -c insert.c
search.o: search.c defs.h buffer.h
cc -c search.c
files.o: files.c defs.h buffer.h command.h
cc -c files.c
utils.o: utils.c defs.h
cc -c utils.c
clean:
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

По умолчанию, make начинает с первого правила (не считая правил, имена целей у которых начинаются с ". "). Это называется главной целью по умолчанию. В нашем случае это правило edit . Если файл edit новее чем объектные файлы от которых он зависит, то ничего не произойдет. В противном случае, прежде чем make сможет полностью обработать это правило, он должен рекурсивно обработать правила для файлов, от которых зависит "edit ". Каждый из этих файлов обрабатывается в соответствии со своими собственным правилом. Перекомпиляция должна быть проведена, если исходный файл или любой из заголовочных файлов, упомянутых среди зависимостей, обновлен позднее, чем объектный файл, или если объектный файл не существует.
Правилу clean не соответствует никакого создаваемого файла и, соответственно, clean ни от чего не зависит и само не входит в список зависимостей. При запуске по умолчанию clean вызываться не будет. Для его выполнения необходимо явно указать цель при запуске make - make clean.
Для сокращения записи можно использовать переменные и действия по умолчанию (неявные правила)

Специальная цель .PHONY является встроенной в make и определяет свои зависимости как цели-имена, которым нет соответствия в виде файлов. Если данное правило пропустить, то создание в текущем каталоге файла с именем clean заблокирует выполнение make clean .
Использование правил по умолчанию позволяет изменить стиль записей зависимостей:

Квадратные скобки означают необязательность присутствия данной части.
Цель - имя цели, которую надо выполнить.
Переменная ="abc" -переопределение переменных. Значения переменных введенных в командной строке имеют больший приоритет, чем определения в make-файле.
Опции:
-f file - явное задание имени make-файла , если задание опущено, то ищются файлы GNUmakefile , makefile или Makefile
-n ; - имитация действий без реального выполнения, служит для отладки
-t - изменение времени модификации цели без реального выполнения
-q - проверка на необходимость обновления цели без реального выполнения

Утилита make предназначена для автоматизации сборки проектов. Если какие-либо файлы проекта могут быть сгенерированы из других файлов, утилита позволяет выполнить процесс построения наиболее оптимальным способом, по возможности минимизируя количество обрабатываемых файлов.

Исторически утилита предназначалась для сборки проектов на языке C в операционной системе Unix, однако может быть использоваться для работы с любыми проектами. Первая версия системы была создана в 1977 году.

На сегодняшний день наиболее распространены три варианта утилиты, объединенные общими принципами работы, но отличающиеся синтаксисом языка и возможностями:

    GNU make - самый распространенный и функциональный вариант

    BSD make (pmake) - используется в проектах BSD, по функциональности примерно соответствует GNU make

    nmake (Microsoft make) - работает под Windows, малофункционален, только базовые принципы make.

Мы работаем с GNU make. На BSD системах (в частности, FreeBSD, он может быть доступен как gmake, на Linux - просто make).

Основные принципы

Утилита make работает по правилам (rules) , записанным в специальном конфигурационном файле. Правила определяют цели (targets) , завимости между целями и набор команд для выполнения каждой цели.

Цели могут соответствовать определенным файлам. Кроме того, цели могут не соответствовать ни одному файлу и использоваться для группировки других целей или определенной последовательности команд. Такие цели называются phony targets.

Каждая цель может зависеть от выполнения других целей. Выполнение цели требует предварительного выполнения других целей, от которых она зависит.

В случае зависимости между целями, соответствующими файлам, цель выполняется только в том случае, если файлы, от которых она зависит, новее, чем файл, соответствующий цели. Это позволяет перегенерировать только файлы, зависящие от измененных файлов, и не выполнять потенциально долгий процесс пересборки всех файлов проекта.

Таким образом, makefile определяет граф зависимостей, по которому утилита make выполняет ту или иную цель, по возможности минимизируя количество операций сборки.

Запуск make

Несмотря на то, что для make можно указать произвольный файл правил, как правило используют стандартное имя Makefile . Поддерживаются также несколько альтернативных имен по умолчанию, но имеет смысл использовать наиболее распространенное.

Соответственно, команда

$ make

будет использовать файл Makefile , находящийся в текущем каталоге.

При запуске make можно указать цель, которая будет выполнена. Если цель не указана, используется цель по умолчанию, которая либо указана в файле правил явно, либо неявно используется первая определенная цель.

Явное указание цели выполняется инструкцией DEFAULT_GOAL в Makefile:

. DEFAULT_GOAL: all

Например, команда

$ make clean

вызовет обработку цели clean файла Makefile , находящегося в текущем каталоге.

Можно указать сразу несколько целей.

Выполнение целей может быть настроено с использованием переменных (о которых ниже). При запуске make можно указать значения переменных:

$ make build PREFIX =/ usr/ local

Значение переменной PREFIX будет доступно в правилах Makefile и может быть использовано при сборке.

Команда поддерживает также ряд дополнительных опций, из которых наиболее важные следующие:

    F - позволяет явно указать файл правил

    C - переходит в указанный каталог перед выполнением, может быть, например, использована для запуска make из внешнего каталога по отношению к каталогу проекта

    B - отключает проверку времени зависимых целей и принудительно выполняет их полностью

Базовый синтаксис make

Основная конструкция, используемая в файлах make , выглядит следующим образом:

Target: dep1 dep2 ... command1 command2 ...

    target - цель

    dep1 , dep2 - цели, от которых зависит цель target

    command1 , command2 - команды, выполняемые для достижения цели target

Например:

Style. css: src/ less/ app. less lessc src/ less/ app. less > style. css

Этот фрагмент определяет, что файл style.css зависит от файла src/less/app.less и для его сборки необходимо выполнить команду lessc src/less/app.less > style.css . Перегенерация файла style.css будет выполняться только в случае,если файл src/less/app.less новее, чем файл style.css (до тех пор, пока при запуске make не будет указан ключ -B).

Перед каждой командой внутри описания цели должен присутствовать символ табуляции. В принципе, это настраивается, но лучше использовать общепринятые соглашения. Если вместо табуляции используются пробелы, make работать не будет.

В качестве команд обработки целей используются команды shell. Текст команды выводится, для того, чтобы он не выводился, команду необходимо начать с символа @ .

Каждая команда запускается в отдельном интерпретаторе shell, таким образом, команды не связаны друг с другом. Иначе говоря, одна строка команды - один shell. Это поведение может быть переопределено с помощью специальной цели.ONESHELL .

Если команду (или список зависимостей) необходимо записать в несколько строк, используют символ переноса \ .

PHONY targets

Цели, не соответствующие файлам, и предназначенные для выполнения набора команд или группировки завимостей, декларируются следующим образом:

.PHONY : clean clean: rm *. o temp

Деклараций.PHONY может быть несколько, обычно определяют одну и прописывают туда все соответствующие цели.

В нашем примере вызов make clean приведет к выполнению цели clean , которая безусловно выполнит удаление временных файлов.

В случае, если у phony target есть зависимость в виде другой phony target, то зависимость выполняется перед зависящей целью. Таким образом, мы получаем механизм, напоминающий подпрограммы. Например, мы можем определить цель all , собирающую все файлы проекта, и отдельные цели css , js и php , собирающие отдельной css -файлы, js -файлы и обрабатывающие php файлы.

Соответственно, в Makefile мы можем написать:

.PHONY : all css js php all: css js php css: www/ style. css ... тут команды js: www/ js/ app. js ... тут еще команды php: ... тут снова команды

В результате мы можем использовать make all для пересборки всех файлов и, скажем, make css для пересборки только CSS -файлов.

Переменные

В make-файле можно использовать переменные, хотя правильнее сказать, что можно использовать макросы.

Переменные определяются присваиванием в makefile или могут быть переданы извне.

Переменные - это макроопределения, причем вычисление переменной всегда выполняется в самый последний момент перед подстановкой. Макросы могут использовать везде в тексте makefile.

СС= gcc IDIR=../ include CFLAGS=- I$ (IDIR ) DEPS= hellomake. o hellofunc. p NAME= hellomake $ (NAME ) : $ (DEPS ) $ (CC ) - o $ (NAME ) $ (DEPS )

Подстановка выполняется конструкцией $(VAR) в отличие от shell, где используется $VAR .

Если в shell команде используется shell-переменная, необходимо квотить знак $ , дублируя его, например:

Printhome: echo $$ HOME

Помимо макропеременных существуют и более традиционные, в которых значение устанавливается сразу. Для работы с ними используется оператор:= . В наших условиях достаточно использовать обычные переменные.

Часто требуется определить переменную только в том случае, если она еще не была определена. Для этого используется оператор?= :

MYSQL_CHARSET ?= UTF8

Соответственно, если мы вызовем

make create-database

будет использована кодировка UTF8 , а в случае

Make create- database MYSQL_CHARSET= CP1251

будет использована CP1251 .

Если переменная содержит несколько строк, можно использовать синтаксис define:

Define MYSQL_APP_CONF_TEMPLATE [ mysql] host=$ (MYSQL_SERVER ) port=$ (MYSQL_PORT ) user=$ (MYSQL_USER ) password= "$(MYSQL_PASSWORD)" endef

Автоматические переменные

Make поддерживает набор автоматических переменных, облегчающих написание правил. Например, переменная $@ соответствую текущей цели (то, что слева от:), а переменная $^ - списку зависимостей (то, что справа от:). Таким образом, например, можно написать:

Www/ js/ script. js: src/ js/ jquery. js src/ js/ plugin1. js src/ js/ plugin2. js cat $^ > $@

В результате www/js/script.js будет результатом объединения трех js-файлов.

Полный список таких переменных приведен в документации, для нас наиболее интересны:

    $@ - имя цели

    $< - имя первой зависимости

    $? - имена всех зависимостей, которые новее чем цель

    $^ - имена всех зависимостей цели

С полным списком можно ознакомиться в документации: Automatic Variables .

Условное выполнение

В Makefile можно использовать условные выражения. Опять же, мы говорим о макрообработке make, соответственно, условные выражения работают на уровне makefile, а не на уровне команд. Обычно условные выражения используются для определения тех или иных целей в зависимости от значения переменных. Например:

ifdef $ (APP ) setup: ... else setup: @ echo "Error, applications is not defined" endif

В качестве условий можно проверять определенность переменной, а также ее значение:

Foo: $ (objects ) ifeq ($ (CC ) , gcc) $ (CC ) - o foo $ (objects ) $ (libs_for_gcc ) else $ (CC ) - o foo $ (objects ) $ (normal_libs ) endif

Полностью с возможностями условных выражений можно ознакомиться в документации: Conditional syntax .

Шаблонные правила

Шаблонные правила (pattern rules) позволяют указать правило преобразования одних файлов в другие на основании зависимостей между их именами. Например, мы можем указать правило для получения объектного файла из файла на языке C:

%. o: %. c $ (CC ) $< - o $@

Обратите внимание на использование переменной %< , которая в таких правилах используется для получения имени исходного файла.

Шаблоны не обязаны ограничиваться расширениями файлов. Если исходные и выходные файлы соответствуют друг другу и в их именах есть какая-либо зависимость, можно использовать pattern rule.

Включение других файлов make

Файл make может подключить другие файлы make оператором include:

include make1. mk make2. mk

Таким образом, из файлов можно строить модульную систему, часто имеет смысл выполнять include внутри условного оператора.

Функции

Make определяет большой набор функций, которые могут быть использованы в переменных (макросах). Вызов функции выполняется конструкцией:

$ (function arg1, arg2,... )

Функции позволяют обрабатывать строки, имена файлов, организовывать циклы по набору значений, организовывать условный вызов других функций.

Несколько примеров из hive. Получаем текущее время (обратите внимание на использование:= :

HIVE_TIME := $ (shell date +% Y/% m/% d\ % H:% M:% S)

Включение файла container.mk только в случае, если он существует:

include $ (shell find $ (HIVE_ETC_DIR ) - name container. mk)

Формирование имени MySQL базы по имени проекта:

MYSQL_DB ?= $ (subst -, _,$ (HIVE_NAME ) _$ (APP ) )

Добавление префиксов и суффиксов к именам файлов

$ (addprefix src/ less/,$ (addsuffix . less, app ui catalog) )

Подробнее о функциях можно прочитать в документации Functions .

Собственные функции

Можно создавать собственные параметризованные функции путем определения переменных, содержащих специальные переменные $1 , $2 , ..., соответствующие переданным аргументам. Вызов пользовательской функции производится специальным макросом call:

$ (call variable, param, param,... )

Очень тупой пример:

Hive_red = "\0 33 1. To cause to … The Collaborative International Dictionary of English

make - make1 vt. made, making 1. to bring into being; specif., a) to form by shaping or… … English World dictionary

Make - (engl. machen, erstellen) ist ein Computerprogramm, das Shellskript ähnlich Kommandos in Abhängigkeit von Bedingungen ausführt. Es wird hauptsächlich bei der Softwareentwicklung eingesetzt. Genutzt wird es beispielsweise, um in einem Projekt, das … Deutsch Wikipedia

Make - Cet article a pour sujet le logiciel intitulé make. Pour une définition du mot « make », voir l’article make du Wiktionnaire. make est un logiciel traditionnel d UNIX. C est un « moteur de production »: il sert à appeler … Wikipédia en Français

make - (engl. machen, erstellen) ist ein Computerprogramm, das Kommandos in Abhängigkeit von Bedingungen ausführt. Es wird hauptsächlich bei der Softwareentwicklung als Programmierwerkzeug eingesetzt. Genutzt wird es beispielsweise, um in Projekten, die … Deutsch Wikipedia

Написание makefile иногда становится головной болью. Однако, если разобраться, все становится на свои места, и написать мощнейший makefile длиной в 40 строк для сколь угодно большого проекта получается быстро и элегантно.

Внимание! Предполагаются базовые знания утилиты GNU make.

Имеем некий типичный абстрактный проект со следующей структурой каталогов:

Пусть для включения заголовочных файлов в исходниках используется что-то типа #include , то есть каталог project/include делается стандартным при компиляции.

После сборки надо, чтобы получилось так:

То есть, в каталоге bin лежат рабочая (application) и отладочная (application_debug) версии, в подкаталогах Release и Debug каталога project/obj повторяется структура каталога project/src с соответствующими исходниками объектных файлов, из которых и компонуется содержимое каталога bin.

Чтобы достичь данного эффекта, создаем в каталоге project файл Makefile следующего содержания:

  1. root_include_dir:= include
  2. root_source_dir:= src
  3. source_subdirs:= . dir1 dir2
  4. compile_flags:= -Wall -MD -pipe
  5. link_flags:= -s -pipe
  6. libraries:= -ldl
  7. relative_include_dirs:= $(addprefix ../ ../ , $(root_include_dir) )
  8. relative_source_dirs:= $(addprefix ../ ../ $(root_source_dir) / , $(source_subdirs) )
  9. objects_dirs:= $(addprefix $(root_source_dir) / , $(source_subdirs) )
  10. objects:= $(patsubst ../ ../% , % , $(wildcard $(addsuffix /* .c* , $(relative_source_dirs) ) ) )
  11. objects:= $(objects:.cpp=.o)
  12. objects:= $(objects:.c=.o)
  13. all: $(program_name)
  14. $(program_name) : obj_dirs $(objects)
  15. g++ -o $@ $(objects) $(link_flags) $(libraries)
  16. obj_dirs:
  17. mkdir -p $(objects_dirs)
  18. VPATH:= ../ ../
  19. % .o: % .cpp
  20. g++ -o $@ -c $< $(compile_flags) $(build_flags) $(addprefix -I, $(relative_include_dirs) )
  21. % .o: % .c
  22. g++ -o $@ -c $< $(compile_flags) $(build_flags) $(addprefix -I, $(relative_include_dirs) )
  23. .PHONY: clean
  24. clean:
  25. rm -rf bin obj
  26. include $(wildcard $(addsuffix /* .d, $(objects_dirs) ) )

В чистом виде такой makefile полезен только для достижения цели clean, что приведет к удалению каталогов bin и obj.
Добавим еще один сценарий с именем Release для сборки рабочей версии:

Mkdir -p bin mkdir -p obj mkdir -p obj/Release make --directory=./obj/Release --makefile=../../Makefile build_flags="-O2 -fomit-frame-pointer" program_name=../../bin/application

И еще один сценарий Debug для сборки отладочной версии:

Mkdir -p bin mkdir -p obj mkdir -p obj/Debug make --directory=./obj/Debug --makefile=../../Makefile build_flags="-O0 -g3 -D_DEBUG" program_name=../../bin/application_debug

Именно вызов одного из них соберет наш проект в рабочем, либо отладочном варианте. А теперь, обо всем по-порядку.

Допустим, надо собрать отладочную версию. Переходим в каталог project и вызываем./Debug. В первых трех строках создаются каталоги. В четвертой строке утилите make сообщается, что текущим каталогом при запуске надо сделать project/obj/Debug, относительно этого далее передается путь к makefile и задаются две константы: build_flags (тут перечисляются важные для отладочной версии флаги компиляции) и program_name (для отладочной версии – это application_debug).

1: Объявляется переменная с именем корневого каталога заголовочных файлов.

2: Объявляется переменная с именем корневого каталога исходников.

3: Объявляются переменная с именами подкаталогов корневого каталога исходников.

4: Объявляется переменная с общими флагами компиляции. -MD заставляет компилятор сгенерировать к каждому исходнику одноименный файл зависимостей с расширением.d. Каждый такой файл выглядит как правило, где целью является имя исходника, а зависимостями – все исходники и заголовочные файлы, которые он включает директивой #include. Флаг -pipe заставляет компилятор пользоваться IPC вместо файловой системы, что несколько ускоряет компиляцию.

5: Объявляется переменная с общими флагами компоновки. -s заставляет компоновщик удалить из результирующего ELF файла секции.symtab, .strtab и еще кучу секций с именами типа.debug*, что значительно уменшает его размер. В целях более качественно отладки этот ключ можно убрать.

6: Объявляется переменная с именами используемых библиотек в виде ключей компоновки.

8: Объявляется переменная, содержащая относительные имена каталогов со стандартными заголовочными файлами. Потом такие имена напрямую передаются компилятору, предваряемые ключем -I. Для нашего случая получится../../include, потому что такой каталог у нас один. Функция addprefix добавляет свой первый аргумент ко всем целям, которые задает второй аргумент.

9: Объявляется переменная, содержащая относительные имена всех подкаталогов корневого каталога исходников. В итоге получим: ../../src/. ../../src/dir1 ../../src/dir1.

10: Объявляется переменная, содержащая имена подкаталогов каталога project/obj/Debug/src относительно текущего project/obj/Debug. То есть, этим мы перечисляем копию структуры каталога project/src. В итоге получим: /src/dir1 src/dir2.

11: Объявляется переменная, содержащая имена исходников, найденных на основе одноименных файлов *.c* (.cpp\.c), безотносительно текущего каталога. Смотрим поэтапно: результатом addsuffix будет../../src/./*.с* ../../src/dir1/*.с* ../../src/dir2/*.с*. Функция wildcard развернет шаблоны со звездочками до реальных имен файлов: ../../src/./main.сpp ../../src/dir1/file1.с../../src/dir1/file2.сpp ../../src/dir2/file3.с../../src/dir2/file4.с. Функция patsubsb уберет префикс../../ у имен файлов (она заменяет шаблон, заданный первым аргументом на шаблон во втором аргументе, а % обозначает любое количество символов). В итоге получим: src/./main.сpp src/dir1/file1.с src/dir1/file2.сpp src/dir2/file3.с src/dir2/file4.с.

12: В переменной с именами исходников расширения.cpp заменяется на.o.

13: В переменной с именами исходников расширения.c заменяется на.o.

15: Первое объявленное правило – его цель становится целью всего проекта. Зависимостью является константа, содержащая имя программы (../../bin/application_debug мы ее передали при запуске make из сценария).

17: Описание ключевой цели. Зависимоcти тоже очевидны: наличие созданных подкаталого в project/obj/Debug, повторяющих структуру каталога project/src и множество объектных файлов в них.

18: Описано действие по компоновке объектных файлов в целевой.

20: Правило, в котором цель – каталог project/obj/Debug/src и его подкаталоги.

21: Действие по достижению цели – создать соответствующие каталоги src/., src/dir1 и src/dir2. Ключ -p утилиты mkdir игнорирует ошибку, если при создании какого-либо каталога, таковой уже существуют.

23: Переменная VPATH принимает значение../../. Это необходимо для шаблонов нижеследующих правил.

25: Описывается множество правил, для которых целями являются любые цели, соответствующие шаблону %.o (то есть имена которых оканчиваются на.o), а зависимостями для этих целей являются одноименные цели, соответствующие шаблону %.cpp (то есть имена которых оканчиваются на.cpp). При этом под одноименностью понимается не только точное совпадение, но также если имя зависимости предварено содержимым переменной VPATH. Например, имена src/dir1/file2 и../../src/dir1/file2 совпадут, так как VPATH содержит../../.

26: Вызов компилятора для превращения исходника на языке С++ в объектный файл.

28: Описывается множество правил, для которых целями являются любые цели, соответствующие шаблону %.o (то есть имена которых оканчиваются на.o), а зависимостями для этих целей являются одноименные цели, соответствующие шаблону %.c (то есть имена которых оканчиваются на.c). Одноименность как в строке 23.

29: Вызов компилятора для превращения исходника на языке С в объектный файл.

31: Некоторая цель clean объявлена абстрактной. Достижение абстрактной цели происходит всегда и не зависит от существования одноименного файла.

32: Объявление абстрактной цели clean.

33: Действие по ее достижению заключается в уничтожении каталогов project/bin и project/obj со всем их содержимым.

36: Включение содержимого всех файлов зависимостей (с расширением.d), находящихся в подкаталогах текущего каталога. Данное действие утилита make делает в начале разбора makefile. Однако, файлы зависимостей создаются только послекомпиляции. Значит, при первой сборке ни один такой файл включен не будет. Но это не страшно. Цель включения этих файлов – вызвать перекомпиляцию исходников, зависящих от модифицированного заголовочного файла. При второй и последующих сборках утилита make будет включать правила, описанные во всех файлах зависимостей, и, при необходимости, достигать все цели, зависимые от модифицированного заголовочного файла.