Makefile inclusion, conditional structures and for loops reminiscent of the C programming language are provided in
make. All such structures are identified by a line beginning with a single dot (‘.') character. Files are included with either
.include <
file> or
.include "
file". Variables between the angle brackets or double quotes are expanded to form the file name. If angle brackets are used, the included makefile is expected to be in the system makefile directory. If double quotes are used, the including makefile's directory and any directories specified using the
-I option are searched before the system makefile directory. For compatibility with other versions of
make ‘include file ...' is also accepted. If the include statement is written as
.-include or as
.sinclude then errors locating and/or opening include files are ignored.
Conditional expressions are also preceded by a single dot as the first character of a line. The possible conditionals are as follows:
.error message
The message is printed along with the name of the makefile and line number, then make will exit.
.export variable ...
Export the specified global variable. If no variable list is provided, all globals are exported except for internal variables (those that start with ‘.'). This is not affected by the
-X flag, so should be used with caution.
Appending a variable name to
.MAKE.EXPORTED is equivalent to exporting a variable.
.export-env variable ...
The same as ‘.export', except that the variable is not appended to .MAKE.EXPORTED. This allows exporting a value to the environment which is different from that used by make internally.
.info message
The message is printed along with the name of the makefile and line number.
.undef variable
Un-define the specified global variable. Only global variables may be un-defined.
.unexport variable ...
The opposite of ‘.export'. The specified global variable will be removed from .MAKE.EXPORTED. If no variable list is provided, all globals are unexported, and .MAKE.EXPORTED deleted.
.unexport-env
Unexport all globals previously exported and clear the environment inherited from the parent. This operation will cause a memory leak of the original environment, so should be used sparingly. Testing for
.MAKE.LEVEL being 0, would make sense. Also note that any variables which originated in the parent environment should be explicitly preserved if desired. For example:
.if ${.MAKE.LEVEL} == 0
PATH := ${PATH}
.unexport-env
.export PATH
.endif
Would result in an environment containing only ‘
PATH', which is the minimal useful environment. Actually ‘
.MAKE.LEVEL' will also be pushed into the new environment.
.warning message
The message prefixed by ‘warning:' is printed along with the name of the makefile and line number.
.if [!]expression [operator expression ...]
Test the value of an expression.
.ifdef [!]variable [operator variable ...]
Test the value of a variable.
.ifndef [!]variable [operator variable ...]
Test the value of a variable.
.ifmake [!]target [operator target ...]
Test the target being built.
.ifnmake [!] target [operator target ...]
Test the target being built.
.else
Reverse the sense of the last conditional.
.elif [!] expression [operator expression ...]
A combination of ‘.else' followed by ‘.if'.
.elifdef [!]variable [operator variable ...]
A combination of ‘.else' followed by ‘.ifdef'.
.elifndef [!]variable [operator variable ...]
A combination of ‘.else' followed by ‘.ifndef'.
.elifmake [!]target [operator target ...]
A combination of ‘.else' followed by ‘.ifmake'.
.elifnmake [!]target [operator target ...]
A combination of ‘.else' followed by ‘.ifnmake'.
.endif
End the body of the conditional.
The
operator may be any one of the following:
&&
Logical AND; of higher precedence than “||”.
As in C,
make will only evaluate a conditional as far as is necessary to determine its value. Parentheses may be used to change the order of evaluation. The boolean operator ‘
!' may be used to logically negate an entire conditional. It is of higher precedence than ‘
&&'.
The value of
expression may be any of the following:
defined
Takes a variable name as an argument and evaluates to true if the variable has been defined.
make
Takes a target name as an argument and evaluates to true if the target was specified as part of make's command line or was declared the default target (either implicitly or explicitly, see .MAIN) before the line containing the conditional.
empty
Takes a variable, with possible modifiers, and evaluates to true if the expansion of the variable would result in an empty string.
exists
Takes a file name as an argument and evaluates to true if the file exists. The file is searched for on the system search path (see .PATH).
target
Takes a target name as an argument and evaluates to true if the target has been defined.
commands
Takes a target name as an argument and evaluates to true if the target has been defined and has commands associated with it.
Expression may also be an arithmetic or string comparison. Variable expansion is performed on both sides of the comparison, after which the integral values are compared. A value is interpreted as hexadecimal if it is preceded by 0x, otherwise it is decimal; octal numbers are not supported. The standard C relational operators are all supported. If after variable expansion, either the left or right hand side of a ‘
==' or ‘
!=' operator is not an integral value, then string comparison is performed between the expanded variables. If no relational operator is given, it is assumed that the expanded variable is being compared against 0 or an empty string in the case of a string comparison.
When
make is evaluating one of these conditional expressions, and it encounters a (white-space separated) word it doesn't recognize, either the “make” or “defined” expression is applied to it, depending on the form of the conditional. If the form is ‘
.ifdef', ‘
.ifndef', or ‘
.if' the “defined” expression is applied. Similarly, if the form is ‘
.ifmake' or ‘
.ifnmake,
the' “make” expression is applied.
If the conditional evaluates to true the parsing of the makefile continues as before. If it evaluates to false, the following lines are skipped. In both cases this continues until a ‘
.else' or ‘
.endif' is found.
For loops are typically used to apply a set of rules to a list of files. The syntax of a for loop is:
.for variable [variable ...] in expression
After the for
expression is evaluated, it is split into words. On each iteration of the loop, one word is taken and assigned to each
variable, in order, and these
variables are substituted into the
make-rules inside the body of the for loop. The number of words must come out even; that is, if there are three iteration variables, the number of words provided must be a multiple of three.