This is the documentation of version 1.40.1. You may want the documentation of the stable version (2.0) or of the well tested 2.1 development snapshot or our homepage.

Makepp Variables

How to use variables in makepp

define, dependencies, dependency, foreach, input, inputs, output, outputs, sorted_dependencies, sorted_inputs, stem, target, targets, =, :=, +=, ?=, !=, $@, $^, $*, $+, $?, $<

Makefiles typically use variables in many places. One important reason for using variables is to ensure that information is contained in only one place in the makefile, so that if it changes, there is no danger of the two copies of the information getting out of sync.

Variable names are case sensitive. In theory, variable names can be made of any characters, but you will probably confuse the makefile parser if you do anything other than alphanumeric characters, _, and -.

Each makefile has its own set of variables, and setting a variable in one makefile will have no effect on its value in any other makefile. If you want to have variables set in many makefiles, the best way to do it is to have each of them include a common definitions file (see the include statement).

Variable Assignment

A variable can assume a value in several different ways:

Setting variables inside a makefile

Variables are assigned with one of several assignment expressions, like this

X = 1
MODULES := a b c d
CC ?= gcc
CFLAGS += -Wall
define VAR
  var line 1
  var line 2

Leading and trailing whitespace around values is always stripped off.

Variable values are always stored as ordinary perl scalars, so you can access them directly from perl code if you need to do any complicated manipulations with them; see the makepp_extending manpage for details.

The different assignment operators have somewhat different meanings.

VARIABLE = text string

This is the usual assignment statement that all implementations of make support. The expression on the right hand side is not evaluated until the value of $(VARIABLE) is actually used somewhere. Thus, if you do the following:

X = 1
Y = $(X)
X = 2

Then $(Y) later in the makefile will evaluate to ``2''.

In general, you usually want to use := (see below) instead of = because it provides more predictable variable evaluation. However, there are times when you need to defer the variable evaluation. Also, if you're writing a makefile that must be backwards-compatible with some version of make other than GNU make, then you have no choice: you may only use =.

VARIABLE := expr

This is the same as VARIABLE = expr except that the right hand side is evaluated at the time of the assignment. Thus if

X := 1
Y := $(X)
X := 2

then $(Y) later in the makefile will evaluate to ``1'' since that's what $(X) was when $(Y) was defined.

VARIABLE += expr

Appends the string to the previous contents of the variable, separated by a space. If the variable was previously assigned with :=, then the right hand side is evaluated before appending.

VARIABLE ?= expr

Sets the value of the variable, but only if the variable is not specified earlier in the makefile, on the command line, or in the environment. The above assignment is exactly equivalent to

  VARIABLE = expr
VARIABLE != shell command

Runs the shell command and sets the variable to contain the command's standard output. This is exactly equivalent to

VARIABLE := $(shell command)
first line of variable's value
second line of variable's value
third line of variable's value

If you need a variable's value to contain newlines, you must use the define statement as shown (or you can assign the value directly in perl). This is primarily useful for ``canned command sequences'', e.g., something like this:

@echo "Compiling $(input)"
@$(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -c $(input) -o $(output)

Then you can use this multi-line variable in several rules, like this:

%.o : %.c
$(ARCH)/%.o : $(ARCH)/%.c

Note that you can often achieve the same effect by using a semicolon instead of a newline, because the shell interprets that as a command delimeter too. For example,

COMPILE_C_PROGRAM = @echo "Compiling $(input)"; \
    $(CC) $(CFLAGS) $(CPPFLAGS) $(INCLUDES) -c $(input) -o $(output)

will have the same effect.

Note that variables assigned a value with define are treated as if they were assigned with = and not :=, i.e., expansion of references to other variables is deferred until the variable is referenced.

Target-specific assignments

target : VARIABLE = string
target : VARIABLE := string
target : VARIABLE += string

Sets a target-specific value of the variable. A target-specific value is in effect only in an action which produces the given target. This is primarily used for things like this:

my_prog: file1.o file2.o special_file.o
special_file.o : CFLAGS := -g
%.o: %.c
      $(CC) $(CFLAGS) -c $(input) -o $(output)

What happens here is that all .c files will be compiled with optimization (-O2) except special_file.c, which is compiled in debug mode (-g). This is a convenient way to specify different compilation options for only a few files.

Target-specific variable assignments like this apply only to the actions of the rule; they are not in effect when evaluating the targets or the dependencies of a rule. If a rule has more than one target, target-specific variable assignents are taken only from the first target. Also note that makepp's target-specific variables are slightly different from GNU make's in that they only apply to the rule for the one file mentioned, and not to any of its predecessors; see makepp_incompatibilities for details.

Wildcard expansion is performed on the target, so you can do something like this:

test_*.o : CFLAGS += -DTEST

For compatibility with GNU make, % may be used in place of *.

Variable Substitution

Makepp's variable substitution rules are similar to those of other makes, but somewhat more powerful. As in all makes, $(CC) or ${CC} both represent the value of the variable CC. If you need a literal dollar sign, put in a double dollar sign ($$), like this:

target: dep1 dep2 dep3 dep4
    $(RM) -f $(output)
    for file in $(inputs); do cat $$file >> $(output); done

rc-style substitution

By default, makepp uses rc-style substitution (so called because it was pioneered by the rc shell). This is best illustrated by an example:

MODULES = a b c d
mylib.a : module_dir/$(MODULES).o $(OTHER_OBJECTS)
    $(CXX) $(dependencies) -o $(target)

The prefix module_dir/ is prepended to each word in MODULES, and the suffix .o is appended to each word.

You can also use rc-style substitution without even putting the list of words into a variable; the syntax is $( word1 word2). Note the space between the parenthesis and the first word. So the above example could have been written as:

mylib.a : module_dir/$( a b c d).o $(OTHER_OBJECTS)
    $(CXX) $(dependencies) -o $(target)

If you put several variables in the same word which expand to arrays of words, rc-style substitution actually takes the cartesian product, so you can do something like this if you want:

DIRS = s1 s2
MODULES = a b c
SUFFIXES = .o .c

and FILES will contain the string

s1/a.o s1/a.c s1/b.o s1/b.c s1/c.o s1/c.c s2/a.o s2/a.c s2/b.o s2/b.c s2/c.o s2/c.c

If rc-style substitution gets in the way, or if you need to have leading or trailing whitespace in your make variables, then you can turn off rc-style substitution with the --norc-substitution command line option. You can also turn it off on a per-makefile basis by setting the variable rc_substitution=0 in your makefile. You should do this near the top of the makefile, or else you may run into funny situations where rc-style substitution is used for some evaluations and not others. (All expressions evaluated before the assignment will use rc-style substitutions, and all expressions evaluated after will not. Since the time of evaluation of expressions in makefiles is complicated and not always obvious from the order of statements in the makefile, it's best to set rc_substitution as early as possible.)

Substitution References

A substitution reference has the form $(VAR:A=B), where A is a pattern to match and B is a pattern to replace it with. For example:

source_files = a.c b.c c.c d.c
object_files = $(source_files:%.c=%.o)

will set $(object_files) to a.o b.o c.o d.o. The % is a special character matches any arbitrary string. Substitution references are an abbreviation fot the patsubst function.

Whitespace in variables

If you need to control the whitespace in a variable, you must (currently) disable rc-style substitution (using the command line option --norc-substitution or by setting rc_substitution:=0 in the makefile) and then use a syntax like this:

null =
T = -o $(null)

When you do this, the variable T contains -o followed by a space.

This kind of a technique to handle whitespace is not recommended. If you need variables in your makefile to contain spaces, you should think seriously about what you're doing. If you need to handle spaces, it is usually much better to put perl code into your makefile to take care of it (using the perl_begin or sub statements), or to handle it in shell statements in the actions of rules.

These cases typically come up when people attempt to use the same rules for different architectures which do not use typical unix command syntax. E.g., sometimes one sees things like this in makefiles:

ifeq ($(ARCH),weirdarch)
 O := /OUTPUT=
 null :=
 O := -o $(null)
%.o : %.c
    $(COMPILER) $(input) $(O)$(output)

You can do this with makepp if you really want to, but you will probably find that your makefiles are substantially more readable if you have less complicated variable stubstitution, e.g.,

ifeq ($(ARCH),weirdarch)
 %.o : %.c
    $(WEIRD_COMPILER) $(input) /OUTPUT=$(output)
 %.o : %.c
    $(CC) -c $(input) -o $(output)

Whitespace is never allowed in variable names, only in their values. This is different from some make implementations.

Automatic Variables

Automatic variables are variables that assume different values depending on which rule they are evaluated in. Makepp supports most of the automatic variables that other versions of make use. In addition, it has less cryptic, longer names for most of them that you can use instead. (For legacy makefiles that happen to redefine these names, the definition in the makefile overrides the default meaning. For example, if you say target = abc in your makefile, then $(target) will always expand to abc, and will no longer be equivalent to $@.)

The following is a complete list of all the automatic variables that makepp supports:

The target of the current rule. Actually, since makepp supports multiple targets for any rule, this is the first target. For example, in the following rule : parser.y
    $(YACC) $(YFLAGS) $(input)

$(output) will contain the value

All targets of the current rule. Same as $(target) unless there is more than one target. In the above example, $(outputs) will be

The first explicit dependency of the rule. For example, in this rule
%.o : %.c
    $(CC) $(CFLAGS) -c $(input) -o $(output)

$(input) will be the name of the .c file, regardless of what .h files makepp discovers.

All the explicit dependencies of the target, not including .h files discovered by the makepp_scanning manpage for includes.

For example, in the rule

myprog.o : *.o
    $(CC) $(CFLAGS) $(inputs) -o $(output)

$(inputs) will be all the .o files in the directory.

All the dependencies of the target, in sorted order, with duplicates removed. Equivalent to $(sort $(inputs)).

In most make implementations, this is the dependencies of the target which have changed. This does not fit into makepp's conceptual framework, because on the next build it will make sure the command is exactly identical to the previous build, or else it considers the file out of date. So makepp attempts to support this variable for backward compatibility by making it equivalent to all dependencies (the same as $+).

This variable has no long name because its use is highly discouraged. Ordinarily it is used in commands like this:

libmine.a : $(MODULES)
    $(AR) ru $@ $?

i.e., ar is told to replace only those modules that have changed. Makepp doesn't like this because it means that the command to build the library is different on each build, and makepp cannot guarantee that the builds are correct. In fact, this can often lead to incorrect builds: if you delete a source file, for example, the .o file will still be in the library. It's better to build a library like this:

libmine.a : $(MODULES)
    $(RM) -f $(output)
    $(AR) cr $(output) $(inputs)

because then it is guaranteed that there are no stale modules inside the library.

The stem in a pattern rule (i.e., whatever the '%' matched). Alternatively, if this is not a pattern rule, returns the file name without the extension (i.e., it's equivalent to $(basename $(input)).

This is mostly for backward compatibility. For example, in old versions of make the only way to tell it how to compile any .c file into the corresponding .o file was like this:

   $(CC) $(CFLAGS) -c $*.c -o $*.o

This is a lousy way to write the rule. It's much clearer to use GNU-make style pattern rules, like this:

%.o : %.c
   $(CC) $(CFLAGS) -c $(input) -o $(output)

The current filename from the foreach clause. foreach clauses are rarely used, but they are the most general-purpose kind of pattern rule that makepp supports. For example,
# Build .c files with some sort of a special preprocessor:
%.c : %.k
   $(preprocessor) $(input) > $(output)
# Compile .c files into .o files:
%.o : %.c
   $(CC) $(CFLAGS) -c $(input) -o $(output)
# Special alternate compilation flags for .c files which are derived
# from .k files:
$(foreach:%.k=%.o) : $(foreach:%.k=%.c) : foreach *.k
   $(CC) $(SPECIAL_K_FLAGS) -c $(input) -o $(output)

See the documentation on the foreach clause in rules for more details and examples.

Gary Holt
Last modified: 2003-11-01