Self-Documented Makefile
All our projects contain a lengthy Makefile
, to automate installation, build, test, and deployment. Most of the target names are standardized (make install
, make deploy
), but some deserve explanation (make run-dev
, make restart-api
). The more we add fine-grained make targets, the more we need to describe what they do in text form. In our projects, we usually write this doc in the README
file:
But when using the CLI, we prefer self-documenting tools. Wouldn't it better if we could just type make
, and get a list of available commands, together with their desciption?
It turns out it's quite easy to do. First, document each target using a comment placed after the target name, and starting with ##
, as follows:
install: ## Install npm dependencies for the api, admin, and frontend apps
@echo "Installing Node dependencies"
@npm install
install-dev: install ## Install dependencies and prepared development configuration
@./node_modules/.bin/selenium-standalone install
@cp -n ./config/development.js-dist ./config/development.js | true
run-frontend-dev: webpack.PID ## Run the frontend and admin apps in dev (using webpack-dev-server)
webpack.PID:
@./node_modules/.bin/babel-node ./node_modules/.bin/webpack-dev-server \
--content-base=build \
--devtool=cheap-module-inline-source-map \
--hot \
--inline \
--progress \
& echo "$$!" > webpack.PID
stop-frontend-dev: webpack.PID ## Stop the frontend and admin apps in dev
@kill `cat $<` && rm $<
@echo "Webpack server stopped"
restart-frontend: ## Restart the frontend and admin apps in dev
@make stop-frontend-dev && make run-frontend-dev
@echo "Frontend app restarted"
Internal targets (like the webpack.PID
in our example) don't need description, and therefore don't appear in the self-documentation. Next, add a help
target in your makefile
, doing some shell scripting voodoo:
.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
If you copy this code snippet to a makefile
, make sure your text editor converts indentation to tabs and not spaces.
Adjust the width of the first column by changing the 30
value in the printf
pattern to something larger or smaller.
Remove the | sort
to have targets ordered the way they appear in the makefile instead of alphabetically.
This glorious piece of code was written by our collaborator Brice, inspired by various snippets found on the Internet. It uses ANSI codes to color the output, and works both on Linux and OS X.
Final touch: make this help
target the default target:
.DEFAULT_GOAL := help
And you're good to go. make
is one of the oldest CLI task launchers, has plenty of documentation, is extremely powerful, and is installed everywhere. With that trick, it can even replace language-specific task launchers (like npm
or php bin/console
) that provide inline help, but that require installation. By the way, if you like make
tricks, check out that other article of ours where we combine make
and docker
to run commands in containers: make-docker-commands.
Update: This article was featured on the Hacker News home page, so part of the discussion continues there: https://news.ycombinator.com/item?id=11195539.