Variables can be defined or redefined directly from the make command line:
$ make CFLAGS=-g CPPFLAGS='-DBSD -DDEBUG'
A command-line argument containing an = is a variable assignment. Each variable assignment on the command line must be a single-shell argument. If the value of the variable (or heaven forbid , the variable itself) contains spaces, the argument must be surrounded by quotes or the spaces must be escaped.
An assignment of a variable on the command line overrides any value from the environment and any assignment in the makefile . Command-line assignments can set either simple or recursive variables by using := or = , respectively. It is possible using the override directive to allow a makefile assignment to be used instead of a command-line assignment.
# Use big-endian objects or the program crashes! override LDFLAGS = -EB
Of course, you should ignore a user 's explicit assignment request only under the most urgent circumstances (unless you just want to irritate your users).
All the variables from your environment are automatically defined as make variables when make starts. These variables have very low precedence, so assignments within the makefile or command-line arguments will override the value of an environment variable. You can cause environment variables to override makefile variables using the ”environment-overrides (or -e ) command-line option.
When make is invoked recursively, some variables from the parent make are passed through the environment to the child make . By default, only those variables that originally came from the environment are exported to the child's environment, but any variable can be exported to the environment by using the export directive:
export CLASSPATH := $(HOME)/classes:$(PROJECT)/classes SHELLOPTS = -x export SHELLOPTS
You can cause all variables to be exported with:
Note that make will export even those variables whose names contain invalid shell variable characters . For example:
export valid-variable-in-make = Neat! show-vars: env grep '^valid-' valid_variable_in_shell=Great invalid-variable-in-shell=Sorry $ make env grep '^valid-' valid-variable-in-make=Neat! valid_variable_in_shell=Great invalid-variable-in-shell=Sorry /bin/sh: line 1: invalid-variable-in-shell=Sorry: command not found make: *** [show-vars] Error 127
An "invalid" shell variable was created by exporting valid-variable-in-make . This variable is not accessible through normal shell syntax, only through trickery such as running grep over the environment. Nevertheless, this variable is inherited by any sub- make where it is valid and accessible. We will cover use of "recursive" make in Part II.
You can also prevent an environment variable from being exported to the sub-process:
The export and unexport directives work the same way their counterparts in sh work.
The conditional assignment operator interacts very nicely with environment variables. Suppose you have a default output directory set in your makefile , but you want users to be able to override the default easily. Conditional assignment is perfect for this situation:
# Assume the output directory $(PROJECT_DIR)/out. OUTPUT_DIR ?= $(PROJECT_DIR)/out
Here the assignment is performed only if OUTPUT_DIR has never been set. We can get nearly the same effect more verbosely with:
ifndef OUTPUT_DIR # Assume the output directory $(PROJECT_DIR)/out. OUTPUT_DIR = $(PROJECT_DIR)/out endif
The difference is that the conditional assignment operator will skip the assignment if the variable has been set in any way, even to the empty value, while the ifdef and ifndef operators test for a nonempty value. Thus, OUTPUT_DIR= is considered set by the conditional operator but not defined by ifdef .
It is important to note that excessive use of environment variables makes your makefile s much less portable, since other users are not likely to have the same set of environment variables. In fact, I rarely use this feature for precisely that reason.