summaryrefslogtreecommitdiff
path: root/doc/guide/files/makefile.xml
blob: 41ef7f47a99433755e1d210c119324abbd9c26ae (plain)
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
<!-- $NetBSD: makefile.xml,v 1.4 2005/05/11 20:53:27 rillig Exp $ -->

<chapter id="makefile"> <?dbhtml filename="makefile.html"?>
  <title>Programming in <filename>Makefile</filename>s</title>

  <para>Pkgsrc consists of many <filename>Makefile</filename> fragments,
  each of which forms a well-defined part of the pkgsrc system. Using
  the &man.make.1; system as a programming language for a big system
  like pkgsrc requires some discipline to keep the code correct and
  understandable.</para>

  <para>The basic ingredients for <filename>Makefile</filename>
  programming are variables (which are actually macros) and shell
  commands. Among these shell commands may even be more complex ones
  like &man.awk.1; programs. To make sure that every shell command runs
  as intended it is necessary to quote all variables correctly when they
  are used.</para>

  <para>This chapter describes some patterns, that appear quite often in
  <filename>Makefile</filename>s, including the pitfalls that come along
  with them.</para>

  <sect1 id="makefile.variables">
    <title><filename>Makefile</filename> variables</title>

    <para><filename>Makefile</filename> variables contain strings that
    can be processed using the five operators ``='', ``+='', ``?='',
    ``:='', and ``!='', which are described in the &man.make.1; man
    page.</para>

    <para>When a variable's value is parsed from a
    <filename>Makefile</filename>, the hash character ``#'' and the
    backslash character ``\'' are handled specially. If a backslash is
    followed by a newline, any whitespace immediately before the
    backslash, the backslash, the newline, and any whitespace
    immediately the newline are replaced with a single space. A
    backspace character followed by a hash character are replaced with a
    single hash character. Otherwise the backslash is passed as is. In a
    variable assignment, any hash character that is not preceded by a
    backslash starts a comment that reaches upto the end of the logical
    line.</para>

    <para><emphasis>Note:</emphasis> Because of this parsing algorithm
    the only way to create a variable consisting of a single backslash
    can only be constructed using the ``!='' operator.</para>

    <para>So far for defining variables. The other thing you can do with
    variables is evaluating them. A variable is evaluated when it is
    part of the right side of the ``:='' or the ``!='' operator, or
    directly before executing a shell command which this variable is
    part of. In all other cases &man.make.1; performs lazy evaluation,
    that is variables are not evaluated until there's no other way. The
    ``modifiers'' mentioned in the man page also evaluate the
    variable.</para>

    <para>Some of the modifiers split the string into words and then
    operate on the words, others operate on the string as a whole. When
    a string is splitted into words, it is splitted as you would expect
    it from
    &man.sh.1;.</para>

    <para>There are several types of variables that must be handled
    differently.</para>

    <itemizedlist>

      <listitem><para><emphasis>Simple values</emphasis> (which I will
      call atoms) can contain any string, which does not have to be
      quoted in any way. All other types are somewhat restricted in
      their possible values.</para></listitem>

      <listitem><para><emphasis>Internal lists</emphasis> are lists that
      are never exported to any shell command. Their elements are
      separated by whitespace. Therefore the elements themselves cannot
      have embedded whitespace. Any other characters are allowed.
      Internal lists can be used in <!-- FIXME
      --><varname>.for</varname> loops. Examples are
      <varname>DEPENDS</varname>,
      <varname>BUILD_DEPENDS</varname>.</para></listitem>
      
      <listitem><para><emphasis>External lists</emphasis> are lists that
      may be exported to a shell command. Their elements can contain any
      characters, including whitespace. That's why they cannot be used
      in <!-- FIXME --><varname>.for</varname> loops. Examples are
      <varname>DISTFILES</varname> and
      <varname>MASTER_SITES</varname>.</para></listitem>

    </itemizedlist>
  </sect1>

  <sect1 id="makefile.code">
    <title>Code snippets</title>

    <para>This section presents you with some code snippets you should
    use in your own code. If you don't find anything appropriate here,
    you should test your code and add it here.</para>

    <sect2>
      <title>Adding things to a list</title>
      
      <programlisting>
ATOM=			foo * bar `date`
INT_LIST=		# empty
ANOTHER_INT_LIST=	apache-[0-9]*:../../www/apache
EXT_LIST=		# empty
ANOTHER_EXT_LIST=	a=b c=d

INT_LIST+=		${ATOM}			# 1
INT_LIST+=		${ANOTHER_INT_LIST}	# 2
EXT_LIST+=		${ATOM:Q}		# 3
EXT_LIST+=		${ANOTHER_EXT_LIST}	# 4
      </programlisting>

      <para>When you add an atom to an external list (example 3), it
      must be quoted. In all other cases, you must not add a quoting
      level. You must not merge internal and external lists, unless you
      are sure that all entries are correctly interpreted in both
      lists.</para>

    </sect2>

    <sect2>
      <title>Converting an internal list into an external list</title>

      <programlisting>
EXT_LIST=	# empty
.for i in ${INT_LIST}
EXT_LIST+=	${i:Q}
.endfor
      </programlisting>

      <para>This code converts the internal list
      <varname>INT_LIST</varname> into the external list
      <varname>EXT_LIST</varname>. As the elements of an internal list
      are unquoted they must be quoted here.</para>

    </sect2>

    <sect2>
      <title>Passing variables to a shell command</title>

      <programlisting>
ATOM=		foo bar <    > * `date` $$HOME ' "
EXT_LIST=	atom=${ATOM:Q} x=second\ item

all:
	echo ${ATOM}			# 1
	echo "${ATOM}"			# 2
	echo "${ATOM:Q}"		# 3
	echo ${ATOM:Q}			# 4
	echo x${ATOM:Q} | sed 1s,.,,	# 5
	env ${EXT_LIST} /bin/sh -c 'echo "$$atom"; echo "$$x"'
      </programlisting>

      <para>Example 1 leads to a syntax error in the shell, as the
      characters are just copied.</para>
      
      <para>Example 2 leads to a syntax error too, and if you leave
      out the last " character from <varname>${ATOM}</varname>,
      &man.date.1; would be executed. The <varname>$HOME</varname> shell
      variable would be evaluated, too.</para>
      
      <para>Example 3 would output each space character preceded by a
      backslash (or not), depending on the implementation of the
      &man.echo.1; command.</para>
      
      <para>Example 4 handles correctly every string that does not start
      with a dash. In that case, the result depends on the
      implementation of the &man.echo.1; command. As long as you can
      guarantee that your input does not start with a dash this form is
      appropriate.</para>

      <para>Example 5 handles even the case of a leading dash
      correctly.</para>

      <para>The <varname>EXT_LIST</varname> does not need to be quoted
      because the quoting has already be done when adding elements to
      the list.</para>

      <para>As internal lists shall not be passed to the shell, there is
      no example for it.</para>

    </sect2>
  </sect1>
</chapter>