Skip to content

Instantly share code, notes, and snippets.

@bluebrown
Last active April 23, 2025 09:56
Show Gist options
  • Save bluebrown/2ec155902622b5e46e2bfcbaff342eb9 to your computer and use it in GitHub Desktop.
Save bluebrown/2ec155902622b5e46e2bfcbaff342eb9 to your computer and use it in GitHub Desktop.
awk script to generate a help text from a Makefile

Auto generate help text

In order to generate a help text for the makefile, the makefile can be read with something like awk. In addition, comments can be used to provide contextual information about a given goal. For example, the kubebuilder projects generates an arcane looking one liner.

This gist inspired by that one liner. It is its own executable script that can be called from the makefile. This help with readability.

It allows to write the documentation for the makefile in the makefile itself.

##@ Options

GITHUB_SHA ?= $(shell git rev-parse main)
DOKTRI_AUTHROR ?= Nico Braun
DOKTRI_CHROMA_STYLE ?= tokyonight-moon

export DOKTRI_AUTHROR DOKTRI_CHROMA_STYLE

##@ Commands

help: $(CURDIR)/Makehelp ## show this help message
    @$< $(MAKEFILE_LIST)

dev: ## run the development server
    doktri serve
    
Makehelp:
    curl -Lo $@ https://gist.githubusercontent.com/bluebrown/2ec155902622b5e46e2bfcbaff342eb9/raw/Makehelp.awk
    chmod +x $@

When invoking make with the defaut or help command, the help message will be printed. The help message will look like this. Note that the colors are not shown here, but they will be in the terminal.

$ make

Usage:
  make [ command ] [ option=value ]...

Options:
  GITHUB_SHA           (default: $(shell git rev-parse main))
  DOKTRI_AUTHROR       (default: Nico Braun)
  DOKTRI_CHROMA_STYLE  (default: tokyonight-moon)

Commands:
  help                 show this help message
  dev                  run the development server
#!/usr/bin/env -S gawk -f
BEGIN {
init_theme()
print_usage()
# split targets and options
FS = "(:.*##|?=)"
}
# options:: <var> ?= <default>
/^[a-zA-Z_\-]+\s\?=.*/ {
printf(" %s%-20s%s (default:%s%s%s)%s\n",
fg_option, $1, fg_comment, fg_value, $2, fg_comment, c_reset)
}
# headings:: ##@ <subject>
/^##@/ { printf("\n%s%s:%s\n", fg_heading, substr($0, 5), c_reset) }
# subheadings:: ###@ <subject>
/^###@/ { printf("\n%s%s:%s\n", fg_subheading, substr($0, 6), c_reset) }
# targets:: <target>: ## <description>
# if the descriptions contains options references like $var or $(var),
# those will be accentuated
/^[a-zA-Z_0-9\-\/]+:.*?##/ {
desc = gensub(/(\$[a-zA-Z_\-\(\)]+)/, sprintf("%s\\1%s", fg_value, fg_comment), "g", $2)
printf(" %s%-20s%s%s%s\n", fg_target, $1, fg_comment, desc, c_reset)
}
function print_usage() {
printf("\n%sUsage:%s\n make%s", fg_heading, fg_binary, c_reset)
printf(" %s[ %scommand%s ]%s", fg_value, fg_target, fg_value, c_reset)
printf(" %s[ %soption%s=value ]...%s\n", fg_value, fg_option, fg_value, c_reset)
}
# cargo style theme
function init_theme() {
c_reset = "\33[0m"
c_bold = "\33[1m"
c_green = "\33[32m"
c_blue = "\33[34m"
c_cyan = "\33[36m"
c_white = "\33[37m"
fg_binary = sprintf("%s%s%s", c_reset, c_bold, c_cyan)
fg_heading = sprintf("%s%s%s",c_reset, c_bold, c_green)
fg_subheading = sprintf("%s%s", c_reset, c_green)
fg_target = sprintf("%s%s%s", c_reset, c_bold, c_cyan)
fg_option = sprintf("%s%s%s", c_reset, c_bold, c_cyan)
fg_value = sprintf("%s%s", c_reset, c_cyan)
fg_comment = sprintf("%s", c_reset)
}
function init_theme() {
c_reset = "\33[0m"
c_bold = "\33[1m"
c_italic = "\33[3m"
c_green = "\33[32m"
c_blue = "\33[34m"
c_white = "\33[37m"
c_yellow = "\33[33m"
c_magenta = "\33[35m"
c_gray = "\33[1;90m"
fg_binary = sprintf("%s%s%s", c_reset, c_bold, c_yellow)
fg_heading = sprintf("%s%s%s", c_reset, c_bold, c_blue)
fg_subheading = sprintf("%s%s", c_reset, c_blue)
fg_target = sprintf("%s%s", c_reset, c_green)
fg_option = sprintf("%s%s", c_reset, c_magenta)
fg_value = sprintf("%s%s%s", c_reset, c_bold, c_magenta)
fg_comment = sprintf("%s%s%s", c_reset, c_italic, c_gray)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment