mirror of
https://github.com/Stichting-MINIX-Research-Foundation/pkgsrc-ng.git
synced 2025-09-08 03:44:13 -04:00
288 lines
10 KiB
XML
288 lines
10 KiB
XML
<!-- $NetBSD: makefile.xml,v 1.26 2016/06/11 19:54:44 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.style">
|
|
<title>Caveats</title>
|
|
|
|
<itemizedlist><listitem><para>When you are creating a file as a
|
|
target of a rule, always write the data to a temporary file first
|
|
and finally rename that file. Otherwise there might occur an error
|
|
in the middle of generating the file, and when the user runs
|
|
&man.make.1; for the second time, the file exists and will not be
|
|
regenerated properly. Example:</para>
|
|
|
|
<programlisting>
|
|
wrong:
|
|
@echo "line 1" > ${.TARGET}
|
|
@echo "line 2" >> ${.TARGET}
|
|
@false
|
|
|
|
correct:
|
|
@echo "line 1" > ${.TARGET}.tmp
|
|
@echo "line 2" >> ${.TARGET}.tmp
|
|
@false
|
|
@mv ${.TARGET}.tmp ${.TARGET}
|
|
</programlisting>
|
|
|
|
<para>When you run <command>make wrong</command> twice, the file
|
|
<filename>wrong</filename> will exist, although there was an error
|
|
message in the first run. On the other hand, running <command>make
|
|
correct</command> gives an error message twice, as expected.</para>
|
|
|
|
<para>You might remember that &man.make.1; sometimes removes
|
|
<literal>${.TARGET}</literal> in case of error, but this only
|
|
happens when it is interrupted, for example by pressing
|
|
<literal>^C</literal>. This does <emphasis>not</emphasis> happen
|
|
when one of the commands fails (like &man.false.1; above).</para>
|
|
|
|
</listitem>
|
|
</itemizedlist>
|
|
</sect1>
|
|
|
|
<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
|
|
backslash 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>The evaluation of variables either happens immediately or lazy.
|
|
It happens immediately when the variable occurs
|
|
on the right-hand side of the ``:='' or the ``!='' operator, in a
|
|
<varname>.if</varname> condition or a <varname>.for</varname> loop.
|
|
In the other cases, it is evaluated lazily.</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 split into words, it is split like in &man.sh.1;.</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 <command>.for</command> 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 <command>.for</command> 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 <command>.for</command> loops you should use
|
|
lowercase variable names for the iteration
|
|
variables.</para></listitem>
|
|
|
|
<listitem><para>All list variables should have a ``plural''
|
|
name, e.g. <varname>PKG_OPTIONS</varname> or
|
|
<varname>DISTFILES</varname>.</para></listitem>
|
|
|
|
</itemizedlist>
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
<sect1 id="makefile.code">
|
|
<title>Code snippets</title>
|
|
|
|
<sect2 id="adding-to-list">
|
|
<title>Adding things to a list</title>
|
|
|
|
<para>When adding a string that possibly contains whitespace or quotes to
|
|
a list (example 1), it must be quoted using the <code>:Q</code>
|
|
modifier.</para>
|
|
|
|
<para>When adding another list to a list (example 2), it must not be
|
|
quoted, since its elements are already quoted.</para>
|
|
|
|
<programlisting>
|
|
STRING= foo * bar `date`
|
|
LIST= # empty
|
|
ANOTHER_LIST= a=b c=d
|
|
|
|
LIST+= ${STRING:Q} # 1
|
|
LIST+= ${ANOTHER_LIST} # 2
|
|
</programlisting>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="echo-literal">
|
|
<title>Echoing a string exacty as-is</title>
|
|
|
|
<para>Echoing a string containing special characters needs special
|
|
work.</para>
|
|
|
|
<programlisting>
|
|
STRING= foo bar < > * `date` $$HOME ' "
|
|
EXAMPLE_ENV= string=${STRING:Q} x=multiple\ quoted\ words
|
|
|
|
all:
|
|
echo ${STRING} # 1
|
|
echo ${STRING:Q} # 2
|
|
printf '%s\n' ${STRING:Q}'' # 3
|
|
env ${EXAMPLE_ENV} sh -c 'echo "$$string"; echo "$$x"' # 4
|
|
</programlisting>
|
|
|
|
<para>Example 1 leads to a syntax error in the shell, as the characters
|
|
are just copied.</para>
|
|
|
|
<para>Example 2 quotes the string so that the shell interprets it
|
|
correctly. But the echo command may additionally interpret strings with a
|
|
leading dash or those containing backslashes.</para>
|
|
|
|
<para>Example 3 can handle arbitrary strings, since &man.printf.1; only
|
|
interprets the format string, but not the next argument.</para>
|
|
|
|
<para>In example 4, the <varname>EXAMPLE_ENV</varname> does not
|
|
need to be quoted because the quoting has already been done
|
|
when adding elements to the list.</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 id="cflags-gnu-configure">
|
|
<title>Passing <varname>CFLAGS</varname> to GNU configure scripts</title>
|
|
|
|
<para>When passing <varname>CFLAGS</varname> or similar variables to a
|
|
GNU-style configure script (especially those that call other configure
|
|
scripts), it must not have leading or trailing whitespace, since
|
|
otherwise the configure script gets confused. To trim leading and
|
|
trailing whitespace, use the <code>:M</code> modifier, as in the
|
|
following example:</para>
|
|
|
|
<!--
|
|
Additional details, intentionally left out of the guide to keep the text
|
|
short:
|
|
|
|
If the configure script calls 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>.
|
|
-->
|
|
|
|
<programlisting>
|
|
CPPFLAGS= # empty
|
|
CPPFLAGS+= -Wundef -DPREFIX=\"${PREFIX}\"
|
|
CPPFLAGS+= ${MY_CPPFLAGS}
|
|
|
|
CONFIGURE_ARGS+= CPPFLAGS=${CPPFLAGS:M*:Q}
|
|
|
|
all:
|
|
echo x${CPPFLAGS:Q}x # leading and trailing whitespace
|
|
echo x${CONFIGURE_ARGS:Q}x # properly trimmed
|
|
</programlisting>
|
|
|
|
<para>In this example, <varname>CPPFLAGS</varname> has both leading and
|
|
trailing whitespace because the <code>+=</code> operator always adds a
|
|
space.</para>
|
|
|
|
</sect2>
|
|
<sect2 id="empty-variables">
|
|
<title>Handling possibly empty variables</title>
|
|
|
|
<para>When a possibly empty variable is used in a shell program, it may
|
|
lead to a syntax error.</para>
|
|
|
|
<programlisting>
|
|
EGFILES= # empty
|
|
|
|
install-examples: # produces a syntax error in the shell
|
|
for egfile in ${EGFILES}; do \
|
|
echo "Installing $$egfile"; \
|
|
done
|
|
</programlisting>
|
|
|
|
<para>The shell only sees the text <code>for egfile in ; do</code>, since
|
|
<code>${EGFILES}</code> is replaced with an empty string by &man.make.1;.
|
|
To fix this syntax error, use one of the snippets below.</para>
|
|
|
|
<programlisting>
|
|
EMPTY= # empty
|
|
|
|
install-examples:
|
|
for egfile in ${EGFILES} ""; do \
|
|
[ -n "$$egfile" ] || continue; \
|
|
echo "Installing $$egfile"; \
|
|
done
|
|
</programlisting>
|
|
|
|
<para>In this case, an empty string is appended to the iteration list (to
|
|
prevent the syntax error) and filtered out later.</para>
|
|
|
|
<programlisting>
|
|
EGFILES= # empty
|
|
|
|
install-examples:
|
|
.for egfile in ${EGFILES}
|
|
echo "Installing ${egfile}"
|
|
.endfor
|
|
</programlisting>
|
|
|
|
<para>This variant only works when <varname>EGFILES</varname> does not
|
|
contain filenames with spaces, since the <code>.for</code> loop splits on
|
|
simple whitespace.</para>
|
|
|
|
<para>To have a shell command test whether a make variable is empty, use
|
|
the following code: <code>${TEST} -z ${POSSIBLY_EMPTY:Q}""</code>.</para>
|
|
|
|
</sect2>
|
|
</sect1>
|
|
</chapter>
|