19.11. Running make
This section explains how to add dependency information to the makefile automatically, and how to use make recursively. These two ways of using make are common and basic, but they do involve multiple features of the program. Finally, the remainder of this section is devoted to a reference list of GNU make's command-line options and the special pseudotargets that also function as runtime options.
The command-line syntax of make is as follows:
make [options] [variable_assignments] [target [target [...]]]
If you don't specify any target on the command line, make behaves as though you had specified the default target; that is, whichever target is named first in the makefile. make builds other targets named in the makefile only if you request them on the command line, or if they need to be built as prerequisites of any target requested.
19.11.1. Generating Header Dependencies
Our program executable circle depends on more files than those we have named in the sample makefile up to now. Just think of the standard headers included in our source code, to begin withnot to mention the implementation-specific header files they include in turn.
Most C source files include both standard and user-defined header files, and the compiled program should be considered out of date whenever any header file has been changed. Because you cannot reasonably be expected to know the full list of header files involved, the standard make technique to account for these dependencies is to let the C preprocessor analyze the #include directives in your C source and write the appropriate make rules. The makefile lines in Example 19-6 fulfill this purpose.
Example 19-6. Generating header dependencies
CC = gcc
OBJ = circle.o circulararea.o
LIB = -lm
circle: $(OBJ) $(LIB)
$(CC) $(LDFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $<
dependencies: $(OBJ:.o=.c)
$(CC) -M $^ > $@
include dependencies
The third rule uses a special kind of make variable reference, called a substitution reference
, to declare that the target dependencies depends on files like those named in the value of $(OBJ), but with the ending .c instead of .o. The command to build dependencies runs the compiler with the preprocessor option -M, which instructs it to collate dependency information from source files. (The GCC compiler permits fine control of the dependency output by means of more preprocessor options that start with -M: these are listed in the section "GCC Options for Generating Makefile Rules," at the end of this chapter.)
The first time you use this makefile, make prints an error message about the include directive because no file named dependencies exists. When this happens, however, make automatically treats the missing file named in the include directive as a target, and looks for a rule to build it. The include directive itself is placed below the target rules to prevent the included file's contents from defining a new default target.
19.11.2. Recursive make Commands
Your makefile rules can include any command that is executable on your system. This includes the make command itself, and indeed recursive invocation of make is a frequently used technique, especially to process source code in subdirectories. make is designed to be aware of such recursive invocation, and incorporates certain features that help it work smoothly when you use it in this way. This section summarizes the special features of "recursive make."
The most typical recursive use of make is in building projects that are organized in subdirectories, with a makefile in each subdirectory. The following snippet illustrates how a top-level makefile can invoke recursive instances of make in three subdirectories named utils, drivers, and doc:
.PHONY: utils drivers doc
utils drivers doc:
$(MAKE) -C $@
The variable MAKE is not defined in the makefile; it is defined internally to yield the full pathname of the currently running program file. Your makefiles should always invoke make in this way to ensure consistent program behavior.
The command-line option -C, or its long form --directory, causes make to change to the specified working directory on startup, before it even looks for a makefile. This is how make "passes control" to the makefile in a subdirectory when used recursively. In this example, the command does not name a target, so the child make will build the first target named in the default makefile in the given subdirectory.
The subdirectories themselves are declared as prerequisites of the special target .PHONY so that make never considers them up to date (see "Phony Targets," earlier in this chapter, for more details). However, if files in one subdirectory depend on files in a parallel subdirectory, you must account for these dependencies in the makefile of a higher-level directory that contains both subdirectories.
There are a few things to remember about command-line options and special variables when you use make recursively. A more complete list of make options and environment variables appears in the next section, "Command-Line Options." The following list merely summarizes those with a special relevance to the recursive use of make:
Some of make's command-line options instruct it not to execute commands, but to only print them (-n), or to touch the files (-t), or to indicate whether the targets are up to date (-q). If in these cases the subordinate make command were not executed, then these options would be incompatible with the recursive use of make. To ensure recursion, when you run make with one of the -t, -n, or -q options, commands containing the variable reference $(MAKE) are executed, even though other commands are not. You can also extend this special treatment to other commands individually by prefixing a plus sign (+) to the command line as a command modifier. The variable MAKELEVEL automatically contains a numeral indicating the recursion depth of the current make instance, starting with 0 for a make invoked from the console. The parent instance of make passes its command-line options to child instances by copying them to the environment variable MAKEFLAGS. However, the options -C, -f, -o, and -W are exceptions: these options, which take a file or directory name as their argument, do not appear in MAKEFLAGS. The -j option, whose argument tells make how many commands it can spawn for parallel processing, is passed on to child instances of make, but with the parallel job limit decreased by one. By default, a child instance of make inherits those of its parent's variables that were defined on the command line or in the environment. You can use the export directive to pass on variables defined in a makefile.
Like any other shell command in a makefile rule, a recursive instance of make can exit with an error status. If this happens, the parent make also exits with an error (unless it was started with the -k or --keep-going option), so that the error cascades up the chain of recursive make instances.
When using make recursively with multiple makefiles in subdirectories, you should use the include directive to avoid duplicating common definitions, implicit rules, and so on. See the section "Includes," earlier in this chapter, for more information.
19.11.3. Command-Line Options
The following is a brief summary of the command-line options
supported by GNU make. Some of these options can also be enabled by including special targets in the makefile. Such targets are described in the following section.
-B, --always-make
Build unconditionally. In other words, make considers all targets out of date.
-C dir, --directory= dir
make changes the current working directory to dir before it does anything else. If the command line includes multiple -C options (which is often the case when make invokes itself recursively), each directory specified builds on the previous one. Example:
$ make -C src -C common -C libs
These options would have the same effect as -C src/common/libs.
-d
Print debugging information.
-e
--environment-overrides
In case of multiple definitions of a given variable name, variables defined on the make command line or in makefiles normally have precedence over environment variables. This command-line option makes environment variables take precedence over variable assignments in makefiles (except for variables specified in override directives).
-f filename, --file= filename, --makefile= filename
Use the makefile filename.
-h, --help
Print make's command-line options.
-i, --ignore-errors
Ignore any errors that occur when executing command scripts.
-I dir, --include-dir= dir
If a makefile contains include directives that specify files without absolute paths, search for such files in the directory dir (in addition to the current directory). If the command line includes several -I options, the directories are searched in the order of their occurrence.
-j [ number] , --jobs[= number]
Run multiple commands in parallel. The optional integer argument number specifies the maximum number of simultaneous jobs. The -j argument by itself causes make to run as many simultaneous commands as possible. (Naturally make is smart enough not to start building any target before its prerequisites have been completed.) If the command line includes several -j options, the last one overrides all others.
| Parallel jobs spawned by make do not share the standard streams elegantly. Console output from different jobs can appear in random order, and only one job can inherit the stdin stream from make. If you use the -j option, make sure none of the commands in your makefiles read from stdin. |
|
-k, --keep-going
This option tells make not to exit after a command has returned a nonzero exit status. Instead, make abandons the failed target and any other targets that depend on it, but continues working on any other goals in progress.
-l [ number], --load-average[= number], --max-load[= number]
In conjunction with the -j option, -l (that's a lowercase L) prevents make from executing more simultaneous commands whenever the system load is greater than or equal to the floating-point value number. The -l option with no argument cancels any load limit imposed by previous -l options.
-n, --just-print, --dry-run, --recon
make prints the commands it would otherwise run, but doesn't actually execute them.
-o filename, --old-file= filename, --assume-old= filename
make treats the specified file as if it were up to date, and yet older than any file that depends on it.
-p, --print-data-base
Before executing any commands, make prints its version information and all its rules and variables, including both built-ins and those acquired from makefiles.
-q, --question
make builds nothing and prints nothing, but returns an exit status as follows:
0
All specified targets are up to date.
1
At least one target is out of date.
2
An error occurred.
-r, --no-builtin-rules
This option disables make's built-in implicit rules, as well as the default list of suffixes for old-style suffix rules. Pattern rules, user-defined suffixes, and suffix rules that you have defined in makefiles still apply, as do built-in variables.
-R, --no-builtin-variables
Like -r, but also disables make's built-in rule-specific variables. Variables you define in makefiles are unaffected.
-s, --silent, --quiet
Ordinarily make echoes each command on standard output before executing it. This option suppresses such output.
-S, --no-keep-going, --stop
This option causes a recursive instance of make to ignore a -k or --keep-going option inherited from its parent make.
-t, --touch
make simply touches target filesthat is, it updates their timestampsinstead of rebuilding them.
-v, --version
make prints its version and copyright information.
-w, --print-directory
make prints a line indicating the working directory both before and after processing the makefile. This output can be useful in debugging recursive make applications. This option is enabled by default for recursive instances of make, and whenever you use the -C option.
--no-print-directory
Disable the working directory output in cases where -w is automatically activated.
-W filename, --what-if= filename, --new-file= filename, --assume-new= filename
make treats the file filename as if it were brand-new.
--warn-undefined-variables
Normally, make takes references to undefined variables in its stride, treating them like references to variables with empty values. This option provides warnings about undefined variables to help you debug your makefiles.
19.11.4. Special Targets Used as Runtime Options
The built-in targets listed in this section are ordinarily used in makefiles to alter make's runtime behavior in general. Other built-in targets are used primarily to assign attributes to certain targets in a makefile, and are listed in the section "Other Target Attributes," earlier in this chapter.
.DEFAULT
You can use the built-in target .DEFAULT to introduce a command script that you want make to execute for any target that is not covered by any other explicit or implicit rule. make also executes the .DEFAULT command script for every prerequisite that is not a target in some rule.
.DELETE_ON_ERROR
You can include the built-in target .DELETE_ON_ERROR anywhere in a makefile to instruct make to delete any target that has been changed by its command script if the script returns a nonzero value on exiting.
.SILENT
Normally make prints each command to standard output before executing it. However, if a given target is a prerequisite of .SILENT, then make does not print the rules when building that target.
If you include .SILENT with no prerequisites in a makefile, it applies to all targets, like the command-line options -s or --silent.
.EXPORT_ALL_VARIABLES
This target acts as an option telling make to export all the currently defined variables before spawning child processes (see the section "Recursive make Commands," earlier in this chapter).
.NOTPARALLEL
This built-in target is a general option; any prerequisites are ignored. The target .NOTPARALLEL in a makefile overrides the command-line option -j for the current instance of make, so that targets are built in sequence. If make invokes itself, however, such recursions still run parallel to the present instance, unless their makefiles also contain .NOTPARALLEL.
.SUFFIXES
This built-in target defines the list of suffixes that make recognizes for use in old-style suffix rules (see "Suffix Rules," earlier in this chapter). You can add suffixes to the built-in list by naming them as prerequisites of .SUFFIXES, or clear the list by declaring the target .SUFFIXES with no prerequisites.
19.11.5. GCC Options for Generating Makefile Rules
-M
Generate a rule showing the prerequisites for the object file that would result from compiling a given source file. The -M option implies the -E option (preprocess only; don't compile), but the -MD and -MMD variants do not. By default, the dependency rules are written to standard output.
-MD
Like -M, but allows GCC to compile source files (unless -E is also present) in addition to running the preprocessor. The dependency output is written to a file whose name is taken from the -o argument, if any, but with the filename ending .d.
-MM
Like -M, but omit header files located in system header directories (and any files they depend on in turn) from the dependency list.
-MMD
Combines the effects of -MM and -MD.
The following options are modifiers used in addition to -M, -MD, -MM, or -MMD:
-MF filename
Writes the dependency information to filename rather than to standard output or to a preprocessor output file.
-MG
Include nonexistent header files in the dependency list.
-MP
Include a phony target for each header file in the dependency output. The effect is that make doesn't complain about header files that have been removed from the project, but not from the dependency list.
-MT target
Substitute target for the actual target in generating dependency rules.
-MQ target
Like -MT, but quote any special characters.
|