Skip to content

Instantly share code, notes, and snippets.

@JasonHewison
Last active February 28, 2018 20:00
Show Gist options
  • Save JasonHewison/25e49e25c6575793cfc75cf6a94e787a to your computer and use it in GitHub Desktop.
Save JasonHewison/25e49e25c6575793cfc75cf6a94e787a to your computer and use it in GitHub Desktop.
./.makefilehelp
#!/usr/bin/env bash
BOLD_RED='\033[1;31m'
BOLD_GREEN='\033[1;32m'
COLOR_NC='\033[0m'
BOLD='\033[1m'
current_dir=`pwd`
makefile=${1:-"${current_dir}/Makefile"}
target=$2
targets=$(cat $makefile \
| grep -e '^[a-zA-Z0-9].*:' \
| grep -v '%' \
| grep -v '^ci' \
| sed 's/\(.*\):.*$/\1/' \
| sort)
# If no target has been passed in then try installing
if [ $# -le 1 ]; then
echo
echo -e "${BOLD}.makefilehelp${COLOR_NC} Installer"
echo "~~~~~~~~~~~~~~~~~~~~~~~"
echo
# If help target already exists then throw an error
if echo "$targets" | grep "help" >/dev/null 2>&1; then
echo -e "${BOLD_RED}ERROR${COLOR_NC}: help target already exists in Makefile ($makefile)" >&2
exit 1;
fi
echo "" >> $makefile
echo '#help:' >> $makefile
echo '# View help documentation for the Makefile' >> $makefile
echo '#' >> $makefile
echo '# - make help' >> $makefile
echo '# View a summary of the help documentation' >> $makefile
echo '#' >> $makefile
echo '# - make help:[ target ]' >> $makefile
echo '# View the help documentation for a specific target' >> $makefile
echo '# e.g.' >> $makefile
echo '# make help:help' >> $makefile
echo '#' >> $makefile
echo '.PHONY: help' >> $makefile
echo 'help:' >> $makefile
echo ' @$(MAKE) -f $(abspath $(lastword $(MAKEFILE_LIST))) help:help' >> $makefile
echo 'help\:%:' >> $makefile
echo ' @(echo $@ \' >> $makefile
echo ' | sed "s/help\://" \' >> $makefile
echo ' | xargs -I "{}" ./.makefilehelp $(abspath $(lastword $(MAKEFILE_LIST))) "{}"; \' >> $makefile
echo ' echo "(press q to quit)" \' >> $makefile
echo ' ) | less -R' >> $makefile
echo -e "${BOLD_GREEN}SUCCESS${COLOR_NC}: Added help targets to ${makefile}"
if [ ! -f "$(dirname $makefile)/.makefilehelp" ]; then
cp $0 "$(dirname $makefile)/.makefilehelp"
echo -e "${BOLD_GREEN}SUCCESS${COLOR_NC}: Added .makefilehelp script to $(dirname $makefile)"
fi
exit 0;
fi
# target has been supplied so continue showing the help docs
# Check if the target is valid for the Makefile
if echo "$targets" | grep "$target" >/dev/null 2>&1; then
echo
echo -e "${BOLD}COMMAND${COLOR_NC}"
echo -e " make $target"
echo
echo -e "${BOLD}DESCRIPTION${COLOR_NC}"
# Check if there are any docs for the target
if ! cat $makefile | grep "^#$target:" >/dev/null 2>&1; then
echo -e " No help documentation found";
else
helptext=$(cat $makefile \
| awk -v RS= -F: "/#$target:/,/#$target:/" \
| sed "/^$target:/ d" \
| sed '/^#/! d' \
| sed 1d \
| sed 's/^#//')
leadingLength=`echo "$helptext" | awk '{t=length($0);sub("^ *","");print t-length($0)}' | head -n 1`
echo "$helptext" \
| sed "s/^$(head -c $leadingLength < /dev/zero | tr '\0' ' ')/ /" \
| sed 's/[[:space:]]*$//'
fi
else
echo -e "${BOLD}COMMAND${COLOR_NC}"
echo -e " make $target"
echo
echo -e "${BOLD}ERROR${COLOR_NC}"
echo -e " ${BOLD}$target${COLOR_NC} does not exist in $makefile"
fi
echo
echo -e "${BOLD}TARGETS${COLOR_NC}"
echo -e " Available targets:"
echo $targets \
| xargs \
| sed 's/ /, /g' \
| fmt -w 60 \
| sed 's/^/ /'
echo
echo -e " ${BOLD}make${COLOR_NC} [ target ]"
echo -e " Run the specified makefile target"
echo
echo -e " ${BOLD}make${COLOR_NC} help:[ target ]"
echo -e " View the help documentation for the specified makefile target"
echo -e " e.g."
echo -e " make help:help"
echo
echo

.makefilehelp

Synopsis

  • The .makefilehelp bash script enables you to create make help and make help:[ target ] commands which display documentation from comments in your Makefile.
  • The help documentation is designed to look and behave like manpages, e.g. man make
  • The aim is to encourage documenting Makefile targets.

Installation

To install .makefilehelp run the following:

curl https://gist.githubusercontent.com/JasonHewison/25e49e25c6575793cfc75cf6a94e787a/raw/cc2d2ac9587457ab3d3f73a765ec632bab355ed4/.makefilehelp --output .makefilehelp

chmod +x .makefilehelp

./.makefilehelp

The make help and make help:help commands should now be available.

The example Makefile in this gist containes examples of how to provide documentation. You need to do is start the documentation with the following tag.

#[ target ]:

e.g.

#start:

Then any comments between that tag and the matching target will be included in the make help:[ target ] documentation. If there are any non-comment elements in between, e.g. Makefile variables these will be ignored. e.g.

#healthcheck:
# Does some sort of healthcheck thing.
# Has a default timeout of 1 minute.
TIMEOUT=60
healthcheck:
	./do-healthcheck.sh ${TIMEOUT}

Finally, when you run make help it is actually showing the help documentation for the help command. You can customize the help text for each project you use it in and optionally include an overview of the project.

Usage Examples

To run the following examples do the following:

echo "Setup an example folder"
mkdir makefilehelp-example
cd makefilehelp-example

curl https://gist.githubusercontent.com/JasonHewison/25e49e25c6575793cfc75cf6a94e787a/raw/dd4223d3752b39c029001034b0ae973c313b767d/Makefile-example --output Makefile

echo "Install .makefilehelp"
curl https://gist.githubusercontent.com/JasonHewison/25e49e25c6575793cfc75cf6a94e787a/raw/cc2d2ac9587457ab3d3f73a765ec632bab355ed4/.makefilehelp --output .makefilehelp

chmod +x .makefilehelp

./.makefilehelp

You should now be able to run the following examples.

View the documentation

make help

View the documentation for a documented target

make help:start

View the documentation for an undocumented target

make help:magic

View the documentation for an invalid target

make help:bob

Motivation

The .makefilehelp script is intended to help document Makefile's that are used as tooling for a repo.

In a lot of project's I've worked on Makefiles are used as a way of providing consistent tooling for all projects so that any engineer unfamiliar with a repo is able to make build, make test and make run.

Sometimes the more complicated a repo, the bigger and more unweildy a Makefile can become, being able to run make help is intended to assist new engineers in learning a repo and it's tooling.

.PHONY: start stop magic
#start:
# Start the development environment.
#
# Currently this just echo's "do some startup stuff"
#
# If you use your imagination, magic things are now in action.
start:
echo "do some startup stuff"
#stop:
# Stop the development environment.
#
# Currently this just echo's "do some shutdown stuff"
#
# Given that there's nothing to start, technically it works perfectly.
stop:
echo "do some shutdown stuff"
magic:
echo "magic!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment