Self-Documented Makefile V1.1
I like Makefiles: The syntax is quite simple, it's easy to use and it's useful to group commands in one place. In 2016, Marmelab published an article on documenting a Makefile. With some shell script voodoo, you can run make help
and it will print all the available targets and their descriptions. It works and it is simple. I've been using this trick for years and I'm happy with it.
Today I would like to go one step further: Let's improve the help
target so it also outputs the variables and their values. To do so, we can read the internal database thanks to make -p
. This command prints a lot of information: recipes, prerequisites, environment variables, variables and so on.
make -pn hello=there # -n for a dry run
# environment
XAUTHORITY = /run/user/1000/gdm/Xauthority
# environment
GDMSESSION = ubuntu
# environment
XMODIFIERS = @im=ibus
# makefile (from 'Makefile', line 3)
NPROC := 12
# command line
hello = there
# ....
A quick lookup to the output later, I can extract the relevant information with the command, nothing fancy here:
make -pn | awk '/^# (makefile |command)/{getline; print}'
Finally, let's format and print the result. Makefile
looks like this:
.DEFAULT_GOAL = help
NPROC := $(shell nproc)
HOST ?= 127.0.0.1
.PHONY: help
help: ## Show this help
@echo "Variables:"
@make -pnf $(MAKEFILE_LIST) | awk '/^# (makefile |command)/{getline; print}' | grep -v "^MAKEFILE_LIST" | sort | uniq | awk 'BEGIN {FS = ":?= "}; {printf " \033[36m%-30s\033[0m %s\n", $$1, $$2}'
@echo "\nTargets:"
@grep -E '^[/%a-zA-Z0-9_-]+: .*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ": .*?## "}; {printf " \033[36m%-30s\033[0m %s\n", $$1, $$2}'
make help hello=world
Variables:
.DEFAULT_GOAL help
HOST 127.0.0.1
NPROC 8
hello world
Targets:
help Show this help