J.N.
J.N.

Reputation: 8421

How to document a makefile?

Is there a way to write "standard" comments in a Makefile to later feed them to a Doxygen-like program so as to output a nice (HTML or man for instance) documentation ? I'd like to have a clear overview of my main targets somewhere but nothing too fancy.

Upvotes: 32

Views: 14629

Answers (9)

TMDevel89
TMDevel89

Reputation: 1

Allow writing a help message BEFORE the command line and divide it into sections

writing a help message BEFORE the command line based on https://stackoverflow.com/a/77566974/23306035 divide it into sections based on https://stackoverflow.com/a/30796664/23306035

build_test_1:
    echo ""

###@clean Help: message for clean_test_1
clean_test_1:
    echo ""

###@build Help: message for build_test_2
build_test_2:
    echo ""

###@clean Help: message for clean_test_2
clean_test_2:
    echo ""

### help: Print this help
help: #check build clean upload
    @awk ' \
        match($$0,/^###(@(\w+))? [Hh]elp: /,m) \
        {c=m[2];h=substr($$0,RLENGTH);next} \
        h&&/^[[:alpha:]][[:alnum:]_/-]+:/ \
        {help[c][idx[c]++]=sprintf("\033[36m%s\033[0m\t%s", substr($$1,1,index($$1,":")-1),h)} \
        1{c=0;h=0} \
        END{ \
            n=asorti(help, help_); \
            for (c = 1; c <= n; c++) { \
                if(help_[c]){indent="  ";printf "\n%s:\n", help_[c]}\
                asort(help[help_[c]]); \
                for(x in help[help_[c]]){print indent help[help_[c]][x]} \
            } \
        }' $(MAKEFILE_LIST) | column -s$$'\t' -tL

Output:


build:
  build_test_1   message for build_test_1
  build_test_2   message for build_test_2

clean:
  clean_test_1   message for clean_test_1
  clean_test_2   message for clean_test_2```

Upvotes: 0

Anton Prokofiev
Anton Prokofiev

Reputation: 957

One more example: Allow to write help message BEFORE command line.

You can use ":" in the help message to print it in a separate column.

## Another help message with data: in a separate column
test::
    echo ""

## Print this help
help::
    @awk '/^## /{c=substr($$0,3);next}c&&/^[[:alpha:]][[:alnum:]_/-]+:/{print substr($$1,1,index($$1,":")),c}1{c=0}' $(MAKEFILE_LIST) | column -s: -t -W 2,3 -o " "

Output:

test       Another help message with data                           in a separate column
help       Print this help                                         

Upvotes: 0

Zak
Zak

Reputation: 982

Here is my version that also strips away the dependencies of a target and aligns the help strings to an even column.

help:   ## Show this help.
    @sed -ne 's/^\([^[:space:]]*\):.*##/\1:\t/p' $(MAKEFILE_LIST) | column -t -s $$'\t'

image: src/*.s src/*.c src/**/*.c   ## Build the image
    riscv32-unknown-elf-gcc $^ -march=rv32i_zicsr -Wall -ggdb -O0 -o image -ffreestanding -nostdlib -lgcc

launch: ## Image Launch the image in renode
    renode --net vexriscv.resc --console

Output

help:    Show this help.
image    Build the image
launch:  Image Launch the image in renode

Upvotes: 1

nowox
nowox

Reputation: 29096

I made my own solution using a short Perl script that formats the help as other GNU tools:

SCRIPT_VERSION=v1.0
SCRIPT_AUTHOR=John Doe

all:                ##@Build Build all the project 

clean:              ##@Cleaning Remove all intermediate objects

mrproper: clean     ##@Cleaning Remove all output and interemediate objects

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

help: ##@Miscellaneous Show this help
    @echo -e "Usage: make [target] ...\n"
    @perl -e '$(HELP_FUN)' $(MAKEFILE_LIST)
    @echo -e "Written by $(SCRIPT_AUTHOR), version $(SCRIPT_VERSION)"
    @echo -e "Please report any bug or error to the author." 

Which gives this:

$ make help
Usage: make [target] ...

Miscellaneous:
  help                Show this help

Build:
  all                 Build all the project

Cleaning:
  clean               Remove all intermediate objects
  mrproper            Remove all output and interemediate objects

Written by John Doe, version v1.0
Please report any bug or error to the author.

Upvotes: 8

Rose
Rose

Reputation: 2809

In a makefile such as :

install: ## Do a
  @echo "foo"

start: ## Do b
  @echo "bar"

test: ## Do c
  @echo "baz"

help:
  @egrep -h '\s##\s' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m  %-30s\033[0m %s\n", $$1, $$2}'

Will output :

enter image description here

Upvotes: 14

MrDor
MrDor

Reputation: 108

I wrote the MakeHelp library exactly for that purpose. It lets you write the rule docs above each rule. Very easy to use.

I find it different from the other self-documenting Makefiles here as it has no repetitiveness and allows multiline docs and private rules.

Upvotes: 0

Frelling
Frelling

Reputation: 3507

The following is a simpler solution that does not require defining user functions or aggregating help text away from the rules they document.

# This is a regular comment, that will not be displayed

## ----------------------------------------------------------------------
## This is a help comment. The purpose of this Makefile is to demonstrate
## a simple help mechanism that uses comments defined alongside the rules
## they describe without the need of additional help files or echoing of
## descriptions. Help comments are displayed in the order defined within
## the Makefile.
## ----------------------------------------------------------------------

help:     ## Show this help.
    @sed -ne '/@sed/!s/## //p' $(MAKEFILE_LIST)

build:    ## Build something.

install:  ## Install something.

deploy:   ## Deploy something.

format:   ## Help comments are display with their leading whitespace. For
          ## example, all comments in this snippet are aligned with spaces.

Running make or make help results in the following:

----------------------------------------------------------------------
This is a help comment. The purpose of this Makefile is to demonstrate
a simple help mechanism that uses comments defined alongside the rules
they describe without the need of additional help files or echoing of
descriptions. Help comments are displayed in the order defined within
the Makefile.
----------------------------------------------------------------------
help:     Show this help.
build:    Build something.
install:  Install something.
deploy:   Deploy something.
format:   Help comments are display with their leading whitespace. For
          example, all comments in this snippet are aligned with spaces.

Upvotes: 67

Simon Michael
Simon Michael

Reputation: 2298

Self-Documenting Makefiles (John Graham-Cumming, 2005) lets you write the help alongside each rule. This is a lightweight and highly nifty solution that works at least with GNU Make.

Here's my slightly modified version (def-help-section helps organize long lists of rules).

Upvotes: 1

sarnold
sarnold

Reputation: 104050

One nice touch is to provide a phony help target that prints a summary of targets and options. From the Linux kernel Makefile:

help:
        @echo  'Cleaning targets:'
        @echo  '  clean           - Remove most generated files but keep the config and'
        @echo  '                    enough build support to build external modules'
        @echo  '  mrproper        - Remove all generated files + config + various backup files'
        @echo  '  distclean       - mrproper + remove editor backup and patch files'
        @echo  ''
        @echo  'Configuration targets:'
        @$(MAKE) -f $(srctree)/scripts/kconfig/Makefile help
        @echo  ''

It might be a bit of work to maintain the documentation this way, but I find it nicely separates what is intended for "users" versus what is intended for people maintaining the Makefile itself (inline comments).

Upvotes: 10

Related Questions