aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/_notes/makefile.md
blob: b35aea26e883117be1db9145d8bd20385070cb0d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
---
title: make
subtitle: best practices
layout: nosidebar
links:
  - {rel: stylesheet, href: 'assets/css/guides.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

            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
  - 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))

            test:
            	echo '$(call escape,$(has_default))'
        dont:
          - |
            has_default ?= Default value

            test:
            	echo '$(call escape,$(has_default))'
          - |
            has_default ?= Default value
            export has_default

            test:
            	echo "$$has_default"
      - do:
          - |
            $(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 }

[detailed blog post]: {{ site.baseurl }}{% post_url 2020-05-20-makefile-escaping %}

{% 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 %}