The targets section of the dependency line lists one or more target names. At least one target must be specified. Separate multiple target names with one or more spaces or tabs. You can specify a path with the filename. Targets are not case sensitive. A target (including path) cannot exceed 256 characters.
If the name of the last target before the colon (:) is a single character, you must put a space between the name and the colon; otherwise, NMAKE interprets the letter-colon combination as a drive specifier.
Usually a target is the name of a file to be built using the commands in the description block. However, a target can be any valid filename, or it can be a pseudotarget. (For more information, see “Pseudotargets”.)
NMAKE builds targets specified on the NMAKE command line. If a command-line target is not specified, NMAKE builds the first target in the first dependency in the makefile.
The example in Figure 18.1 tells NMAKE how to build a single target file called MYAPP.EXE if it is missing or out-of-date.
Using Targets in Multiple Description Blocks
A target can appear in only one description block when specified as shown in Figure 18.1. To update a target using more than one description block, specify two consecutive colons (::) between targets and dependents. One use for this feature is for building a complex target that contains components created with different commands.
Example
The following makefile updates a library:
target.lib :: one.asm two.asm three.asm
ML one.asm two.asm three.asm
LIB target -+one.obj -+two.obj -+three.obj;
target.lib :: four.c five.c
CL /c four.c five.c
LIB target -+four.obj -+five.obj;
If any of the assembly-language files have changed more recently than the library, NMAKE assembles the source files and updates the library. Similarly, if any of the C-language files have changed, NMAKE compiles the C files and updates the library.
Accumulating Targets in Dependencies
Dependency lines are cumulative when the same target appears more than once in a single description block. For example,
bounce.exe : jump.obj
bounce.exe : up.obj
echo Building bounce.exe...
is evaluated by NMAKE as
bounce.exe : jump.obj up.obj
echo Building bounce.exe...
This evaluation has several effects. Since NMAKE builds the dependency tree based on one target at a time, the lines can contain other targets, as in:
bounce.exe leap.exe : jump.obj
bounce.exe climb.exe : up.obj
echo Building bounce.exe...
NMAKE evaluates a dependency for each of the three targets as if each were specified in a separate description block. If bounce.exe or climb.exe is out-of-date, NMAKE runs the given command. If leap.exe is out-of-date, the given command does not apply, and NMAKE tries to use an inference rule.
Summary: Be careful when specifying the same target in different dependencies in the makefile.
If the same target is specified in two single-colon dependency lines in different locations in the makefile, and if commands appear after only one of the lines, NMAKE interprets the dependency lines as if they were adjacent or combined. This can cause an unwanted side effect: NMAKE does not invoke an inference rule for the dependency that has no commands (see “Inference Rules”). Rather, it assumes that the dependencies belong to one description block and executes the commands specified with the other dependency.
The following makefile is interpreted in the same way as the preceding examples:
bounce.exe : jump.obj
echo Building bounce.exe...
.
.
.
bounce.exe : up.obj
This effect does not occur if the colons are doubled (::) after the duplicate targets. A double-colon dependency with no commands block invokes an inference rule, even if another double-colon dependency containing the same target is followed by a commands block.
A “pseudotarget” is a target that doesn't specify a file but instead names a label for use in executing a group of commands. NMAKE interprets the pseudotarget as a file that does not exist and thus is always out-of-date. When NMAKE evaluates a pseudotarget, it always executes its commands block. Be sure that the current directory does not contain a file with a name that matches the pseudotarget.
A pseudotarget name must follow the syntax rules for filenames. Like a filename target, a pseudotarget name is not case sensitive. However, if the name does not have an extension (that is, it does not contain a period), it can exceed the 8-character limit for filenames and can be up to 256 characters long.
A pseudotarget can be listed as a dependent. A pseudotarget used this way must appear as a target in another dependency; however, that dependency does not need to have a commands block.
A pseudotarget used as a target has an assumed time stamp that is the most recent time stamp of all its dependents. If a pseudotarget has no dependents, the assumed time stamp is the current time. NMAKE uses the assumed time stamp if the pseudotarget appears as a dependent elsewhere in the makefile.
Pseudotargets are useful when you want NMAKE to build more than one target automatically. NMAKE builds only those targets specified on the NMAKE command line, or, when no command-line target is specified, it builds only the first target in the first dependency in the makefile. To tell NMAKE to build multiple targets without having to list them on the command line, write a description block with a dependency containing a pseudotarget and list as its dependents the targets you want to build. Either place this description block first in the makefile or specify the pseudotarget on the NMAKE command line.
Example 1
In the following example, UPDATE is a pseudotarget.
UPDATE : *.*
!COPY $** a:\product
If UPDATE is evaluated, NMAKE copies all files in the current directory to the specified drive and directory.
Example 2
In the following makefile, the pseudotarget all builds both PROJECT1.EXE and PROJECT2.EXE if either all or no target is specified on the command line. The pseudotarget setenv changes the LIB environment variable before the .EXE files are updated:
all : setenv project1.exe project2.exe
project1.exe : project1.obj
LINK project1;
project2.exe : project2.obj
LINK project2;
setenv :
set LIB=\project\lib