We have already introduced the define directive, which produces a simply expanded variable or a function. Other make directives allow you to influence the effective contents of your makefiles dynamically by making certain lines in a makefile dependent on variable conditions, or by inserting additional makefiles on the fly.
You can also make part of your makefile conditional upon the existence of a variable by using the ifdef or ifndef directive. They work the same as the C preprocessor directives of the same names, except that in make, an undefined variable is the same as one whose value is empty. Here is an example:
OBJ = circle.o LIB = -lm ifdef SHAREDLIBS LIB += circulararea.so else OBJ += circulararea.o endif circle: $(OBJ) $(LIB) $(CC) -o $@ $^ %.so : %.o $(CC) -shared -o $@ $<
As the example shows, the variable name follows ifdef or ifndef without a dollar sign or parentheses. The makefile excerpt shown here defines a rule to link object files into a shared library if the variable SHAREDLIBS has been defined. You might define such a general build option in an environment variable, or on the command line, for example.
You can also make certain lines of the makefile conditional upon whether two expressionsusually the value of a variable and a literal stringare equal. The ifeq and ifneq directives test this condition. The two operands whose equality is the condition to test are either enclosed together in parentheses and separated by a comma, or enclosed individually in quotation marks and separated by whitespace. Here is an example:
ifeq ($(MATHLIB), /usr/lib/libm.so) # ... Special provisions for this particular math library ... endif
That conditional directive, with parentheses, is equivalent to this one with quotation marks:
ifeq "$(MATHLIB)" "/usr/lib/libm.so" # ... Special provisions for this particular math library ... endif
The second version has one strong advantage: the quotation marks make it quite clear where each of the operands begins and ends. In the first version, you must remember that whitespace within the parentheses is significant, except immediately before and after the comma (see also the section "Variables and Whitespace," earlier in this chapter).
The include directive serves the same purpose as its C preprocessor counterpart, but works slightly differently. To start with an example, you might write a makefile named defaults.mk with a set of standard variables for your environment, containing something like this:
BINDIR = /usr/bin HOMEBINDIR = ~/bin SRCDIR = project/src BUILDDIR = project/obj RM = rm -f MKDIR = mkdir -p # ... etc. ...
Then you could add these variables to any makefile by inserting this line:
The include keyword may be followed by more than one filename. You can also use shell wildcards like * and ?, and reference make variables to form filenames:
include $(HOMEBINDIR)/myutils.mk $(SRCDIR)/*.mk
For included files without an absolute path, make searches in the current working directory first, then in any directories specified with the -I option on the command line, and then in standard directories determined when make was compiled.
If make fails to find a file named in an include directive, it continues reading the makefile, and then checks to see whether there is a rule that will build the missing file. If so, make rereads the whole makefile after building the included file. If not, make exits with an error. The -include directive (or its synonym sinclude) is more tolerant: it works the same as include, except that make ignores the error and goes on working if it can't find or build an included file.
19.10.3. Other Directives
Of the other four make directives, three are used to control the interplay between make's internal variables and the shell environment, while the fourth instructs make where to look for specific kinds of files. These directives are: