Self-documented Makefile

Problem
Documenting the commands in a Makefile is usually achieved by creating another make recipe (often named “help”) which prints the documentation of each target/command in the following fashion:

help:
    @echo 'Makefile for a pelican Web site                         '
    @echo '                                                        '
    @echo 'Usage:                                                  '
    @echo '   make html         (re)generate the web site          '
    @echo '   make clean        remove the generated files         '
    @echo '   make regenerate   regenerate files upon modification '

html:
    echo "This command (re)generates thee web site"

clean:
    echo "This command removes the generated files"

regenerate: clean
    echo "This command regenerates the files upon modification"

This approach has the drawback of having to maitain this “help” recipe independently of the corresponding make commands. This often results in outdated “documentation”.

Solution
A more automated approach is to write small script which will print out all the make targets along with their documentation.

How is the documentation written you may ask? As an inline comment next to each target!
Harder to forget, easier to maintain. Smooth.

Code
Include the following “help” recipe near the top of your Makefile, insert each command’s documentation as an inline comment and you’re good to go!

help:
    @awk -F ':.*?## ' '/^[^\t]+\:[^\t]+##/ { printf "\033[36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)

html: ## (re)generate the web site
    echo "This command (re)generates thee web site"

clean: ## remove the generated files
    echo "This command removes the generated files"

regenerate: clean ## regenerate files upon modification
    echo "This command regenerates the files upon modification"

To make it even more solid, add the next line at the top of the Makefile to set the “help” target as the default one.
.DEFAULT_GOAL := help

Try it out
Now, run make or make help to see the results!

Notes
Make sure the white space is translated as “tab” and not “space” character before the “awk” script.







Credits

This post was inspired from this one by Marmelab.