Makefile ToC
К большому сожалению, несмотря на наличие продвинутых систем сборок, нам всё ещё
приходится использовать утилиту make
и писать Makefile
-ы руками.
Передо мной встала задача по составлению справки по целям сборки в
текущем Makefile
проекта. Из коробки древняя утилита не позволяет получить
список целей сборки и их описание, которого не предполагалось.
Поискав готовые решения и убедившись, что большая часть из них не сработает
на macOS
из-за её родства с BSD
-системами, я принял решение подумать над
собственным вариантом генерации оглавления.
Итак, перед нам две задачи:
- Вызов команды
make
без аргументов выводит список целей сборки и их описание; - Сбор целей и их описаний во всех текущих
Makefile
-ах проекта.
Первая задача решается кросс-системно и довольно легко. Достаточно указать
переменную .DEFAULT_GOAL
в самом начале Makefile
:
.DEFAULT_GOAL := help
Теперь вызов команды make
без аргументов будет вызывать цель help
по
умолчанию:
.DEFAULT_GOAL := help
.PHONY: help
help:
@echo This is help target
Вторая задача оказалась чуть более сложной. Она заключается в том, чтобы собрать имена целей и их описание, затем вывести их в две ровные колонки.
Посмотрев на примеры, я принял решение использовать следующий формат объявления целей сборки:
.PHONY: foo
foo: ## do some foo
@echo foo
Здесь, после двух знаков ##
следует комментарий, который будет выводиться как
справочная информация. Имя цели — описание цели, всё рядом и достаточно удобно.
Теперь необходимо “оживить” команду make help
, чтобы справочная информация
генерировалась динамически.
Вот моё решение:
.PHONY: help
help: ## shows this help message
@grep --fixed-strings --no-filename "##" $(MAKEFILE_LIST) \
| grep -v 'grep --fixed-strings' \
| sed -e 's/:/ /' \
| awk 'BEGIN { FS="#"; } { print $$1 $$3 }' \
| column -t -s $$'\t'
Что здесь происходит? Всё достаточно просто:
- Встроенная переменная
MAKEFILE_LIST
содержит список путей ко всем файламMakefile
проекта; - С помощью команды
grep
находятся все строки, содержащие в себе два символа##
, которые будут использоваться для добалвения комментария к цели сборки; - Далее,
sed
подменяет символ:
на символ табуляции; - Самая главная роль отводится команде
awk
, которая принимает на себя вывод используя разделитель полей#
(переменнаяFS
) и выводит имена целей сборки и комментарии к ним последовательно; - За аккуратный вывод в две ровные колонки отвечает команда
column
.
Ознакомьтесь с демонстрационным примером такого Makefile
:
.DEFAULT_GOAL := help
.PHONY: help
help: ## shows this help message
@grep --fixed-strings --no-filename "##" $(MAKEFILE_LIST) \
| grep -v 'grep --fixed-strings' \
| sed -e 's/:/ /' \
| awk 'BEGIN { FS="#"; } { print $$1 $$3 }' \
| column -t -s $$'\t'
.PHONY: foo
foo: ## do some foo
@echo foo
.PHONY: bar
bar: ## do some bar
@echo bar
.PHONY: some-long-named-makefile-target
some-long-named-makefile-target: ## this is some-long-named-makefile-target
@echo some-long-named-makefile-target
.PHONY: ignored
ignored:
@echo ignored
А вот вывод команды make
без аргументов:
$ make
help shows this help message
foo do some foo
bar do some bar
some-long-named-makefile-target this is some-long-named-makefile-target
Аккуратно, не правда ли?
Тем не менее, допускаю, что решение получилось далеко не самым переносимым между
разными версиями make
и операционными системами. Поэтому, если у вас есть
возможность, старайтесь избегать устаревших систем сборок.