5.2 KiB
title, description, position, category
title | description | position | category |
---|---|---|---|
Makefiles для чайников. | Автоматизируем по старинке. | 1 | DevOps |
Makefiles для чайников
Если описывать в двух словах, то это просто описание команд для упрощения работы с проектом. Изначально делались для того, чтобы удобно компилировать всякие проекты на любых языках.
Как они работают
Достаточно просто.
Вот пример Makefile
:
# Сгенерируем простой файл
test.gen:
@echo 'echo "Hi!"' > "test.gen"
# Команда для запуска файла test.gen
.PHONY: run
run: test.gen
sh "test.gen"
До двоеточий обазначены команды (tagets). Например тут это: test.gen
и run
.
Данные таргеты можно запускать через make ${target}
.
Например, если ввести make run
в папке с Makefile
, то мы получим следующее:
$ sh "test.gen"
Hi!
Как видно из выхлопа данной команды, у нас успешно запустился файл test.gen
, хотя мы не запускали команду make test.gen
. Что произошло? Давайте разбираться.
Зависимости таргетов
На строчке объявления таргета run
видно, что объявлен test.gen
. Это зависимость данного таргета и она будет вызвана до того, как выполнится скрипт описываемого таргета. Таких зависимостей может быть много, перечисляются они чере пробел.
Например:
.PHONY: target1
target1:
echo "1"
.PHONY: target2
target2: target1
echo "2"
.PHONY: target3
target3: target1 target2
echo "memes"
При вызове make target3
будет выведено:
$ make target3
echo "1"
1
echo "2"
2
echo "memes"
memes
Как можно видеть, он построил граф зависимостей и не выполнил target1
дважды.
Сокрытие вывода команд
В предыдущем примере можно заметить, что он написал все команды в терминал. Для того, чтобы этого избежать следует добавить "@" в начало команды и она не будет напечатана.
.PHONY: target1
target1:
@echo "1"
.PHONY: target2
target2: target1
@echo "2"
.PHONY: target3
target3: target1 target2
@echo "memes"
Теперь при вызое make target3
будет показано следующее:
$ make target3
1
2
memes
Валидация сгенерированных файлов
Зачастую Makefile
используют для компиляции С и зачастую требуется
собрать какую-либо часть проект и пропустить сборку этой части, если эта часть уже собрана.
Раскрою секрет, в Makefile это базовый функционал.
Давайте немного поменяем первый Makefile и запустим дважды.
# Сгенерируем простой файл
test.gen:
echo 'echo "Hi!"' > "test.gen"
# Команда для запуска файла test.gen
.PHONY: run
run: test.gen
sh "test.gen"
Теперь вызываемая команда таргета test.gen
выводится на экран.
Позапускаем.
$ make run
echo 'echo "Hi!"' > "test.gen" # Наша командабыла вызвана.
sh "test.gen"
Hi!
$ make run
sh "test.gen" # Наша команда не вызвана.
Hi!
Дело в том, что названия таргетов - названия файлов, которые должны сгенерировать эти самые таргеты.
То есть, в данном случае таргет test.gen
должен сгенерировать файл test.gen
по окончании выполнения. Если этот файл уже присутствует, то команда выполнена не будет. Именно поэтому у нас она не запустилась второй раз, так как в первый запуск был создан треубемый файл и его никто не удалял между запусками.
А что если я вот не хочу чтобы команда создавала и проверяла файлы?
Для этого пишут .PHONY: ${target}
. Например у нас так объявлен таргет run
и, даже если файл с названием run
будет присутствовать в директории цель не будет выполняться.