Skip to content

Instantly share code, notes, and snippets.

@ruittenb
Last active October 9, 2025 07:48
Show Gist options
  • Select an option

  • Save ruittenb/5d2d281237385276f49652b9b9f6d5a1 to your computer and use it in GitHub Desktop.

Select an option

Save ruittenb/5d2d281237385276f49652b9b9f6d5a1 to your computer and use it in GitHub Desktop.
Makefile target for automatically generating help
############################################################################
#
# This code automatically creates a table of Makefile targets and short descriptions.
# Descriptions should be added in the Makefile itself:
#
# '##' after a target is used for target descriptions
# '##@' at the start of a line is used for header lines.
#
# See the examples below.
#
# The awk option '-v tab=10' can be changed to indent the second column of the output.
#
##@ This is heading text, which is shown on a separate line.
##@ Heading text may be \
extended across lines.
##@ Heading text may contain\n- newlines\n- by specifying them with\n- backslash-n\n
# This is just any comment and its continuation. \
It will not be parsed by 'make help'.
############################################################################
#
# Readable version, with '$' replaced with makefile-style '$$':
#
# @awk -v tab=10 '
# BEGIN {
# FS = ":.*## ";
# buffer = "";
# color = "\033[36m";
# nocolor = "\033[0m";
# indent = " ";
# usage();
# }
# function trim(str) {
# gsub(/[ \t]+$$/, "", str);
# gsub(/^[ \t]+/, "", str);
# return str;
# }
# function spout(target, desc) {
# printf "%s%s%-" tab "s%s%s\n", indent, color, trim(target), nocolor, desc;
# }
# function usage() {
# printf "\nUsage:\n%smake %s<target>%s\n\nRecognized targets:\n", indent, color, nocolor;
# }
# /\\$$/ {
# gsub(/\\$$/, "");
# buffer = buffer $$0;
# next;
# }
# buffer {
# $$0 = buffer $$0;
# buffer = "";
# }
# /^[-a-zA-Z0-9*%_. ]+:.*?## / {
# pad = sprintf("\n%" tab "s" indent, "");
# gsub(/\\n/, pad);
# spout($$1, $$2);
# }
# /^##@ / {
# gsub(/\\n/, "\n");
# printf "\n%s\n", substr($$0, 5);
# }
# END {
# print "";
# }
# ' $(MAKEFILE_LIST) # v1.51
############################################################################
#
# Concise version. Copy this block over to your own Makefile:
.PHONY: help # See https://gist.github.com/ruittenb/5d2d281237385276f49652b9b9f6d5a1
help: ## Print help for each target
@awk -v tab=10 'BEGIN { FS = ":.*## "; buffer = ""; color = "\033[36m"; nocolor = "\033[0m"; indent = " "; usage(); } function trim(str) { gsub(/[ \t]+$$/, "", str); gsub(/^[ \t]+/, "", str); return str; } function spout(target, desc) { printf "%s%s%-" tab "s%s%s\n", indent, color, trim(target), nocolor, desc; } function usage() { printf "\nUsage:\n%smake %s<target>%s\n\nRecognized targets:\n", indent, color, nocolor; } /\\$$/ { gsub(/\\$$/, ""); buffer = buffer $$0; next; } buffer { $$0 = buffer $$0; buffer = ""; } /^[-a-zA-Z0-9*%_. ]+:.*?## / { pad = sprintf("\n%" tab "s" indent, ""); gsub(/\\n/, pad); spout($$1, $$2); } /^##@ / { gsub(/\\n/, "\n"); printf "\n%s\n", substr($$0, 5) } END { print "" }' $(MAKEFILE_LIST) # v1.51
############################################################################
#
##@ Example targets:
show1: ## This is a description for show1, no prerequisites
show2: prereq1 prereq2 ## This is a description for show2, with compact prerequisites
show3: prereq1 \
prereq2 ## This is a description for show3, with continuation prerequisites
show4: ## This is a description for show4 \
and its continuation, no prerequisites
show5: prereq1 prereq2 ## This is a description for show5 \
and its continuation, with compact prerequisites
show6: prereq1 \
prereq2 ## This is a description for show6 \
and its continuation, with continuation prerequisites
##@ None of these should be printed:
noshow1: # This is just any comment, which will not be parsed by 'make help'
noshow2: prereq1 prereq2 # This is just any comment, which will not be parsed by 'make help'
noshow3: prereq1 \
prereq2 # This is just any comment, which will not be parsed by 'make help'
noshow4: # This is just any comment and its continuation. \
It will not be parsed by 'make help'.
noshow5: prereq1 prereq2 # This is just any comment and its continuation. \
It will not be parsed by 'make help'.
noshow6: prereq1 \
prereq2 # This is just any comment and its continuation. \
It will not be parsed by 'make help'.
# Makefile directives
.DEFAULT_GOAL:=help
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment