Instantly share code, notes, and snippets.

@prwhite /Makefile
Last active Oct 19, 2018

Embed
What would you like to do?
Add a help target to a Makefile that will allow all targets to be self documenting
# Add the following 'help' target to your Makefile
# And add help text after each target name starting with '\#\#'
help: ## Show this help.
@fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
# Everything below is an example
target00: ## This message will show up when typing 'make help'
@echo does nothing
target01: ## This message will also show up when typing 'make help'
@echo does something
# Remember that targets can have multiple entries (if your target specifications are very long, etc.)
target02: ## This message will show up too!!!
target02: target00 target01
@echo does even more
@prwhite

This comment has been minimized.

Show comment
Hide comment
@prwhite

prwhite Dec 29, 2013

Output will be:

help: Show this help.
target00: This message will show up when typing 'make help'
target01: This message will also show up when typing 'make help'
target02: This message will show up too!!!

Owner

prwhite commented Dec 29, 2013

Output will be:

help: Show this help.
target00: This message will show up when typing 'make help'
target01: This message will also show up when typing 'make help'
target02: This message will show up too!!!

@amussey

This comment has been minimized.

Show comment
Hide comment
@amussey

amussey Oct 6, 2014

This is great! Thanks for sharing it.

Here's a modified help command I've put together so the messages are pushed out to the same point:

help: ## This help dialog.
    @IFS=$$'\n' ; \
    help_lines=(`fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//'`); \
    for help_line in $${help_lines[@]}; do \
        IFS=$$'#' ; \
        help_split=($$help_line) ; \
        help_command=`echo $${help_split[0]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
        help_info=`echo $${help_split[2]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
        printf "%-30s %s\n" $$help_command $$help_info ; \
    done

# Everything below is an example

target00: ## This message will show up when typing 'make help'
    @echo does nothing

target01: ## This message will also show up when typing 'make help'
    @echo does something

# Remember that targets can have multiple entries (if your target specifications are very long, etc.)
target02:  ## This message will show up too!!!
target02: target00 target01
    @echo does even more

will respond with:

help:                          This help dialog.
target00:                      This message will show up when typing 'make help'
target01:                      This message will also show up when typing 'make help'
target02:                      This message will show up too!!!

amussey commented Oct 6, 2014

This is great! Thanks for sharing it.

Here's a modified help command I've put together so the messages are pushed out to the same point:

help: ## This help dialog.
    @IFS=$$'\n' ; \
    help_lines=(`fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//'`); \
    for help_line in $${help_lines[@]}; do \
        IFS=$$'#' ; \
        help_split=($$help_line) ; \
        help_command=`echo $${help_split[0]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
        help_info=`echo $${help_split[2]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
        printf "%-30s %s\n" $$help_command $$help_info ; \
    done

# Everything below is an example

target00: ## This message will show up when typing 'make help'
    @echo does nothing

target01: ## This message will also show up when typing 'make help'
    @echo does something

# Remember that targets can have multiple entries (if your target specifications are very long, etc.)
target02:  ## This message will show up too!!!
target02: target00 target01
    @echo does even more

will respond with:

help:                          This help dialog.
target00:                      This message will show up when typing 'make help'
target01:                      This message will also show up when typing 'make help'
target02:                      This message will show up too!!!
@LogicalChaos

This comment has been minimized.

Show comment
Hide comment
@LogicalChaos

LogicalChaos Oct 20, 2014

Thanks to the both of you for providing this.

LogicalChaos commented Oct 20, 2014

Thanks to the both of you for providing this.

@rcmachado

This comment has been minimized.

Show comment
Hide comment
@rcmachado

rcmachado Oct 23, 2014

I've made a version using only awk (tested on OS X, but possible works on gawk too). I also moved the help message just before the task - so you don't need to declare the target multiple times:

https://gist.github.com/rcmachado/af3db315e31383502660

rcmachado commented Oct 23, 2014

I've made a version using only awk (tested on OS X, but possible works on gawk too). I also moved the help message just before the task - so you don't need to declare the target multiple times:

https://gist.github.com/rcmachado/af3db315e31383502660

@nowox

This comment has been minimized.

Show comment
Hide comment
@nowox

nowox Feb 16, 2015

Very nice idea. I modified it with a small Perl script that support categories:

 # Add the following 'help' target to your Makefile
 # And add help text after each target name starting with '\#\#'
 # A category can be added with @category

 HELP_FUN = \
         %help; \
         while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^(\w+)\s*:.*\#\#(?:@(\w+))?\s(.*)$$/ }; \
         print "usage: make [target]\n\n"; \
     for (keys %help) { \
         print "$$_:\n"; $$sep = " " x (20 - length $$_->[0]); \
         print "  $$_->[0]$$sep$$_->[1]\n" for @{$$help{$$_}}; \
         print "\n"; }     

 help:           ##@miscellaneous Show this help.
     @perl -e '$(HELP_FUN)' $(MAKEFILE_LIST)

 # Everything below is an example

 target00:       ##@foo This message will show up when typing 'make help'
     @echo does nothing

 target01:       ##@foo This message will also show up when typing 'make help'
     @echo does something

 # Remember that targets can have multiple entries (if your target specifications are very long, etc.)
 target02:       ## This message will show up too!!!
 target02: target00 target01
     @echo does even more

The output is this:

 $ make help
 usage: make [target]

 options:
   target02                    This message will show up too!!!

 foo:
   target00                    This message will show up when typing 'make help'
   target01                    This message will also show up when typing 'make help'

 miscellaneous:
   help                    Show this help.

nowox commented Feb 16, 2015

Very nice idea. I modified it with a small Perl script that support categories:

 # Add the following 'help' target to your Makefile
 # And add help text after each target name starting with '\#\#'
 # A category can be added with @category

 HELP_FUN = \
         %help; \
         while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^(\w+)\s*:.*\#\#(?:@(\w+))?\s(.*)$$/ }; \
         print "usage: make [target]\n\n"; \
     for (keys %help) { \
         print "$$_:\n"; $$sep = " " x (20 - length $$_->[0]); \
         print "  $$_->[0]$$sep$$_->[1]\n" for @{$$help{$$_}}; \
         print "\n"; }     

 help:           ##@miscellaneous Show this help.
     @perl -e '$(HELP_FUN)' $(MAKEFILE_LIST)

 # Everything below is an example

 target00:       ##@foo This message will show up when typing 'make help'
     @echo does nothing

 target01:       ##@foo This message will also show up when typing 'make help'
     @echo does something

 # Remember that targets can have multiple entries (if your target specifications are very long, etc.)
 target02:       ## This message will show up too!!!
 target02: target00 target01
     @echo does even more

The output is this:

 $ make help
 usage: make [target]

 options:
   target02                    This message will show up too!!!

 foo:
   target00                    This message will show up when typing 'make help'
   target01                    This message will also show up when typing 'make help'

 miscellaneous:
   help                    Show this help.
@muhmi

This comment has been minimized.

Show comment
Hide comment
@muhmi

muhmi Mar 25, 2015

This is awesome! I wanted ANSI colors so ...

help: ## This help dialog.
    @IFS=$$'\n' ; \
    help_lines=(`fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##/:/'`); \
    printf "%-30s %s\n" "target" "help" ; \
    printf "%-30s %s\n" "------" "----" ; \
    for help_line in $${help_lines[@]}; do \
        IFS=$$':' ; \
        help_split=($$help_line) ; \
        help_command=`echo $${help_split[0]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
        help_info=`echo $${help_split[2]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
        printf '\033[36m'; \
        printf "%-30s %s" $$help_command ; \
        printf '\033[0m'; \
        printf "%s\n" $$help_info; \
    done

target: ## Does absolutely nothing!
    exit 0

muhmi commented Mar 25, 2015

This is awesome! I wanted ANSI colors so ...

help: ## This help dialog.
    @IFS=$$'\n' ; \
    help_lines=(`fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##/:/'`); \
    printf "%-30s %s\n" "target" "help" ; \
    printf "%-30s %s\n" "------" "----" ; \
    for help_line in $${help_lines[@]}; do \
        IFS=$$':' ; \
        help_split=($$help_line) ; \
        help_command=`echo $${help_split[0]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
        help_info=`echo $${help_split[2]} | sed -e 's/^ *//' -e 's/ *$$//'` ; \
        printf '\033[36m'; \
        printf "%-30s %s" $$help_command ; \
        printf '\033[0m'; \
        printf "%s\n" $$help_info; \
    done

target: ## Does absolutely nothing!
    exit 0

@colonelfazackerley

This comment has been minimized.

Show comment
Hide comment
@colonelfazackerley

colonelfazackerley Jan 14, 2016

This is great stuff. Can you declare a licence, so I can use it in good conscience?

colonelfazackerley commented Jan 14, 2016

This is great stuff. Can you declare a licence, so I can use it in good conscience?

@lordnynex

This comment has been minimized.

Show comment
Hide comment
@lordnynex

lordnynex Mar 1, 2016

@nowox I know this gist is quite old but I liked your solution. I just had to make a small modification and wanted to share

  • Modified the regex to match rules that have special chars in them
  • Sort help hash before generating messages for consistent output
  • Use printf with a fixed width column for consistent output. (There where alignment issues in your initial implementation)
HELP_FUNC = \
    %help; \
    while(<>) { \
        if(/^([a-z0-9_-]+):.*\#\#(?:@(\w+))?\s(.*)$$/) { \
            push(@{$$help{$$2}}, [$$1, $$3]); \
        } \
    }; \
    print "usage: make [target]\n\n"; \
    for ( sort keys %help ) { \
        print "$$_:\n"; \
        printf("  %-20s %s\n", $$_->[0], $$_->[1]) for @{$$help{$$_}}; \
        print "\n"; \
    }

lordnynex commented Mar 1, 2016

@nowox I know this gist is quite old but I liked your solution. I just had to make a small modification and wanted to share

  • Modified the regex to match rules that have special chars in them
  • Sort help hash before generating messages for consistent output
  • Use printf with a fixed width column for consistent output. (There where alignment issues in your initial implementation)
HELP_FUNC = \
    %help; \
    while(<>) { \
        if(/^([a-z0-9_-]+):.*\#\#(?:@(\w+))?\s(.*)$$/) { \
            push(@{$$help{$$2}}, [$$1, $$3]); \
        } \
    }; \
    print "usage: make [target]\n\n"; \
    for ( sort keys %help ) { \
        print "$$_:\n"; \
        printf("  %-20s %s\n", $$_->[0], $$_->[1]) for @{$$help{$$_}}; \
        print "\n"; \
    }
@tweekmonster

This comment has been minimized.

Show comment
Hide comment
@tweekmonster

tweekmonster Mar 7, 2016

Here's my take:

  • Colored target names
  • Used column to have reasonable spacing between the target and help message
  • Help comments can be on the same line as target dependencies
# Needed SHELL since I'm using zsh
SHELL := /bin/bash
.PHONY: help

# Add the following 'help' target to your Makefile
# And add help text after each target name starting with '\#\#'

help: ## This help message
    @echo -e "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)"

# Everything below is an example

target00:       ## This message will show up when typing 'make help'
    @echo does nothing

target01:       ## This message will also show up when typing 'make help'
    @echo does something

# Remember that targets can have multiple entries (if your target specifications are very long, etc.)
target02:       ## This message will show up too!!!
target02: target00 target01
    @echo does even more

tweekmonster commented Mar 7, 2016

Here's my take:

  • Colored target names
  • Used column to have reasonable spacing between the target and help message
  • Help comments can be on the same line as target dependencies
# Needed SHELL since I'm using zsh
SHELL := /bin/bash
.PHONY: help

# Add the following 'help' target to your Makefile
# And add help text after each target name starting with '\#\#'

help: ## This help message
    @echo -e "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)"

# Everything below is an example

target00:       ## This message will show up when typing 'make help'
    @echo does nothing

target01:       ## This message will also show up when typing 'make help'
    @echo does something

# Remember that targets can have multiple entries (if your target specifications are very long, etc.)
target02:       ## This message will show up too!!!
target02: target00 target01
    @echo does even more
@gibatronic

This comment has been minimized.

Show comment
Hide comment
@gibatronic

gibatronic Mar 7, 2016

If anyone is interested, I wrote a package for that: make-help

The following Makefile:

# generate all assets
build: scripts styles

# show some help
help:
    echo
    echo '  Usage:'
    echo '    make <target>'
    echo
    echo '  Targets:'
    make-help -p 4 "$(lastword $(MAKEFILE_LIST))"
    echo

# generete scripts
scripts:
    ...

# generete styles
styles:
    ...

Will output this when make help is called:

  Usage:
    make <target>

  Targets:
    build    generate all assets
    help     show some help
    scripts  generete scripts
    styles   generete styles

gibatronic commented Mar 7, 2016

If anyone is interested, I wrote a package for that: make-help

The following Makefile:

# generate all assets
build: scripts styles

# show some help
help:
    echo
    echo '  Usage:'
    echo '    make <target>'
    echo
    echo '  Targets:'
    make-help -p 4 "$(lastword $(MAKEFILE_LIST))"
    echo

# generete scripts
scripts:
    ...

# generete styles
styles:
    ...

Will output this when make help is called:

  Usage:
    make <target>

  Targets:
    build    generate all assets
    help     show some help
    scripts  generete scripts
    styles   generete styles
@HarasimowiczKamil

This comment has been minimized.

Show comment
Hide comment
@HarasimowiczKamil

HarasimowiczKamil Mar 18, 2016

@nowox version with colors and repair targets with - and separator length:

#COLORS
GREEN  := $(shell tput -Txterm setaf 2)
WHITE  := $(shell tput -Txterm setaf 7)
YELLOW := $(shell tput -Txterm setaf 3)
RESET  := $(shell tput -Txterm sgr0)

# Add the following 'help' target to your Makefile
# And add help text after each target name starting with '\#\#'
# A category can be added with @category
HELP_FUN = \
    %help; \
    while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^([a-zA-Z\-]+)\s*:.*\#\#(?:@([a-zA-Z\-]+))?\s(.*)$$/ }; \
    print "usage: make [target]\n\n"; \
    for (sort keys %help) { \
    print "${WHITE}$$_:${RESET}\n"; \
    for (@{$$help{$$_}}) { \
    $$sep = " " x (32 - length $$_->[0]); \
    print "  ${YELLOW}$$_->[0]${RESET}$$sep${GREEN}$$_->[1]${RESET}\n"; \
    }; \
    print "\n"; }

help: ##@other Show this help.
    @perl -e '$(HELP_FUN)' $(MAKEFILE_LIST)

HarasimowiczKamil commented Mar 18, 2016

@nowox version with colors and repair targets with - and separator length:

#COLORS
GREEN  := $(shell tput -Txterm setaf 2)
WHITE  := $(shell tput -Txterm setaf 7)
YELLOW := $(shell tput -Txterm setaf 3)
RESET  := $(shell tput -Txterm sgr0)

# Add the following 'help' target to your Makefile
# And add help text after each target name starting with '\#\#'
# A category can be added with @category
HELP_FUN = \
    %help; \
    while(<>) { push @{$$help{$$2 // 'options'}}, [$$1, $$3] if /^([a-zA-Z\-]+)\s*:.*\#\#(?:@([a-zA-Z\-]+))?\s(.*)$$/ }; \
    print "usage: make [target]\n\n"; \
    for (sort keys %help) { \
    print "${WHITE}$$_:${RESET}\n"; \
    for (@{$$help{$$_}}) { \
    $$sep = " " x (32 - length $$_->[0]); \
    print "  ${YELLOW}$$_->[0]${RESET}$$sep${GREEN}$$_->[1]${RESET}\n"; \
    }; \
    print "\n"; }

help: ##@other Show this help.
    @perl -e '$(HELP_FUN)' $(MAKEFILE_LIST)
@caylorme

This comment has been minimized.

Show comment
Hide comment
@caylorme

caylorme Mar 21, 2016

Any way to make this support targets created with templates?
https://www.gnu.org/software/make/manual/html_node/Eval-Function.html

caylorme commented Mar 21, 2016

Any way to make this support targets created with templates?
https://www.gnu.org/software/make/manual/html_node/Eval-Function.html

@HarasimowiczKamil

This comment has been minimized.

Show comment
Hide comment
@HarasimowiczKamil

HarasimowiczKamil Mar 24, 2016

@caylorme you need to modify fragment [a-zA-Z\-] to like this [a-zA-Z\-\$\(\)]

HarasimowiczKamil commented Mar 24, 2016

@caylorme you need to modify fragment [a-zA-Z\-] to like this [a-zA-Z\-\$\(\)]

@sjparkinson

This comment has been minimized.

Show comment
Hide comment
@sjparkinson

sjparkinson Mar 30, 2016

I'm starting to use the following:

.PHONY: help
help: ## Show this help message.
    echo 'usage: make [target] ...'
    echo
    echo 'targets:'
    egrep '^(.+)\:\ ##\ (.+)' ${MAKEFILE_LIST} | column -t -c 2 -s ':#'

sjparkinson commented Mar 30, 2016

I'm starting to use the following:

.PHONY: help
help: ## Show this help message.
    echo 'usage: make [target] ...'
    echo
    echo 'targets:'
    egrep '^(.+)\:\ ##\ (.+)' ${MAKEFILE_LIST} | column -t -c 2 -s ':#'
@Nachi-M

This comment has been minimized.

Show comment
Hide comment
@Nachi-M

Nachi-M Jan 19, 2017

Would somebody help on how to make the entire help that is in multiple lines show up aligned with first line of help associated with the target?

Example: For below make file content


target00: ## This message will show up when typing 'make help'
    @echo does nothing

target01: ## This message will also show up when typing 'make help'
    @echo does something

# Remember that targets can have multiple entries (if your target specifications are very long, etc.)
target02:  ## This message will show up too!!!
## This help message is way too long so it is in multiple line
target02: target00 target01
    @echo does even more

Desired output:
help:                     This help dialog.
target00:              This message will show up when typing 'make help'
target01:              This message will also show up when typing 'make help'
target02:              This message will show up too!!!
                              This help message is way too long so it is in multiple line

Nachi-M commented Jan 19, 2017

Would somebody help on how to make the entire help that is in multiple lines show up aligned with first line of help associated with the target?

Example: For below make file content


target00: ## This message will show up when typing 'make help'
    @echo does nothing

target01: ## This message will also show up when typing 'make help'
    @echo does something

# Remember that targets can have multiple entries (if your target specifications are very long, etc.)
target02:  ## This message will show up too!!!
## This help message is way too long so it is in multiple line
target02: target00 target01
    @echo does even more

Desired output:
help:                     This help dialog.
target00:              This message will show up when typing 'make help'
target01:              This message will also show up when typing 'make help'
target02:              This message will show up too!!!
                              This help message is way too long so it is in multiple line

@benjick

This comment has been minimized.

Show comment
Hide comment
@benjick

benjick Aug 15, 2017

@nowox (20 - length $$_->[0]) always return 20 for me

benjick commented Aug 15, 2017

@nowox (20 - length $$_->[0]) always return 20 for me

@crifan

This comment has been minimized.

Show comment
Hide comment
@crifan

crifan Dec 7, 2017

reference above and others, updated to Colorful and usable syntax:

# COLORS
GREEN  := $(shell tput -Txterm setaf 2)
YELLOW := $(shell tput -Txterm setaf 3)
WHITE  := $(shell tput -Txterm setaf 7)
RESET  := $(shell tput -Txterm sgr0)


TARGET_MAX_CHAR_NUM=20
## Show help
help:
	@echo ''
	@echo 'Usage:'
	@echo '  ${YELLOW}make${RESET} ${GREEN}<target>${RESET}'
	@echo ''
	@echo 'Targets:'
	@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 "  ${YELLOW}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${GREEN}%s${RESET}\n", helpCommand, helpMessage; \
		} \
	} \
	{ lastLine = $$0 }' $(MAKEFILE_LIST)

then above target use ## target description, example:

## Generate Mobi file
mobi: clean_mobi create_foler_mobi
	gitbook mobi $(CURRENT_DIR_NOSLASH) $(MOBI_FULLNAME)

## Generate all files: website/pdf/epub/mobi
all: website pdf epub mobi

will generate colorful help info:
colorfule make help

for latest makefile pls refer my: Makefile

crifan commented Dec 7, 2017

reference above and others, updated to Colorful and usable syntax:

# COLORS
GREEN  := $(shell tput -Txterm setaf 2)
YELLOW := $(shell tput -Txterm setaf 3)
WHITE  := $(shell tput -Txterm setaf 7)
RESET  := $(shell tput -Txterm sgr0)


TARGET_MAX_CHAR_NUM=20
## Show help
help:
	@echo ''
	@echo 'Usage:'
	@echo '  ${YELLOW}make${RESET} ${GREEN}<target>${RESET}'
	@echo ''
	@echo 'Targets:'
	@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 "  ${YELLOW}%-$(TARGET_MAX_CHAR_NUM)s${RESET} ${GREEN}%s${RESET}\n", helpCommand, helpMessage; \
		} \
	} \
	{ lastLine = $$0 }' $(MAKEFILE_LIST)

then above target use ## target description, example:

## Generate Mobi file
mobi: clean_mobi create_foler_mobi
	gitbook mobi $(CURRENT_DIR_NOSLASH) $(MOBI_FULLNAME)

## Generate all files: website/pdf/epub/mobi
all: website pdf epub mobi

will generate colorful help info:
colorfule make help

for latest makefile pls refer my: Makefile

@TediCreations

This comment has been minimized.

Show comment
Hide comment
@TediCreations

TediCreations Dec 11, 2017

Thanks for these tips on make help

alt text

Here is my Makefile for C/C++ development.

TediCreations commented Dec 11, 2017

Thanks for these tips on make help

alt text

Here is my Makefile for C/C++ development.

@lavaldi

This comment has been minimized.

Show comment
Hide comment
@lavaldi

lavaldi Dec 12, 2017

Hi @muhmi, I try your solution in Ubuntu but I get this error 😞

'/bin/sh: 2: Syntax error: "(" unexpected
Makefile:144: fallo en las instrucciones para el objetivo 'help'
make: *** [help] Error 2'

you know what could be the reason?

lavaldi commented Dec 12, 2017

Hi @muhmi, I try your solution in Ubuntu but I get this error 😞

'/bin/sh: 2: Syntax error: "(" unexpected
Makefile:144: fallo en las instrucciones para el objetivo 'help'
make: *** [help] Error 2'

you know what could be the reason?

@martinwalsh

This comment has been minimized.

Show comment
Hide comment
@martinwalsh

martinwalsh May 24, 2018

Wow, these are great 🎉 Thanks for sharing!

I did something similar in ludicrous-makefiles (here and here), which handles multiple lines of help text for each target and also generate a prologue from any comments not directly associated with a target (I used #> as the marker instead of ##). No colors, but that's a nice touch so I'll probably add them!

@crifan I particularly like the readability and conciseness of your awk! For some reason it truncates targets by 1 character for me on ubuntu:18.04 (using mawk 1.3.3), but this change seems to help ...

19c19
< 			helpCommand = substr($$1, 0, index($$1, ":")-1); \
---
> 			helpCommand = $$1; sub(/:$$/, "", helpCommand); \

martinwalsh commented May 24, 2018

Wow, these are great 🎉 Thanks for sharing!

I did something similar in ludicrous-makefiles (here and here), which handles multiple lines of help text for each target and also generate a prologue from any comments not directly associated with a target (I used #> as the marker instead of ##). No colors, but that's a nice touch so I'll probably add them!

@crifan I particularly like the readability and conciseness of your awk! For some reason it truncates targets by 1 character for me on ubuntu:18.04 (using mawk 1.3.3), but this change seems to help ...

19c19
< 			helpCommand = substr($$1, 0, index($$1, ":")-1); \
---
> 			helpCommand = $$1; sub(/:$$/, "", helpCommand); \
@hans-d

This comment has been minimized.

Show comment
Hide comment
@hans-d

hans-d Sep 8, 2018

no perl, grouping per @label_with_some_description
(sorting only on @Label, skipping sorting the targets)

default: | help-prefix help-targets

help-prefix:
	@echo Whatever help info you want here, eg
	@echo '  make <target>'
	@echo '  make <target> <VAR>=<value>'
	@echo ''

## @info help
test:

## @abc help
test2:

## @info help2
a:

# --- helper

HELP_TARGET_MAX_CHAR_NUM = 20

help-targets:
	@awk '/^[a-zA-Z\-\_0-9]+:/ \
		{ \
			helpMessage = match(lastLine, /^## (.*)/); \
			if (helpMessage) { \
				helpCommand = substr($$1, 0, index($$1, ":")-1); \
				helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
				helpGroup = match(helpMessage, /^@([^ ]*)/); \
				if (helpGroup) { \
					helpGroup = substr(helpMessage, RSTART + 1, index(helpMessage, " ")-2); \
					helpMessage = substr(helpMessage, index(helpMessage, " ")+1); \
				} \
				printf "%s|  %-$(HELP_TARGET_MAX_CHAR_NUM)s %s\n", \
					helpGroup, helpCommand, helpMessage; \
			} \
		} \
		{ lastLine = $$0 }' \
		$(MAKEFILE_LIST) \
	| sort -t'|' -sk1,1 \
	| awk -F '|' ' \
			{ \
			cat = $$1; \
			if (cat != lastCat || lastCat == "") { \
				if ( cat == "0" ) { \
					print "Targets:" \
				} else { \
					gsub("_", " ", cat); \
					printf "Targets %s:\n", cat; \
				} \
			} \
			print $$2 \
		} \
		{ lastCat = $$1 }'
	

hans-d commented Sep 8, 2018

no perl, grouping per @label_with_some_description
(sorting only on @Label, skipping sorting the targets)

default: | help-prefix help-targets

help-prefix:
	@echo Whatever help info you want here, eg
	@echo '  make <target>'
	@echo '  make <target> <VAR>=<value>'
	@echo ''

## @info help
test:

## @abc help
test2:

## @info help2
a:

# --- helper

HELP_TARGET_MAX_CHAR_NUM = 20

help-targets:
	@awk '/^[a-zA-Z\-\_0-9]+:/ \
		{ \
			helpMessage = match(lastLine, /^## (.*)/); \
			if (helpMessage) { \
				helpCommand = substr($$1, 0, index($$1, ":")-1); \
				helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
				helpGroup = match(helpMessage, /^@([^ ]*)/); \
				if (helpGroup) { \
					helpGroup = substr(helpMessage, RSTART + 1, index(helpMessage, " ")-2); \
					helpMessage = substr(helpMessage, index(helpMessage, " ")+1); \
				} \
				printf "%s|  %-$(HELP_TARGET_MAX_CHAR_NUM)s %s\n", \
					helpGroup, helpCommand, helpMessage; \
			} \
		} \
		{ lastLine = $$0 }' \
		$(MAKEFILE_LIST) \
	| sort -t'|' -sk1,1 \
	| awk -F '|' ' \
			{ \
			cat = $$1; \
			if (cat != lastCat || lastCat == "") { \
				if ( cat == "0" ) { \
					print "Targets:" \
				} else { \
					gsub("_", " ", cat); \
					printf "Targets %s:\n", cat; \
				} \
			} \
			print $$2 \
		} \
		{ lastCat = $$1 }'
	
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment