NMAKE preprocessing directives are similar to compiler preprocessing directives. You can use several of the directives to conditionally process the makefile. With other preprocessing directives you can display error messages, include other files, undefine a macro, and turn certain options on or off. NMAKE reads and executes the preprocessing directives before processing the makefile as a whole.
Preprocessing directives begin with an exclamation point (!), which must appear at the beginning of the line. Zero or more spaces or tabs can appear between the exclamation point and the directive keyword; this allows indentation for readability. These directives (and their keywords and operators) are not case sensitive.
!CMDSWITCHES {+|–}opt...
Turns on or off one or more options. (For descriptions of options, see page 647.) Specify an operator, either a plus sign (+) to turn options on or a minus sign (–) to turn options off, followed by one or more letters representing options. Letters are not case sensitive. Do not specify the slash (/). Separate the directive from the operator by one or more spaces or tabs; no space can appear between the operator and the options. To turn on some options and turn off other options, use separate specifications of the !CMDSWITCHES directives.
All options with the exception of /F, /HELP, /NOLOGO, /X, and /? can appear in !CMDSWITCHES specifications in TOOLS.INI. In a makefile, only the letters D, I, N, and S can be specified. If !CMDSWITCHES is specified within a description block, the changes do not take effect until the next description block. This directive updates the MAKEFLAGS macro; the changes are inherited during recursion.
!ERROR text
Displays text to standard error in the message for error U1050, then stops the NMAKE session. This directive stops the build even if /K, /I, .IGNORE, !CMDSWITCHES, or the dash (–) command modifier is used. Spaces or tabs before text are ignored.
!MESSAGE text
Displays text to standard output, then continues the NMAKE session. Spaces or tabs before text are ignored.
!INCLUDE [[<]]filename[[>]]
Reads and evaluates the file filename as a makefile before continuing with the current makefile. NMAKE first looks for filename in the current directory if filename is specified without a path; if a path is specified, NMAKE looks in the specified directory. Next, if the !INCLUDE directive is itself contained in a file that is included, NMAKE looks for filename in the parent file's directory; this search is recursive, ending with the original makefile's directory. Finally, if filename is enclosed by angle brackets (<>), NMAKE searches in the directories specified by the INCLUDE macro. The INCLUDE macro is initially set to the value of the INCLUDE environment variable.
!IF constantexpression
Processes the statements between the !IF and the next !ELSE or !ENDIF if constantexpression evaluates to a nonzero value.
!IFDEF macroname
Processes the statements between the !IFDEF and the next !ELSE or !ENDIF if macroname is defined. NMAKE considers a macro with a null value to be defined.
!IFNDEF macroname
Processes the statements between the !IFNDEF and the next !ELSE or !ENDIF if macroname is not defined.
!ELSE [[IF constantexpression|IFDEF macroname|IFNDEF macroname]]
Processes the statements between the !ELSE and the next !ENDIF if the preceding !IF, !IFDEF, or !IFNDEF statement evaluated to zero. The optional keywords give further control of preprocessing.
!ELSEIF
Synonym for !ELSE IF.
!ELSEIFDEF
Synonym for !ELSE IFDEF.
!ELSEIFNDEF
Synonym for !ELSE IFNDEF.
!ENDIF
Marks the end of an !IF, !IFDEF, or !IFNDEF block. Anything following !ENDIF on the same line is ignored.
!UNDEF macroname
Undefines a macro by removing macroname from NMAKE's symbol table. (For more information, see “Null Macros and Undefined Macros”.
Example
The following set of directives
!IF
!ELSE
! IF
! ENDIF
!ENDIF
is equivalent to the set of directives
!IF
!ELSE IF
!ENDIF
The constantexpression used with the !IF or !ELSE IF directives can consist of integer constants, string constants, or program invocations. You can group expressions by enclosing them in parentheses. NMAKE treats numbers as decimals unless they start with 0 (octal) or 0x (hexadecimal).
Expressions in NMAKE use C-style signed long integer arithmetic; numbers are represented in 32-bit two's-complement form and are in the range –2147483648 to 2147483647.
Two unary operators evaluate a condition and return a logical value of true (1) or false (0):
DEFINED (macroname)
Evaluates to true if macroname is defined. In combination with the !IF or !ELSE IF directives, this operator is equivalent to the !IFDEF or !ELSE IFDEF directives. However, unlike these directives, DEFINED can be used in complex expressions using binary logical operators.
EXIST (path)
Evaluates to true if path exists. EXIST can be used in complex expressions using binary logical operators. If path contains spaces (allowed in some file systems), enclose it in double quotation marks.
Integer constants can use the unary operators for numerical negation (–), one's complement (~), and logical negation (!).
Constant expressions can use any binary operator listed in Table 18.2. To compare two strings, use the equality (==) operator and the inequality (!=) operator. Enclose strings in double quotation marks.
Table 18.2 Binary Operators for Preprocessing
Operator | Description |
+ | Addition |
– | Subtraction |
* | Multiplication |
/ | Division |
% | Modulus |
& | Bitwise AND |
| | Bitwise OR |
^ | Bitwise XOR |
&& | Logical AND |
|| | Logical OR |
<< | Left shift |
>> | Right shift |
== | Equality |
!= | Inequality |
< | Less than |
> | Greater than |
<= | Less than or equal to |
>= | Greater than or equal to |
Example
The following example shows how preprocessing directives can be used to control whether the linker inserts debugging information into the .EXE file:
!INCLUDE <infrules.txt>
!CMDSWITCHES +D
winner.exe : winner.obj
!IF DEFINED(debug)
! IF "$(debug)"=="y"
LINK /CO winner.obj;
! ELSE
LINK winner.obj;
! ENDIF
!ELSE
! ERROR Macro named debug is not defined.
!ENDIF
In this example, the !INCLUDE directive inserts the INFRULES.TXT file into the makefile. The !CMDSWITCHES directive sets the /D option, which displays the time stamps of the files as they are checked. The !IF directive checks to see if the macro debug is defined. If it is defined, the next !IF directive checks to see if it is set to y. If it is, NMAKE reads the LINK command with the /CO option; otherwise, NMAKE reads the LINK command without /CO. If the debug macro is not defined, the !ERROR directive prints the specified message and NMAKE stops.
Executing a Program in Preprocessing
Summary: NMAKE can run programs before processing the makefile.
You can invoke a program or command from within NMAKE and use its exit code during preprocessing. NMAKE executes the command during preprocessing, and it replaces the specification in the makefile with the command's exit code. A nonzero exit code usually indicates an error. You can use this value in an expression to control preprocessing.
Specify the command, including any arguments, within brackets ([]). You can use macros in the command specification; NMAKE expands the macro before executing the command.
Example
The following part of a makefile tests the space on disk before continuing the NMAKE session:
!IF [c:\util\checkdsk] != 0
! ERROR Not enough disk space; NMAKE terminating.
!ENDIF