3ce24f9a87
list to an external list" had been wrong.
306 lines
12 KiB
XML
306 lines
12 KiB
XML
<!-- $NetBSD: makefile.xml,v 1.11 2005/05/14 03:30:56 rillig Exp $ -->
|
|
|
|
<!-- based on:
|
|
pkgsrc/bootstrap/bmake/for.c 1.1.1.1
|
|
pkgsrc/bootstrap/bmake/make.1 1.3
|
|
pkgsrc/bootstrap/bmake/str.c 1.1.1.1
|
|
pkgsrc/bootstrap/bmake/var.c 1.2
|
|
-->
|
|
|
|
<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 in front of the
|
|
backslash, the backslash, the newline, and any whitespace
|
|
immediately behind the newline are replaced with a single space. A
|
|
backspace character and an immediately following 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 continues 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
|
|
is using the ``!='' operator, for example: <!-- FIXME
|
|
--><varname>BACKSLASH!=echo "\\"</varname>.</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 the 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>No rule without exception—the ``.for'' loop does not
|
|
follow the shell quoting rules but splits at sequences of
|
|
whitespace.</para>
|
|
|
|
<para>There are several types of variables that should be handled
|
|
differently. Strings and two types of lists.</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para><emphasis>Strings</emphasis> can contain arbitrary
|
|
characters. Nevertheless you should restrict yourself to only
|
|
using printable characters. Examples are
|
|
<varname>PREFIX</varname> and
|
|
<varname>COMMENT</varname>.</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> and
|
|
<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>
|
|
|
|
<sect2 id="makefile.variables.names">
|
|
<title>Naming conventions</title>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>All variable names starting with an underscore
|
|
are reserved for use by the pkgsrc infrastructure. They shall
|
|
not be used by package
|
|
<filename>Makefile</filename>s.</para></listitem>
|
|
|
|
<listitem><para>In <!-- FIXME --><varname>.for</varname> loops
|
|
you should use lowercase variable names for the iteration
|
|
variables.</para></listitem>
|
|
|
|
</itemizedlist>
|
|
</sect2>
|
|
|
|
</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>
|
|
STRING= 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+= ${STRING} # 1
|
|
INT_LIST+= ${ANOTHER_INT_LIST} # 2
|
|
EXT_LIST+= ${STRING:Q} # 3
|
|
EXT_LIST+= ${ANOTHER_EXT_LIST} # 4
|
|
</programlisting>
|
|
|
|
<para>When you add a string 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. The reason for appending
|
|
<varname>""</varname> is explained below.</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Passing variables to a shell command</title>
|
|
|
|
<programlisting>
|
|
STRING= foo bar < > * `date` $$HOME ' "
|
|
EXT_LIST= string=${STRING:Q} x=second\ item
|
|
|
|
all:
|
|
echo ${STRING} # 1
|
|
echo "${STRING}" # 2
|
|
echo "${STRING:Q}" # 3
|
|
echo ${STRING:Q} # 4
|
|
echo x${STRING:Q} | sed 1s,.,, # 5
|
|
env ${EXT_LIST} /bin/sh -c 'echo "$$string"; 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>${STRING}</varname>,
|
|
&man.date.1; will be executed. The <varname>$HOME</varname> shell
|
|
variable would be evaluated, too.</para>
|
|
|
|
<para>Example 3 outputs 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>
|
|
|
|
<sect2>
|
|
<title>Quoting guideline</title>
|
|
|
|
<para>There are many possible sources of wrongly quoted variables.
|
|
This section lists some of the commonly known ones.</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem><para>Whenever you use the value of a list, think
|
|
about what happens to leading or trailing whitespace. If the
|
|
list is a well-formed shell expression you can apply the
|
|
<varname>:M*</varname> modifier to strip leading and trailing
|
|
whitespace from each word. The <varname>:M</varname> operator
|
|
first splits its argument according to the rules of the shell,
|
|
and then creates a new list consisting of all words that match
|
|
the shell glob expression <varname>*</varname>, that is: all.
|
|
One class of situations where this is needed is when adding a
|
|
variable like <varname>CPPFLAGS</varname> to
|
|
<varname>CONFIGURE_ARGS</varname>. If the configure script
|
|
invokes other configure scripts it strips the leading and
|
|
trailing whitespace from the variable and then passes it to the
|
|
other configure scripts. But these configure scripts expect the
|
|
(child) <varname>CPPFLAGS</varname> variable to be the same as
|
|
the parent <varname>CPPFLAGS</varname>. That's why we better
|
|
pass the <varname>CPPFLAGS</varname> value properly trimmed. And
|
|
here is how we do it:</para>
|
|
|
|
<programlisting>
|
|
CPPFLAGS= # empty
|
|
CPPFLAGS+= -Wundef -DPREFIX=\"${PREFIX:Q}\"
|
|
CPPFLAGS+= ${MY_CPPFLAGS}
|
|
|
|
CONFIGURE_ARGS+= CPPFLAGS=${CPPFLAGS:M*:Q}
|
|
|
|
all:
|
|
echo x${CPPFLAGS:Q}x # leading and trailing whitespace
|
|
echo x${CONFIGURE_ARGS}x # properly trimmed
|
|
</programlisting></listitem>
|
|
|
|
<listitem><para>The example above contains one bug: The
|
|
<varname>${PREFIX}</varname> is a properly quoted shell
|
|
expression, but there is the C compiler after it, which also
|
|
expects a properly quoted string (this time in C syntax). The
|
|
version above is therefore only correct if
|
|
<varname>${PREFIX}</varname> does not have embedded backslashes
|
|
or double quotes. If you want to allow these, you have to add
|
|
another layer of quoting to each variable that is used as a C
|
|
string literal. You cannot use the <varname>:Q</varname>
|
|
operator for it, as this operator only works for the
|
|
shell.</para></listitem>
|
|
|
|
<listitem><para>Whenever a variable can be empty the
|
|
<varname>:Q</varname> operator can have surprising results. Here
|
|
are two completely different cases which can be solved with the
|
|
same trick.</para>
|
|
|
|
<programlisting>
|
|
EMPTY= # empty
|
|
empty_test:
|
|
for i in a ${EMPTY:Q} c; do \
|
|
echo "$$i"; \
|
|
done
|
|
|
|
for_test:
|
|
.for i in a:\ a:\test.txt
|
|
echo ${i:Q}
|
|
echo "foo"
|
|
.endfor
|
|
</programlisting>
|
|
|
|
<para>The first example will only print two of the three lines
|
|
we might have expected. This is because
|
|
<varname>${EMPTY:Q}</varname> expands to the empty string, which
|
|
the shell cannot see. The workaround is to write
|
|
<varname>${EMPTY:Q}""</varname>. This pattern can be often found
|
|
as <varname>${TEST} -z ${VAR:Q}</varname> or as <varname>${TEST}
|
|
-f ${FNAME:Q}</varname> (both of these are wrong).</para>
|
|
|
|
<para>The second example will only print three lines instead of
|
|
four. The first line looks like <varname>a:\ echo foo</varname>.
|
|
This is because the backslash of the value
|
|
<varname>a:\</varname> is interpreted as a line-continuation by
|
|
&man.make.1;, which makes the second line the arguments of the
|
|
&man.echo.1; command from the first line. To avoid this, write
|
|
<varname>${i:Q}""</varname>.</para></listitem>
|
|
|
|
</itemizedlist>
|
|
</sect2>
|
|
|
|
</sect1>
|
|
</chapter>
|