Table of Contents
Pkgsrc consists of many Makefile fragments,
  each of which forms a well-defined part of the pkgsrc system. Using
  the make(1) system as a programming language for a big system
  like pkgsrc requires some discipline to keep the code correct and
  understandable.
The basic ingredients for Makefile
  programming are variables and shell
  commands. Among these shell commands may even be more complex ones
  like 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.
This chapter describes some patterns that appear quite often in
  Makefiles, including the pitfalls that come along
  with them.
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 make(1) for the second time, the file exists and will not be regenerated properly. Example:
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}
When you run make wrong twice, the file
    wrong will exist, although there was an error
    message in the first run. On the other hand, running make
    correct gives an error message twice, as expected.
You might remember that make(1) sometimes removes
    ${.TARGET} in case of error, but this only
    happens when it is interrupted, for example by pressing
    Ctrl+C. This does not happen
    when one of the commands fails (like false(1) above).
Makefile variables contain strings that
    can be processed using the five operators =,
    +=, ?=, := and
    !=, which are described in the make(1) man
    page.
When a variable's value is parsed from a
    Makefile, the hash character # and
    the backslash character \ are handled specially. If a
    backslash is the last character in a line, that backslash is removed
    from the line and the line continues with the next line of the file.
The # character starts a comment that reaches
    until the end of the line. To get an actual # character,
    such as in a URL, write \# instead.
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
    .if condition or a .for loop.
    In the other cases, it is evaluated lazily.
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, double quotes and single quotes are interpreted as delimiters, just like in sh(1).
All variable names starting with an underscore are reserved for use by the pkgsrc infrastructure. They shall not be used by packages.
In .for loops you should use lowercase variable names for the iteration variables.
All list variables should have a plural name,
	such as PKG_OPTIONS or
	DISTFILES.
When adding a string that possibly contains whitespace or quotes to
a list (example 1), it must be quoted using the :Q
modifier.
When adding another list to a list (example 2), it must not be quoted, since its elements are already quoted.
STRING=         foo * bar `date`
LIST=           # empty
ANOTHER_LIST=   a=b c=d
LIST+=          ${STRING:Q}       # 1
LIST+=          ${ANOTHER_LIST}   # 2
Echoing a string containing special characters needs special work.
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
Example 1 leads to a syntax error in the shell, as the characters are just copied.
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.
Example 3 can handle arbitrary strings, since printf(1) only interprets the format string, but not the next argument. The trailing single quotes handle the case when the string is empty. In that case, the :Q modifier would result in an empty string too, which would then be skipped by the shell. For printf(1) this doesn't make a difference, but other programs may care.
In example 4, the EXAMPLE_ENV does not
need to be quoted because the quoting has already been done
when adding elements to the list.
When passing CFLAGS 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 :M modifier, as in the
following example:
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
In this example, CPPFLAGS has both leading and
trailing whitespace because the += operator always adds a
space.
When a possibly empty variable is used in a shell program, it may lead to a syntax error.
EGFILES=        # empty
install-examples:   # produces a syntax error in the shell
        for egfile in ${EGFILES}; do            \
                echo "Installing $$egfile";     \
        done
The shell only sees the text for egfile in ; do, since
${EGFILES} is replaced with an empty string by make(1).
To fix this syntax error, use one of the snippets below.
EGFILES=        # empty
install-examples:
        for egfile in ${EGFILES} ""; do         \
                [ -n "$$egfile" ] || continue;  \
                echo "Installing $$egfile";     \
        done
In this case, an empty string is appended to the iteration list (to prevent the syntax error) and filtered out later.
EGFILES=        # empty
install-examples:
.for egfile in ${EGFILES}
        echo "Installing ${egfile}"
.endfor
If one of the filenames contains special characters, it should be enclosed in single or double quotes.
To have a shell command test whether a make variable is empty, use
the following code: ${TEST} -z ${POSSIBLY_EMPTY:Q}"".
When a variable can have the values yes or
no, use the following pattern to test the variable:
.if ${VAR:U:tl} == "yes"
# do something
.endif
The :U modifier is only necessary if the variable
can be undefined. If the variable is guaranteed to be defined, the
:U can be omitted.
The :tl modifier converts the variable value to
lowercase, allowing for the values yes,
Yes, YES.