Make в 21-вом веке

Все современные фреймворки и языки программирования обладают отличной экосистемой: cargo у языка rust; manage.py у фреймворка django; go нужна только одна команда. Все это избавляет от необходимости использовать сторонние тулзы. Но есть инструмент от которого я не могу отказаться - make. Созданный еще в 70-х как инструмент сборки, он до сих пор остается чрезвычайно полезным инструментом в любом проекте.

Краткое введение

Все что нужно для запуска make это файл Makefile. В нем описываются правила по шаблону:

target: prerequisites
    recipe

Где:

Следуя этим правилам make будет собирать что-то, если это нужно собирать. По умолчанию target является именем файла, который будет создан по окончанию выполнения блока recipe. make отслеживает prerequisites, если они были изменены с последнего запуска, то target будет заново собрана, а иначе make не предпринимает ни каких действий.

Рассмотрим простой пример Makefile:

foo: bar
	echo "foo" > foo

bar:
	echo "bar" > bar

Если просто запустить make, он выполнит первое правило из возможных т.е. foo.

$ make
echo "bar" > bar
echo "foo" > foo

Но так как правило имеет предпосылки, то сначала будет выполнено правило bar, а лишь затем foo.

Если запустить make еще раз, то программа сообщает, что файлы bar и foo уже созданы и делать ничего не нужно.

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

$ make bar

Синтаксис Makefile очень богат. Позволяет создавать переменные:

MY_FILE := foo
$(MY_FILE):
	echo "foo" > $(MY_FILE)

Помечать правила по результатам которых не создается файла, это особенно полезно при запуске тестов или линтеров:

.PHONY: foo
foo:
	echo "foo"

Указывать правило по-умоланию:

.DEFAULT_GOAL := foo
.PHONY: foo
foo:
	echo "foo"

И еще много чего.

Зачем мне make?

Возьмем go, любой разработчик на этом языке может сказать “Зачем мне make? Тесты я могу запускать go test, устанавливать через go install и тд “.

В данном случае make нужно рассматривать как инструмент оптимизации временных затрат. Предположим нужно собрать версию приложения для linux, а вы работаете на macos, очень утомительно писать каждый раз: GOOS=linux GOARCH=amd64 go build -o builds/app-linux-amd64. А если нужно собрать приложение сразу под все платформы? Согласитесь make release выглядит более продуктивно.

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

Заключение

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