Description blocks form the heart of the description file. Figure 10.1 illustrates a typical NMAKE description block, including the three sections: targets, dependents, and commands.
Summary: The target is the file that you want to build.
The targets section of the dependency line lists one or more files to build. The line that lists targets and dependents is called the “dependency line.”
The example in Figure 10.1 tells NMAKE how to build a single target, MYAPP.EXE, if it is missing or out-of-date. Although single targets are common, you can also list multiple targets in a single dependency line; you must separate each target name with a space. If the name of the last target before the colon (:) is one character long, put a space between the name and the colon, so NMAKE won't interpret the character as a drive specification.
A target can appear in only one dependency line when specified as shown above. To update a target using more than one description block, specify two consecutive colons (::) between targets and dependents. For details, see Section 10.3.1.8, “Specifying a Target in Multiple Description Blocks.”
The target is usually a file, but it can also be a “pseudotarget,” a name that lets you build groups of files or execute a group of commands. For more information, see Section 10.3.2, “Pseudotargets.”
Summary: A dependent is a file used to build a target.
The dependents section of the description block lists one or more files from which the target is built. A colon (:) separates it from the targets section. The example in Figure 10.1 lists three dependents after MYAPP.EXE:
myapp.exe : myapp.obj another.obj myapp.def
You can also specify the directories in which NMAKE should search for a dependent. Enclose one or more directory names in braces ({}). Separate multiple directories with a semicolon (;). The syntax for a directory specification is
{directory[[;directory...]]}dependent
Example
The following dependency line tells NMAKE to search the current directory first, then the specified directories:
forward.exe : {\src\alpha;d:\proj}pass.obj
In the line above, the target, FORWARD.EXE, has one dependent, PASS.OBJ. The directory list specifies two directories:
{\src\alpha;d:\proj}
NMAKE first searches for PASS.OBJ in the current directory. If PASS.OBJ isn't there, NMAKE searches the \SRC\ALPHA directory, then the D:\PROJ directory. If NMAKE cannot find a dependent in the current directory or a listed directory, it looks for a description block with a dependency line containing PASS.OBJ as a target, and uses the commands in that description block to create PASS.OBJ. If NMAKE cannot find such a description block, it looks for an inference rule that describes how to create the dependent. (See Section 10.3.5, “Inference Rules.”)
The dependency line in Figure 10.1 tells NMAKE to rebuild the target MYAPP.EXE whenever MYAPP.OBJ, ANOTHER.OBJ, or MYAPP.DEF has changed more recently than MYAPP.EXE.
The object files in the dependency list above would never be newer than the executable file (unless you had recompiled the source code before running NMAKE). So NMAKE checks to see if the object files themselves are targets in other dependency lists, and if any dependents in those lists are targets elsewhere, and so on.
NMAKE continues moving through all dependencies this way to build a “dependency tree” that specifies all the steps required to fully update the target. If NMAKE then finds any dependents in the tree that are newer than the target, NMAKE updates the appropriate files and rebuilds the target.
Summary: The commands section can contain one or more commands.
The commands section of the description block lists the commands that NMAKE should use to build the target. You can use any command that can be executed from the command line. The example in Figure 10.1 tells NMAKE to build MYAPP.EXE using the following LINK command:
link myapp another.obj, , NUL, os2, myapp
Notice that the line is indented. NMAKE uses indentation to distinguish between a dependency line and a command line. A command line must be indented at least one space or tab. The dependency line must not be indented (it cannot start with a space or tab).
Many targets are built with a single command, but you can place more than one command after the dependency line, each on a separate line, as shown in Figure 10.1.
A long command can span several lines if each line ends with a backslash (\). A backslash at the end of a line is equivalent to a space on the command line. For example, the command
echo abcd\
efgh
is equivalent to the command
echo abcd efgh
You can also place a command at the end of a dependency line. Use a semicolon (;) to separate the command from the rightmost dependent, as in
project.exe : project.obj ; link project;
Summary: OS/2 allows multiple commands on one command line.
OS/2 allows you to combine two or more commands on a single command line with an ampersand (&). For example, the following command line is legal in an OS/2 description file:
DIR & COPY sample.exe backup.exe
A slight restriction is imposed on the use of the CD, CHDIR, and SET commands in OS/2 description files. NMAKE executes these commands itself rather than passing them to OS/2. Therefore, if any of these commands is the first command on a line, the remaining commands are not executed because they aren't passed to OS/2.
The following multiple-command line does not display the directory listing because DIR is preceded by a CD command:
CD \mydir & DIR
To use CD, CHDIR, or SET in a description block, place these commands on separate lines:
CD \mydir
DIR
NMAKE interprets a percent symbol (%) within a command line as the start of a file specifier. To use a literal percent symbol in a command line, specify it as a double percent symbol (%%). (See Section 10.3.8, “Extracting Filename Components.”)
You can use DOS and OS/2 wild-card characters (* and ?) to specify target and dependent filenames. NMAKE expands the wild cards when analyzing dependencies and when building targets. For example, the following description block links all files having the .OBJ extension in the current directory:
project.exe : *.obj
LINK $*.obj;
Command modifiers are special prefixes attached to the command. They provide extra control over the commands in a description block. You can use more than one modifier for a single command. Table 10.1 describes the three NMAKE command modifiers.
Table 10.1 Command Modifiers
Character | Action |
<$!>@ | Prevents NMAKE from displaying the command as it executes. In the example below, the at sign (@) suppresses display of the ECHO command line: |
sort.exe : sort.obj @ECHO Now sorting. | |
The output of the ECHO command is not suppressed. | |
–[[number]] | Turns off error checking for the command. Spaces and tabs can appear before the command. If the dash is followed by a number, NMAKE checks the exit code returned by the command and stops if the code is greater than the number. No space or tab can appear between the dash and number. (See Section 10.12, “Using Exit Codes with NMAKE.”) |
In the following example, if the program sample returns an exit code, NMAKE does not stop but continues to execute commands; if sort returns an exit code greater than 5, NMAKE stops: | |
light.lst : light.txt -sample light.txt -5 sort light.txt | |
! | Executes the command for each dependent file if the command preceded by the exclamation point uses the predefined macros $** or $?. (See Section 10.3.4, “Macros.”) The $** macro refers to all dependent files in the description block. The $? macro refers to all dependent files in the description block that have a more recent modification time than the target. For example |
print : one.txt two.txt three.txt !print $** lpt1: | |
generates the following commands: | |
print one.txt lpt1: print two.txt lpt1: print three.txt lpt1: |
You may need to specify as a literal character one of the characters that NMAKE uses for a special purpose. These characters are
: ; # ( ) $ ^ \ { } ! @ —
To use one of these characters literally, place a caret (^) in front of it. For example, suppose you define a macro that ends with a backslash:
exepath=c:\bin\
The line above is intended to define a macro named exepath with the value c:\bin\. But the second backslash has an unintended side effect. Since the backslash is NMAKE's line-continuation character, the line actually defines exepath as c:\bin, followed by whatever appears on the next line of the description file. You can avoid this problem by placing a caret in front of the second backslash:
exepath=c:\bin^\
You can also use a caret to insert a literal newline character in a string or macro:
XYZ=abc^
def
The caret tells NMAKE to interpret the newline character as part of the macro, not a line break. Note that this effect differs from using a backslash (\) to continue a line. A newline character that follows a backslash is replaced with a space.
NMAKE ignores carets that precede characters other than the special characters listed above. The line
ign^ore : these ca^rets
is interpreted as
ignore : these carets
A caret within a quoted string is treated as a literal caret character.
You can specify a target in more than one description block by placing two colons (::) after the target. This feature is useful for building a complex target, such as a library, that contains components created with different commands. For example,
target.lib :: a.asm b.asm c.asm
ML a.asm b.asm c.asm
LIB target -+a.obj -+b.obj -+c.obj;
target.lib :: d.c e.c
CL /c d.c e.c
LIB target -+d.obj -+e.obj;
Both description blocks update the library named TARGET.LIB. If any of the assembly-language files have changed more recently than the library, NMAKE executes the commands in the first block to assemble the source files and update the library. Similarly, if any of the C-language files have changed, NMAKE executes the second group of commands to compile the C files and update the library.
If you use a single colon in the example above, NMAKE issues an error message. It is legal, however, to use single colons if the target appears in only one block. In this case, dependency lines are cumulative. For example,
target : jump.bas
target : up.c
echo Building target...
is equivalent to
target : jump.bas up.c
echo Building target...
No commands can appear between cumulative dependency lines, but blank lines, comment lines, macro definitions, and directives can appear.