Programming Utilities Guide

Implicit Rules and Dynamic Macros

make maintains a set of macros dynamically, on a target-by-target basis. These macros are used quite extensively, especially in the definitions of implicit rules. It is important to understand what they mean.


Note -

Because they are not explicitly defined in a makefile, the convention is to document dynamic macros with the $-sign prefix attached (in other words, by showing the macro reference).


They are:

$@

The name of the current target.

$?

The list of dependencies newer than the target.

$<

The name of the dependency file, as if selected by make for use with an implicit rule.

$*

The base name of the current target (the target name stripped of its suffix).

$%

For libraries, the name of the member being processed. See "Building Object Libraries " for more information.

Implicit rules use these dynamic macros in order to supply the name of a target or dependency file to a command line within the rule itself. For instance, in the .c.o rule, shown in the next example:

.c.o:
         $(COMPILE.c) $< $(OUTPUT_OPTION)

$< is replaced by the name of the dependency file (in this case the .c file) for the current target.


Note -

The macro OUTPUT_OPTION has an empty value by default. While similar to CFLAGS in function, it is provided as a separate macro intended for passing an argument to the -o compiler option to force compiler output to a given file name.


In the .c rule:

.c:
         $(LINK.c) $< -o $@

$@ is replaced with the name of the current target.

Because values for both the $< and $* macros depend upon the order of suffixes in the suffixes list, you might get surprising results when you use them in an explicit target entry. See "Suffix Replacement in Macro References " for a strictly deterministic method for deriving a file name from a related file name.

Dynamic Macro Modifiers

Dynamic macros can be modified by including F and D in the reference. If the target being processed is in the form of a pathname, $(@F) indicates the file name part, while $(@D) indicates the directory part. If there are no / characters in the target name, then $(@D) is assigned the dot character (.) as its value. For example, with the target named /tmp/test, $(@D) has the value /tmp; $(@F) has the value test.

Dynamic Macros and the Dependency List: Delayed Macro References

Dynamic macros are assigned while processing any and all targets. They can be used within the target rule as is, or in the dependency list by prepending an additional $ character to the reference. A reference beginning with $$ is called a delayed reference to a macro. For instance, the entry:

x.o y.o z.o: $$@.BAK 
         cp $@.BAK $@

could be used to derive x.o from x.o.BAK, and so forth for y.o and z.o.

Dependency List Read Twice

This technique works because make reads the dependency list twice, once as part of its initial reading of the entire makefile, and again as it processes target dependencies. In each pass through the list, it performs macro expansion. Since the dynamic macros aren't defined in the initial reading, unless references to them are delayed until the second pass, they are expanded to null strings.

The string $$ is a reference to the predefined macro `$'. This macro, conveniently enough, has the value `$'; when make resolves it in the initial reading, the string $$@ is resolved to $@. In dependency scan, when the resulting $@ macro reference has a value dynamically assigned to it, make resolves the reference to that value.

Notice that make only evaluates the target-name portion of a target entry in the first pass. A delayed macro reference as a target name produces incorrect results. The makefile:

NONE= none 
all: $(NONE) 

$$(NONE): 
         @: this target's name isn't `none'

produces the following results.

$ make 
make: Fatal error: Don't know how to make target `none'

Rules Evaluated Once

make evaluates the rule portion of a target entry only once per application of that command, at the time that the rule is executed. Here again, a delayed reference to a make macro produces incorrect results.

No Transitive Closure for Suffix Rules

There is no transitive closure for suffix rules. If you had a suffix rule for building, say, a .Y file from a .X file, and another for building a .Z file from a .Y file, make would not combine their rules to build a .Z file from a .X file. You must specify the intermediate steps as targets, although their entries can have null rules:

trans.Z: 
trans.Y:

In this example trans.Z is built from trans.Y if it exists. Without the appearance of trans.Y as a target entry, make might fail with a "don't know how to build" error, since there would be no dependency file to use. The target entry for trans.Y guarantees that make will attempt to build it when it is out of date or missing. Since no rule is supplied in the makefile, make will use the appropriate implicit rule, which in this case would be the .X.Y rule. If trans.X exists (or can be retrieved from SCCS), make rebuilds both trans.Y and trans.Z as needed.