# Built-in help in a Makefile

My colleagues often ask me, "Dude could you remind me what I have to type to build this target?". So I eventually implemented a nice workaround in my Makefiles.

I wanted my Makefiles to have a help target that give some usage clues to the users. This is achieved with an embedded Perl script and some markers.

Wherever I want a target to be documented, I simply add this trailing comment:

##@<category> <description>


Here is an example:

SCRIPT_VERSION=v1.0
SCRIPT_AUTHOR=John Doe

all:                ##@Build Build all the project
echo "Hello World!" > all

clean:              ##@Cleaning Remove all intermediate objects
rm all

mrproper: clean     ##@Cleaning Remove all output and interemediate objects

HELP_FUN = \
%help; while(<>){push@{$$help{$$2//'options'}},[$$1,$$3] \
if/^(\w+)\s*:.*\#\#(?:@(\w+))?\s(.*)$$/}; \ print"$$_:\n", map"  $$_->[0]".(" "x(20-length($$_->[0])))."$$_->[1]\n",\ @{$$help{$$_}},"\n" for keys %help; \ help: ##@Miscellaneous Show this help @echo -e "Usage: make [target] ...\n" @perl -e '(HELP_FUN)' (MAKEFILE_LIST) @echo -e "Written by (SCRIPT_AUTHOR), version (SCRIPT_VERSION)" @echo -e "Please report any bug or error to the author."  Here what I get if I type make help:  make help Usage: make [target] ... Miscellaneous: help Show this help Build: all Build all the project Cleaning: clean Remove all intermediate objects mrproper Remove all output and interemediate objects Written by John Doe, version v1.0 Please report any bug or error to the author.  In the case the Makefile takes time to parse the dependencies we can bypass the file for the help target: ifeq (,(filter help,(MAKECMDGOALS))) # Core of the makefile endif  What do you think of this technique. Is it a good approach? Can I improve it? ## 3 Answers It looks pretty good to me, but I see a few minor things that might be improved. ## Specify which perl to run I'd recommend not leaving it to chance as to which instance of perl is run. Instead, for both safety and consistency, it might be better to do this: PERL=/usr/bin/perl ##... @(PERL) -e '(HELP_FUN)' (MAKEFILE_LIST)  ## Allow multiword category tags With a slight change in your regex, multiword categories could be supported. If the second line is changed to this: if/^(\w+)\s*:.*\#\#(?:@([^@]*)@)?\s(.*)$$/}; \


It will support multiword categories, delimited with @,

nothing:         ##@Odds & ends@ Do nothing, but gracefully


## Sort the keys for printing

On my machine, I get a different ordering each time I run make help which is a little confusing. To fix that, sort the keys, rendering the last line:

@{$$help{$$_}},"\n" for sort keys %help


Note that you shouldn't have a line continuation there, and you don't need the trailing semicolon (although you may prefer one for style reasons).

## Omit declaration of hash

Because %help is unambiguously used, you don't need to predeclare it. It will automatically be created as an empty hash, so the first line can become:

while(<>){push@{$$help{$$2//'options'}},[$$1,$$3] \


This is a minor point, but you should declare all non-file targets as phony. Otherwise make will behave strangely if you have a file named named "all", "clean" etc in your directory. make will only run the command when the file is updated, which is not the desired behaviour.

.PHONY: all clean mrproper help


You can do this in pure make if you'd like (that is, without requiring an external tool like Perl). John Graham-Cumming has a detailed explanation of it on his blog, but here's the short version.

You can add documentation to a make target by declaring it like this:

include help-system.mk

all: $(call print-help,all,Builds everything) # commands go here lib:$(call print-help,lib,Builds only the static library)
# commands go here

clean: \$(call print-help,clean,Removes intermediate and output files)
# commands go here


Invoking make help will print out something that looks like:

Makefile:6: all -- Builds everything
Makefile:14: lib -- Builds only the static library
Makefile:20: clean -- Removes intermediate and output files


The contents of "help-system.mk" are listed at the link given above.

Note: the macro "print-help" expands to an empty string so this won't interfere with listing prerequisites for a target.