Create a gist now

Instantly share code, notes, and snippets.

@rcmachado /Makefile
Last active Jun 18, 2018

Embed
Add a help target to a Makefile that will allow all targets to be self documenting
.SILENT:
.PHONY: help
# Based on https://gist.github.com/prwhite/8168133#comment-1313022
## This help screen
help:
printf "Available targets\n\n"
awk '/^[a-zA-Z\-\_0-9]+:/ { \
helpMessage = match(lastLine, /^## (.*)/); \
if (helpMessage) { \
helpCommand = substr($$1, 0, index($$1, ":")-1); \
helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
printf "%-15s %s\n", helpCommand, helpMessage; \
} \
} \
{ lastLine = $$0 }' $(MAKEFILE_LIST)
## Another dummy task
another-dummy-task:
echo dummy
@olibre

This comment has been minimized.

Show comment
Hide comment
@olibre

olibre Sep 30, 2015

Improvements:

  • Colorize and bold target name
  • Use HelpMsg above or on same line
  • Width of first column is adapted to maximum length of target names
all: pdf html       ## Default target, same as 'make pdf html'

pdf:  ${pdffiles}   ## Convert to PDF all discovered '*.md' files

html: ${htmfiles}   ## Convert to HTML all discovered '*.md' files

## Display this help text
help: 
        $(info Available targets)
        @awk '/^[a-zA-Z\-\_0-9]+:/ {                                   \
          nb = sub( /^## /, "", helpMsg );                             \
          if(nb == 0) {                                                \
            helpMsg = $$0;                                             \
            nb = sub( /^[^:]*:.* ## /, "", helpMsg );                  \
          }                                                            \
          if (nb)                                                      \
            printf "\033[1;31m%-" width "s\033[0m %s\n", $$1, helpMsg; \
        }                                                              \
        { helpMsg = $$0 }'                                             \
        width=$$(grep -o '^[a-zA-Z_0-9]\+:' $(MAKEFILE_LIST) | wc -L)  \
        $(MAKEFILE_LIST)

output

Available targets
all:   Default target, same as 'make pdf html'
pdf:   Convert to PDF all discovered '*.md' files
html:  Convert to HTML all discovered '*.md' files
help:  Display this help text

The below simpler version uses command column instead of the tricky grep | wc -L but:

  • no color
  • no ':' in HelpMsg
all: pdf html       ## Default target, same as 'make pdf html'

pdf:  ${pdffiles}   ## Convert to PDF all discovered '*.md' files

html: ${htmfiles}   ## Convert to HTML all discovered '*.md' files

## Display this help text
help: 
        $(info Available targets)
        @awk '/^[a-zA-Z\-\_0-9]+:/ {                    \
          nb = sub( /^## /, "", helpMsg );              \
          if(nb == 0) {                                 \
            helpMsg = $$0;                              \
            nb = sub( /^[^:]*:.* ## /, "", helpMsg );   \
          }                                             \
          if (nb)                                       \
            print  $$1 helpMsg;                         \
        }                                               \
        { helpMsg = $$0 }'                              \
        $(MAKEFILE_LIST) | column -ts:

output

Available targets
all   Default target, same as 'make pdf html'
pdf   Convert to PDF all discovered '*.md' files
html  Convert to HTML all discovered '*.md' files
help  Display this help text

Let's complicate a bit the above Makefile using $$'\t' and colorize first column using grep --color.
The grep color can be controlled by the environment variable GREP_COLORS.
Try GREP_COLORS='mt=1;41;37' make help or be inspired from many color posibilities.
(You can embed the GREP_COLORS value within the Makefile)

all: pdf html       ## Default target, same as 'make pdf html'

pdf:  ${pdffiles}   ## Convert to PDF all discovered '*.md' files

html: ${htmfiles}   ## Convert to HTML all discovered '*.md' files

## Display this help text
help: 
        $(info Available targets)
        @awk '/^[a-zA-Z\-\_0-9]+:/ {                    \
          nb = sub( /^## /, "", helpMsg );              \
          if(nb == 0) {                                 \
            helpMsg = $$0;                              \
            nb = sub( /^[^:]*:.* ## /, "", helpMsg );   \
          }                                             \
          if (nb)                                       \
            print  $$1 "\t" helpMsg;                    \
        }                                               \
        { helpMsg = $$0 }'                              \
        $(MAKEFILE_LIST) | column -ts $$'\t' |          \
        grep --color '^[^ ]*'

output

Available targets
all:   Default target, same as 'make pdf html'
pdf:   Convert to PDF all discovered '*.md' files
html:  Convert to HTML all discovered '*.md' files
help:  Display this help text

olibre commented Sep 30, 2015

Improvements:

  • Colorize and bold target name
  • Use HelpMsg above or on same line
  • Width of first column is adapted to maximum length of target names
all: pdf html       ## Default target, same as 'make pdf html'

pdf:  ${pdffiles}   ## Convert to PDF all discovered '*.md' files

html: ${htmfiles}   ## Convert to HTML all discovered '*.md' files

## Display this help text
help: 
        $(info Available targets)
        @awk '/^[a-zA-Z\-\_0-9]+:/ {                                   \
          nb = sub( /^## /, "", helpMsg );                             \
          if(nb == 0) {                                                \
            helpMsg = $$0;                                             \
            nb = sub( /^[^:]*:.* ## /, "", helpMsg );                  \
          }                                                            \
          if (nb)                                                      \
            printf "\033[1;31m%-" width "s\033[0m %s\n", $$1, helpMsg; \
        }                                                              \
        { helpMsg = $$0 }'                                             \
        width=$$(grep -o '^[a-zA-Z_0-9]\+:' $(MAKEFILE_LIST) | wc -L)  \
        $(MAKEFILE_LIST)

output

Available targets
all:   Default target, same as 'make pdf html'
pdf:   Convert to PDF all discovered '*.md' files
html:  Convert to HTML all discovered '*.md' files
help:  Display this help text

The below simpler version uses command column instead of the tricky grep | wc -L but:

  • no color
  • no ':' in HelpMsg
all: pdf html       ## Default target, same as 'make pdf html'

pdf:  ${pdffiles}   ## Convert to PDF all discovered '*.md' files

html: ${htmfiles}   ## Convert to HTML all discovered '*.md' files

## Display this help text
help: 
        $(info Available targets)
        @awk '/^[a-zA-Z\-\_0-9]+:/ {                    \
          nb = sub( /^## /, "", helpMsg );              \
          if(nb == 0) {                                 \
            helpMsg = $$0;                              \
            nb = sub( /^[^:]*:.* ## /, "", helpMsg );   \
          }                                             \
          if (nb)                                       \
            print  $$1 helpMsg;                         \
        }                                               \
        { helpMsg = $$0 }'                              \
        $(MAKEFILE_LIST) | column -ts:

output

Available targets
all   Default target, same as 'make pdf html'
pdf   Convert to PDF all discovered '*.md' files
html  Convert to HTML all discovered '*.md' files
help  Display this help text

Let's complicate a bit the above Makefile using $$'\t' and colorize first column using grep --color.
The grep color can be controlled by the environment variable GREP_COLORS.
Try GREP_COLORS='mt=1;41;37' make help or be inspired from many color posibilities.
(You can embed the GREP_COLORS value within the Makefile)

all: pdf html       ## Default target, same as 'make pdf html'

pdf:  ${pdffiles}   ## Convert to PDF all discovered '*.md' files

html: ${htmfiles}   ## Convert to HTML all discovered '*.md' files

## Display this help text
help: 
        $(info Available targets)
        @awk '/^[a-zA-Z\-\_0-9]+:/ {                    \
          nb = sub( /^## /, "", helpMsg );              \
          if(nb == 0) {                                 \
            helpMsg = $$0;                              \
            nb = sub( /^[^:]*:.* ## /, "", helpMsg );   \
          }                                             \
          if (nb)                                       \
            print  $$1 "\t" helpMsg;                    \
        }                                               \
        { helpMsg = $$0 }'                              \
        $(MAKEFILE_LIST) | column -ts $$'\t' |          \
        grep --color '^[^ ]*'

output

Available targets
all:   Default target, same as 'make pdf html'
pdf:   Convert to PDF all discovered '*.md' files
html:  Convert to HTML all discovered '*.md' files
help:  Display this help text
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment