Self-Documenting Makefiles


In this article, Ask Mr. Make explores self-documenting Makefiles.



Before showing you how it works, here's a small example. This Makefile has three targets that the creator thinks you need to know about: all, clean and package. They've documented the Makefile by including some extra information with each target:


all: $(call print-help,all,Builds all modules in Banana Wumpus system)
...commands for building all ...

clean: $(call print-help,clean,Remove all object and library files)
...commands for doing a clean ...

package: $(call print-help,package,Package application-must run all target first)
...commands for doing package step ...

For each of the targets needing documentation the Makefile maintainer has added a call to a user-defined function called print-help with two arguments: the name of the target and a brief description of that target. The call to print-help doesn't interfere with the definition of the prerequisites of the rule because it always returns (or is expanded to) an empty string.

Typing make with this Makefile outputs

Type 'make help' to get help

and typing make help reveals:

Makefile:11: all -- Build all modules in Banana Wumpus system
Makefile:17: clean -- Remove all object and library files
Makefile:23: package -- Package application-must run all target first

Make has automatically printed out the names of the interesting targets, with an explanation of what they do, and the line number of the Makefile where you can find more information about the commands for that target.

All the interesting work is being done by the included Makefile help-system.mak. help-system.mak first defines the user-defined function print-help.

print-help is the function called for each target that needs documenting and it uses GNU Make's $(warning ) function to output the appropriate message based on the two parameters passed to print-help. The first parameter (stored in $1) is the name of the target and the second (in $2) is the help text; they are separated by --. $(warning ) writes a message to the console and returns an empty string; hence print-help can safely be used in the prerequisite list of a rule.

define print-help
$(if $(need-help),$(warning $1 -- $2))

print-help decides whether it needs to print any message by examining the need-help variable which will be the string help if the user specified help on the Make command-line, or empty if they did not. GNU Make's $(if ) function will expand its second argument (the $(warning $1 -- $2)) if the first argument is non-blank. In either case the expanded value of print-help is an empty string.

need-help determines whether the user entered help on the command-line by examining the built-in variable MAKECMDGOALS which is a space separated list of all the goals specified on the Make command line. need-help filters out any goal that doesn't match the text help, and hence is the string help if help was in MAKECMDGOALS and empty otherwise.

need-help := $(filter help,$(MAKECMDGOALS))

The definition of need-help and print-help are all that is needed to cause Make to print out help on each target when run with help on the command line. The rest of help-system.mak prints out the message

Type 'make help' to get help

when the user simply types make.

It defines a default goal for the Makefile called help which will be run if no other goal is specified on the command line.

help: ; @echo $(if $(need-help),,Type \'$(MAKE)$(dash-f) help\' to get help)

This rule will output nothing if the user has asked for help (determined by the need-help variable), but if not then it will output the message containing the name of the Make program (stored in $(MAKE)) followed by the appropriate parameter

About the author

CMCrossroads is a TechWell community.

Through conferences, training, consulting, and online resources, TechWell helps you develop and deliver great software every day.