Skip to content

Instantly share code, notes, and snippets.

@fhuitelec
Last active February 5, 2017 16:16
Show Gist options
  • Save fhuitelec/1f7a439be0dc6749857c090fcd5601a4 to your computer and use it in GitHub Desktop.
Save fhuitelec/1f7a439be0dc6749857c090fcd5601a4 to your computer and use it in GitHub Desktop.
Powerful Makefile template
# Badass Makefile
Badass makefile template ready to use.

Badass Makefile

You have at your disposal print helpers, autodocumented sub-makes, environment handlers, etc.

Install

Copy/paste the content of zz1.download-gist.sh at the root of your project. The following files will be created:

  • Makefile
  • .utils.make

Be careful if you already have a Makefile, it's going to be overriden.

Usage

TODO

#!/bin/bash
# Check dependencies
where wget 1> /dev/null 2>&1 || (echo 'Error: wget is not installed' && (exit 127))
# If dependencies are satisfied
if [ $? -eq 0 ]; then
# Download raw gists
wget https://gist.githubusercontent.com/fhuitelec/1f7a439be0dc6749857c090fcd5601a4/raw/zz2.utils.make
wget https://gist.githubusercontent.com/fhuitelec/1f7a439be0dc6749857c090fcd5601a4/raw/zz3.Makefile.make
# Rename gists
mv zz3.Makefile.make Makefile
mv zz2.utils.make .utils.make
fi
#!/usr/bin/make -f
####################### INTERNALS ###########################
.SILENT: ; # no need for @ to silent commands #
.ONESHELL: ; # recipes execute in same shell #
.EXPORT_ALL_VARIABLES: ; # send all vars to shell #
.NOTPARALLEL: ; # wait for this target to finish #
default: help; # default target #
Makefile: ; # skip prerequisite discovery #
#############################################################
######## UTILS ###########
##########################
export BLUE=\033[0;34m
export YELLOW=\033[0;33m
export RED=\033[0;31m
export NO_COLOR=\033[0;37m
# Prints Makefile targets having a comment in the following format:
# ## $(type) This is a comment
#
# Example:
# ## COMMAND This is a comment
# $type type of comment you want to display. In the example above, it's COMMAND
.print-detailed-help:
tabs 4
grep -E '^[a-zA-Z0-9_-]+:.*?## $(type)(.*)$$' $(MAKEFILE_LIST) | cut -d":" -f2- | awk 'BEGIN {FS = ":.*?## $(type)"}; {printf "\t%-30s %s\n", $$1, $$2}'
# Prints pretty help to have a uniform help
# $item item you want to present
# $description description of the item
.print-pretty-help:
printf "\t%-31s %s\n" "$(item)" "$(description)"
# Print basic message in white
# $message message to print
.print:
tabs 4
printf "$(message)\n"
# Print info message in blue
# $message message to print
.info:
tabs 4
printf "%b%s%b\n" "${BLUE}" "$(message)" "${NO_COLOR}"
# Print notice message in yellow
# $message message to print
.notice:
tabs 4
printf "%b%s%b\n" "${YELLOW}" "$(message)" "${NO_COLOR}"
# Print error message in red
# $message message to print
.error:
tabs 4
printf "%b%s%b\n" "${RED}" "$(message)" "${NO_COLOR}"
# Ask a yes or no question, return kind of a boolean
# Usage: @if ! make .prompt-yesno message='You sure?' 2> /dev/null; then \ (...)
# $message message you want to prompt
.prompt-yesno:
echo ""; \
printf "$(message) [Y/n]: "
read -rs -n 1 yn; \
echo ""; \
echo ""; \
[[ -z $$yn ]] || [[ $$yn == [yY] ]] && echo Y >&2 || (echo N >&2 && exit 1)
# Evaluates environment and returns kind of a boolean
# Usage: @if make .is-production env=${ENVIRONMENT} 2> /dev/null; then \ (...)
# $env environment you want to evaluate
.is-production:
[[ -z ${env} ]] || [[ ${env} == 'PRODUCTION' ]] && echo Y >&2 || (echo N >&2 && exit 1)
# Exits if global environment is not set to production
# Usage: use on make recipes you want to run exclusively on production
.check-production:
@if [ ${ENVIRONMENT} == 'DEVELOPMENT' ]; then\
make .error message="Error: You cannot execute this make recipe on development";\
exit 1; \
fi
# Exits if global environment is not set to production
# Usage: use on make recipes you want to run exclusively on development
.check-development:
@if [ ${ENVIRONMENT} == 'PRODUCTION' ]; then\
make .error message="Error: You cannot execute this make recipe on production";\
exit 1; \
fi
#!/usr/bin/make -f
###### INCLUDES ######
include .utils.make #
######################
####################### EXPORTS ###########################
export ENVIRONMENT = 'DEVELOPMENT' #
###########################################################
command-on-production: .check-production
command-on-production: ## COMMAND-PRODUCTION Command example that runs on production only
echo ${ENVIRONMENT}
command-both-env: ## COMMAND-PRODUCTION Command example that runs both on production and development
command-both-env: ## COMMAND-DEVELOPMENT Command example that runs both on production and development
@if make .is-production env=${ENVIRONMENT} 2> /dev/null; then \
echo 'You''re on production!'; \
else \
echo 'You''re not on production!'; \
fi
command-on-development: .check-development
command-on-development: ## COMMAND-DEVELOPMENT
echo 'You''re on development!'
help: ## COMMAND Print this help
make .notice message="Example custom makefile"
make .print message=""
make .notice message="USAGE"
make .print message="\tmake [development|production] COMMAND"
make .print message=""
make .notice message="ENVIRONMENT"
make .print-detailed-help type=ENVIRONMENT
make .print message=""
make .notice message="COMMAND DEVELOPMENT"
make .print-detailed-help type=COMMAND-DEVELOPMENT
make .print message=""
make .notice message="COMMAND PRODUCTION"
make .print-detailed-help type=COMMAND-PRODUCTION
production: ## ENVIRONMENT Set environment to production
$(eval export ENVIRONMENT = 'PRODUCTION')
development: ## ENVIRONMENT Set environment to development
$(eval export ENVIRONMENT = 'DEVELOPMENT')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment