diff options
Diffstat (limited to '')
-rw-r--r-- | _notes/makefile.md | 172 | ||||
-rw-r--r-- | _posts/2020-05-20-makefile-escaping.md | 52 |
2 files changed, 123 insertions, 101 deletions
diff --git a/_notes/makefile.md b/_notes/makefile.md index fb52d43..2c01406 100644 --- a/_notes/makefile.md +++ b/_notes/makefile.md @@ -1,65 +1,129 @@ --- title: Makefile subtitle: best practices ---- -Best practices for my Makefiles (sorry for the botched highlighting). - -```make -# Put this in the top of the Makefile: - -MAKEFLAGS += --no-builtin-rules --no-builtin-variables --warn-undefined-variables -unexport MAKEFLAGS -.DEFAULT_GOAL := all -.DELETE_ON_ERROR: -.SUFFIXES: -SHELL := bash -.SHELLFLAGS := -eu -o pipefail -c - -escape = $(subst ','\'',$(1)) - -define noexpand -ifeq ($$(origin $(1)),environment) - $(1) := $$(value $(1)) -endif -ifeq ($$(origin $(1)),environment override) - $(1) := $$(value $(1)) -endif -ifeq ($$(origin $(1)),command line) - override $(1) := $$(value $(1)) -endif -endef +layout: nosidebar +links: + - {rel: stylesheet, href: 'assets/css/bash.css'} +features: + - note: This should go on top of every Makefile. + sections: + - do: + - | + MAKEFLAGS += --no-builtin-rules --no-builtin-variables --warn-undefined-variables + unexport MAKEFLAGS + .DEFAULT_GOAL := all + .DELETE_ON_ERROR: + .SUFFIXES: + SHELL := bash + .SHELLFLAGS := -eu -o pipefail -c -# OK, now some examples of how to use it: + escape = $(subst ','\'',$(1)) -.PHONY: all -all: test-escape test-noexpand + define noexpand + ifeq ($$(origin $(1)),environment) + $(1) := $$(value $(1)) + endif + ifeq ($$(origin $(1)),environment override) + $(1) := $$(value $(1)) + endif + ifeq ($$(origin $(1)),command line) + override $(1) := $$(value $(1)) + endif + endef + - note: Quote command arguments and use the `escape` function on variables and shell output. + sections: + - do: + - | + var := Includes ' quote + test: + printf '%s\n' '$(call escape,$(var))' + dont: + - | + var := Includes space + test: + printf '%s\n' $(var) + - | + var := Includes ' quote + test: + printf '%s\n' '$(var)' + - do: + - | + cwd := $(shell pwd) + test: + printf 'In directory %s\n' '$(call escape,$(cwd))' + dont: + - | + cwd := $(shell pwd) + test: + printf 'In directory %s\n' $(cwd) + - | + cwd := $(shell pwd) + test: + printf 'In directory %s\n' '$(cwd)' + - note: Use the `noexpand` function on environment variables or variables that can be overridden on the command line. + sections: + - do: + - | + has_default ?= Default value + $(eval $(call noexpand,has_default)) -# Always put command arguments in single quotes. -# Escape variables and shell output using the escape function. + test: + echo '$(call escape,$(has_default))' + dont: + - | + has_default ?= Default value -var_with_quote := Includes ' quote + test: + echo '$(call escape,$(has_default))' + - | + has_default ?= Default value + export has_default -.PHONY: test-escape -test-escape: - printf '%s\n' '$(call escape,$(var_with_quote))' - printf '%s\n' '$(call escape,$(shell echo "Includes ' quote"))' + test: + echo "$$has_default" + - do: + - | + $(eval $(call noexpand,ENV_VAR)) -# The above recipe will print "Includes ' quote" twice. - -# If you define variables using ?= or use environment variables in your -# Makefile, use noexpand on them (to safeguard against ${accidental} -# references). - -var_with_default ?= Accidental reference? -$(eval $(call noexpand,var_with_default)) - -$(eval $(call noexpand,env_var)) + test: + echo '$(call escape,$(ENV_VAR))' + dont: + - | + test: + echo '$(call escape,$(ENV_VAR))' +--- +I've made a [detailed blog post] about how all of this works. +{: .alert .alert-info } -.PHONY: test-noexpand -test-noexpand: - printf '%s\n' '$(call escape,$(var_with_default))' - printf '%s\n' '$(call escape,$(env_var))' +[detailed blog post]: {{ site.baseurl }}{% post_url 2020-05-20-makefile-escaping %} -# The above recipe will print "Accidental ${reference}" twice if you run using -# env_var='Accidental ${reference}' make var_with_default='Accidental ${reference}' -``` +{% for feature in page.features %} + {{ feature.note | markdownify }} + {% for section in feature.sections %} +<div class="row"> + {% if section.do %} + {% if section.dont %}{% assign width = "6" %}{% else %}{% assign width = "12" %}{% endif %} + <div class="col-md-{{ width }}"> + {% for guide in section.do %} + <div class="pre_container pre_do"> + <pre>{{ guide }}</pre> + <div class="pre_mark"><span class="glyphicon glyphicon-ok"></span></div> + </div> + {% endfor %} + </div> + {% endif %} + {% if section.dont %} + {% if section.do %}{% assign width = "6" %}{% else %}{% assign width = "12" %}{% endif %} + <div class="col-md-{{ width }}"> + {% for guide in section.dont %} + <div class="pre_container pre_dont"> + <pre>{{ guide }}</pre> + <div class="pre_mark"><span class="glyphicon glyphicon-remove"></span></div> + </div> + {% endfor %} + </div> + {% endif %} +</div> + {% endfor %} + <hr/> +{% endfor %} diff --git a/_posts/2020-05-20-makefile-escaping.md b/_posts/2020-05-20-makefile-escaping.md index 4190fff..7d468dc 100644 --- a/_posts/2020-05-20-makefile-escaping.md +++ b/_posts/2020-05-20-makefile-escaping.md @@ -2,6 +2,11 @@ title: Escaping characters in Makefile excerpt: Making less error-prone. --- +TL;DR: visit [this page] for a short and concise version of this article. +{: .alert .alert-success } + +[this page]: {{ site.baseurl }}{% link _notes/makefile.md %} + I'm a big sucker for irrelevant nitpicks like properly quoting arguments in shell scripts. I've also recently started using GNU make as a substitute for one-line shell @@ -32,53 +37,6 @@ the choice of shell is very relevant. The Makefiles in this post specify `bash` explicitly using the `SHELL` variable, but the same rules should apply for all similar `sh`-like shells. -TL;DR ------ - -Visit [this page] for an all-in-one Makefile template. -{: .alert .alert-info } - -[this page]: {{ site.baseurl }}{% link _notes/makefile.md %} - -* Put the prologue above at the top of your Makefile. -* Quote command arguments in Makefiles using single quotes `'`. -* Define a helper function: - - escape = $(subst ','\'',$(1)) - - Instead of: - - test: - echo '$(var)' - - do - - test: - echo '$(call escape,$(var))' - -* If you use environment variables in your Makefile (or you override variables -on the command line), add the following lengthy snippet: - - define noexpand - ifeq ($$(origin $(1)),environment) - $(1) := $$(value $(1)) - endif - ifeq ($$(origin $(1)),environment override) - $(1) := $$(value $(1)) - endif - ifeq ($$(origin $(1)),command line) - override $(1) := $$(value $(1)) - endif - endef - - Then `eval` the `noexpand` function output for every possibly overridden -variable or a used environment variable: - - has_default ?= Default value - $(eval $(call noexpand,has_default)) - - $(eval $(call noexpand,ENV_VAR)) - Quoting arguments ----------------- |