CTO and co-founder of Signal Sciences. Author and speaker on software engineering, devops, and security.

Self-Documenting Makefiles

Automatically have "make help" print the usage of your Makefile.

Makefiles are making a come-back due to wide use in the golang community. The only problem is... what do they do? Reading a makefile can be hard -- it's often ugly and many of targets are for internal use only. And unlike a good CLI program, there is no equivalent of --help.

Wouldn't it be great if you could mark-up the makefile and have make help automatically produce a usage description?

I first read how to do this at the Marme Lab Blog in Self-Documented Makefile. There was a follow-up in Hacker News, and buried near the bottom, m6w6 posted an even better version:

# https://www.client9.com/self-documenting-makefiles/
        @awk -F ':|##' '/^[^\t].+?:.*?##/ {\
        printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \
        }' $(MAKEFILE_LIST)

Add this to the bottom of your makefile (and be sure to replace leading spaces with a tab). Or as a one-liner in bash:

@awk -F ':|##' '/^[^\t].+?:.*?##/ {printf "\033[36m%-30s\033[0m %s\n", $1, $NF}' Makefile

Geez, in one line, you got makefile stuff, awk stuff, regular expressions, printf formats and terminal colors. Understanding this might be hard, but using it is very easy. Just document your targets on the same line using a ## comment:

build: ## build but do not install
        go build .
install: ## install command
        go install .
lint: ## run linters
        gometalinter ...
clean:  ## cleanup
        go clean ./..

And try it out:

$ make help
build               build but do not install
install             install command
lint                run linters
clean               cleanup

If you want sorted output, by all means add a |sort to the end of the help target.

I've seen some other solutions to add documentation to Makefiles. One involved wrapping make with another program. I was tempted to have make help call a golang program that would parse the Makefile to generate help. But this awk trick is by far the best, as it will work out of the box on just about every system. I've tested on macOS, linux, and Alpine Linux with busybox awk.

Thank you MarmeLab and m6w6 for this gift.

© 2018 Nick Galbreath