About MAKE

MAKE.EXE is a command-line utility that helps you manage project compilation and link cycles. MAKE is not inherently tied to compiling and linking, but is a more generic tool for executing commands based on file dependencies. MAKE helps you quickly build projects by compiling only the files you have modified since the last compilation. In addition, you can set up rules that specify how MAKE should deal with the special circumstances in your builds.


MAKE Basics

MAKE uses rules you write along with its default settings to determine how it should compile the files in your project. For example, you can specify when to build your projects with debug information and to compile your .OBJ files only if the date/time stamps of a source file is more recent than the .OBJ itself. If you need to force the compilation of a module, use TOUCH.EXE to modify the time stamp of one of the module's dependents.

In an ASCII makefile, you write explicit and implicit rules to tell MAKE how to treat the files in your project; MAKE determines if it should execute a command on a file or set of files using the rules you set up. Although your commands usually tell MAKE to compile or link a set of files, you can specify nearly any operating system command with MAKE.

The general syntax for MAKE is

MAKE [options...] [target[target]]

where:

options
are MAKE options that control how MAKE works
target
is the name of the target listed in the makefile that you want to build

You must separate the MAKE command and the options and target arguments with spaces. When specifying targets, you can use wildcard characters (such as * and ?) to indicate multiple files. To get command-line help for MAKE, type MAKE -?.

Note: If you need to compile in real mode, use the program MAKER.EXE.


Default MAKE actions

When you issue a MAKE command, MAKE looks for the file BUILTINS.MAK , which contains the default rules for MAKE (use the -r option to ignore the default rules). MAKE looks for this file first in the current directory, then in the directory where MAKE.EXE is stored. After loading BUILTINS.MAK, MAKE looks in the current directory for a file called MAKEFILE or MAKEFILE.MAK (use the -f option to specify a file other than MAKEFILE). If MAKE can't find either of these files, it generates an error message.

After loading the makefile, MAKE tries to build only the first explicit target listed in the makefile by checking the time and date of the dependent files of the first target. If the dependent files are more recent than the target file, MAKE executes the commands to update the target.

If one of the first target's dependent files is used as a target elsewhere in the makefile, MAKE checks that target's dependencies and builds it before building the first target. This chain reaction is called a linked dependency.

If something during the build process fails, MAKE deletes the target file it was building. Use the .precious directive if you want MAKE to keep the target when a build fails.

You can stop MAKE after issuing the MAKE command by pressing Ctrl+Break or Ctrl+C.


BUILTINS.MAK

The file BUILTINS.MAK contains standard rules and macros that MAKE uses when it builds the targets in a makefile. To ignore this file, use the -r MAKE option .

Here is the default text of BUILTINS.MAK:

#
# Borland C++ - (C) Copyright 1997 by Borland International
#

CC       = bcc32
RC       = brcc32
AS       = tasm32

.asm.obj:
  $(AS) $(AFLAGS) $&.asm

.c.exe:
  $(CC) $(CFLAGS) $&.c

.c.obj:
  $(CC) $(CFLAGS) /c $&.c

.cpp.exe:
  $(CC) $(CFLAGS) $&.cpp

.cpp.obj:
  $(CC) $(CPPFLAGS) /c $&.cpp

.rc.res:
  $(RC) $(RFLAGS) /r $&

.SUFFIXES: .exe .obj .asm .c .res .rc

!if !$d(BCEXAMPLEDIR)
BCEXAMPLEDIR = $(MAKEDIR)\..\EXAMPLES
!endif

About makefiles

A makefile is an ASCII file that contains the set of instructions that MAKE uses to build a certain project. Although MAKE assumes your makefile is called MAKEFILE or MAKEFILE.MAK, you can specify a different makefile name with the -f option.

MAKE either builds the target(s) you specify with the make command or it builds the first target it finds in the makefile To build more than a single target, use a symbolic target in your makefile.

Makefiles can contain


Symbolic targets

A symbolic target forces MAKE to build multiple targets in a makefile. When you specify a symbolic target, the dependency line lists all the targets you want to build (a symbolic target basically uses linked dependencies to build more than one target).

For example, the following makefile uses the symbolic target AllFiles to build both FILE1.EXE and FILE2.EXE:

AllFiles: file1.exe file2.exe  #Note that AllFiles has no commands
file1.exe: file1.obj
bcc32 file1.obj
file2.exe: file2.obj
bcc32 file2.obj

Rules for symbolic targets

Observe the following rules when you use symbolic targets:

MAKE options

You can use command-line options to control the behavior of MAKE. MAKE options are case- sensitive and must be preceded with either a hyphen (-) or slash (/).

The general syntax for MAKE is

MAKE [options...] [target[target]]

where:

options
are MAKE options that control how MAKE works
target
is the name of the target listed in the makefile that you want to build

You must separate the MAKE command and the options and target arguments with spaces. When specifying targets, you can use wildcard characters (such as * and ?) to indicate multiple files. To get command-line help for MAKE, type MAKE -?.

For example, to use a file called PROJECTA.MAK as the makefile, type MAKE - fPROJECTA.MAK. Many of the command-line options have equivalent directives that you can use within the makefile.

Option Description
-a Checks dependencies of include files and nested include files associated with .OBJ files and updates the .OBJ if the .h file changed. See also -c.
-B Builds all targets regardless of file dates.
-c Caches autodependency information, which can improve MAKE speed. Use with -a. Do not use this option if MAKE modifies include files (which can happen if you use TOUCH in the makefile or if you create header or include files during the MAKE process).
-Dmacro Defines macro as a single character, causing an expression !ifdef macro written in the makefile to return true.
[-D]macro=[string] Defines macro as string. If string contains any spaces or tabs, enclose string in quotation marks. The -D is optional.
-ddirectory Specifies the drive and directory that MAKER (the real mode version of MAKE) uses when it swaps out of memory. This option must be used with -S. MAKE ignores this option.
-e Ignores a macro if its name is the same as an environment variable (MAKE uses the environment variable instead of the macro).
-ffilename Uses filename or filename.MAK instead of MAKEFILE (a space after -f is optional).
-h or -? Displays MAKE options. Default settings are shown with a trailing plus sign.
-Idirectory Searches for include files in the current directory first, then in directory you specify with this option.
-i Ignores the exit status of all programs run from the makefile and continues the build process.
-l Enables the use of long comment lines (on by default).
-K Keeps temporary files that MAKE creates (MAKE usually deletes them).
-m Displays the date and time stamp of each file as MAKE processes it.
-N Causes MAKE to mimic Microsoft's NMAKE .
-n Prints the MAKE commands but does not perform them, this is helpful for debugging makefiles.
-p Displays all macro definitions and implicit rules before executing the makefile.
-q Returns 0 if the target is up-to-date and nonzero if it is not (for use with batch files).
-r Ignores any rules defined in BUILTINS.MAK .
-S Swaps MAKER out of memory while commands are executed, reducing memory overhead and allowing compilation of large modules. MAKE ignores this option.
-s Suppresses onscreen command display (silent).
-Umacro Undefines the previous macro definition of macro.
-Wfilename Writes MAKE to filename, updating all non-string options.


Using temporary response files

MAKE can create temporary response files when your command lines become too long to place on a single line.

To begin writing to a response file, place the MAKE operator && followed by a delimiter of your choice (| makes a good delimiter) in the makefile. To finish writing to the file, repeat your delimiter.

The following example shows &&| instructing MAKE to create a file for the input to TLINK32.

prog.exe: A.obj B.obj
TLINK32 /c @&&|     # &&| opens temp file, @ for TLINK32
c0s.obj $**
prog.exe
prog.map
maths.lib cs.lib
|                       # | closes temp file, must be on first column

The response file created by &&| contains these instructions:

c0s.obj a.obj b.obj
prog.exe
prog.map
maths.lib cs.lib

MAKE names temporary file starting at MAKE0000.@@@, where the 0000 increments by one with each temporary file you create. MAKE later deletes the temporary file when it terminates.


Compatibility with Microsoft's NMAKE

Use the -N option if you want to use a makefile that was originally created for Microsoft's NMAKE. The following changes occur when you use - N:

Explicit and implicit rules

You write explicit and implicit rules to instruct MAKE how to build the targets in your makefile. In general, these rules are defined as follows: Explicit rules are instructions for specific files. Implicit rules are general instructions for files without explicit rules.

All the rules you write follow this general format:

Dependency line
Command line

While the dependency line has a different syntax for explicit and implicit rules, the command line syntax stays the same for both rule types.

MAKE supports multiple dependency lines for a single target, and a single target can have multiple command lines. However, only one dependency line should contain a related command line. For example:

Target1: dependent1 dep2 dep3 dep4 dep5
Target1: dep6 dep7 dep8
bcc -c $**


Explicit rule syntax

Explicit rules specify the instructions that MAKE must follow when it builds specific targets. Explicit rules name one or more targets followed by one or two colons. One colon means one rule is written for the target(s); two colons mean that two or more rules are written for the target(s).

Explicit rules follow this syntax:

target [target...]:[:][{path}] [dependent[s]...]
[commands]

where:

target
specifies the name and extension of the file to be built (a target must begin a line in the makefile-you cannot precede the target name with spaces or tabs). To specify more than one target, separate the target names with spaces or tabs. Also, you cannot use a target name more than once in the target position of an explicit rule.
path
is a list of directories that tells MAKE where to find the dependent files. Separate multiple directories with semicolons and enclosed the entire path specification in braces.
dependent
is the file (or files) whose date and time MAKE checks to see if it is newer than target. Each dependent file must be preceded by a space. If a dependent appears elsewhere in the makefile as a target, MAKE updates or creates that target before using the dependent in the original target (this in known as a linked dependency).
commands
are any operating system command or commands. You must indent the command line by at least one space or tab, otherwise they are interpreted as a target. Separate multiple commands with spaces.

If a dependency or command line continues on the following line, use a backslash (\) at the end of the first line to indicate that the line continues. For example,

MYSOURCE.EXE: FILE1.OBJ\          #Dependency line
FILE3.OBJ                     #Dependency line continued
bcc file1.obj file3.obj       #Command line

Single targets with multiple rules

A single target can have more than one explicit rule. To specify more than a single explicit rule, use a double colon (::) after the target name. The following example shows targets with multiple rules and commands.
.cpp.obj:
bcc -c -ncobj $<

.asm.obj:
tasm  /mx $<, asmobj\

mylib.lib :: f1.obj f2.obj      #double colon specifies multipe rules
echo Adding C files
tlib mylib -+cobjf1 -+cobjf2

mylib.lib :: f3.obj f4.obj
echo Adding ASM files
tlib mylib -+asmobjf3 -+asmobjf4


Implicit rule syntax

An implicit rule specifies a general rule for how MAKE should build files that end with specific file extensions. Implicit rules start with either a path or a period. Their main components are file extensions separated by periods. The first extension belongs to the dependent, the second to the target.

If implicit dependents are out-of-date with respect to the target, or if the dependents don't exist, MAKE executes the commands associated with the rule. MAKE updates explicit dependents before it updates implicit dependents.

Implicit rules follow this basic syntax:

[{source_dir}].source_ext[{target_dir}].target_ext:
[commands]

where:

source_dir
specifies the directory (or directories) containing the dependent files. Separate multiple directories with a semicolon.
.source_ext
specifies the dependent filename extension.
target_dir
specifies the directory where MAKE places the target files. The implicit rule will only be used for targets in this directory. Without specifying a target directory, targets from any directory will match the implicit rule.
.target_ext
specifies the target filename extension. Macros are allowed here.
: (colon)
marks the end of the dependency line.
commands
are any operating system command or commands. You must indent the command line by at least one space or tab, otherwise they are interpreted as a target.

If two implicit rules match a target extension but no dependent exists, MAKE uses the implicit rule whose dependent's extension appears first in the .SUFFIXES list.

Explicit rules with implicit commands

A target in an explicit rule can get its command line from an implicit rule. The following example shows an implicit rule followed by an explicit rule without a command line.
.c.obj:
bcc -c $<   #This command uses a macro $< described later

myprog.obj:     #This explicit rule uses the command: bcc -c myprog.c
The implicit rule command tells MAKE to compile MYPROG.C (the macro $< replaces the name myprog.obj with myprog.c).


Command syntax

Commands immediately follow an explicit or implicit rule and must begin on a new line with a space or tab.

Commands can be any operating system command, but they can also includeMAKE macros , directives , and special operators that your operating system won't recognize (however, note that | can't be used in commands). Here are some sample commands:

cd..

bcc -c mysource.c

COPY *.OBJ C:\PROJECTA

bcc -c $(SOURCE)     #Macros are explained later in the chapter.

Commands follow this general syntax:

[prefix...] commands

Command prefixes

Commands in both implicit and explicit rules can have prefixes that modify how MAKE treats the commands. The following table lists the prefixes you can use in makefiles:
Prefix Description
@ Don't display the command while it's being executed.
-num Stop processing commands in the makefile when the exit code returned from command exceeds the integer num. Normally, MAKE aborts if the exit code is nonzero. No space is allowed between - and num.
- Continue processing commands in the makefile, regardless of the exit codes they return.
& Expand either the macro $**, which represents all dependent files, or the macro $?, which represents all dependent files stamped later than the target. Execute the command once for each dependent file in the expanded macro.
! Will behave like the & prefix.

Using @

The following command uses the @ prefix, which prevents MAKE from displaying the command onscreen.
diff.exe : diff.obj
@bcc diff.obj

Using -num and -

The -num and - prefixes control the makefile processing when errors occur. You can choose to continue with the MAKE process if an error occurs or you can specify a number of errors to tolerate.

In the following example, MAKE continues processing if BCC returns errors:

target.exe : target.obj
target.obj : target.cpp
-bcc -c target.cpp

Using &

The & prefix issues a command once for each dependent file. It is especially useful for commands that don't take a list of files as parameters. For example,
copyall : file1.cpp file2.cpp
&copy $** c:\temp

invokes COPY twice as follows:

copy file1.cpp c:\temp
copy file2.cpp c:\temp

Without the & modifier, MAKE would call COPY only once. Note: the & prefix only works with $** and $! macros.


MAKE command operators

While you can use any operating system command in a MAKE command section, you can also use the following special operators:
Operator Description
< Use input from a specified file rather than from standard input
> Send the output from command to file
>> Append the output from command to file
<< Create a temporary inline file and use its contents as standard input to command. Also, create temporary response file when -N is used. Note: this is only for use with NMAKE.
&& Create a temporary response file and insert its name in the makefile
delimiter Use delimiters with temporary response files. You can use any character other than # as a delimiter. Use << and && as a starting and ending delimiter for a temporary file. Any characters on the same line and immediately following the starting delimiter are ignored. The closing delimiter must be written on a line by itself.


Using MAKE macros

A macro is a variable that MAKE expands into a string whenever MAKE encounters the macro in a makefile. For example, you can define a macro called LIBNAME that represents the string "mylib.lib." To do this, type the line LIBNAME = mylib.lib at the beginning of your makefile. Then, when MAKE encounters the macro $(LIBNAME), it substitutes the string mylib.lib. Macros let you create template makefiles that you can change to suit different projects.

To use a macro in a makefile, type $(MacroName) where MacroName is a defined macro . You can use braces or parentheses to enclose MacroName.

MAKE expands macros at various times depending on where they appear in the makefile:

If MAKE finds an undefined macro in a makefile, it looks for an operating system environment variable of that name (usually defined with SET) and uses its definition as the expansion text. For example, if you wrote $(PATH) in a makefile and never defined PATH, MAKE would use the text you defined for PATH in your AUTOEXEC.BAT. See your operating system manuals for information on defining environment variables.


Defining MAKE macros

The general syntax for defining a macro in a makefile is:
MacroName = expansion_text.

where:

MacroName
is case-sensitive (MACRO1 is different from Macro1). MacroName is limited to 512 characters.
expansion_text
is limited to 4096 characters. Expansion characters may be alphanumeric, punctuation, or spaces.
You must define each macro on a separate line in your makefile and each macro definition must start on the first character of the line. For readability, macro definitions are usually put at the top of the makefile. If MAKE finds more than one definition of MacroName, the new definition overwrites the old one.

You can also define macros using the -D command-line option. No spaces are allowed before or after the equal sign (=); however, you can define more than one macro by separating the definitions with spaces. The following examples show macros defined at the command line:

make -Dsourcedir=c:\projecta
make -Dcommand="bcc -c"
make -Dcommand=bcc option=-c

Note: Macros defined in makefiles overwrite those defined on the command line.


String substitutions in MAKE macros

MAKE lets you temporarily substitute characters in a previously defined macro. For example, if you defined the macro
SOURCE = f1.cpp f2.cpp f3.cpp

you could substitute the characters .obj for the characters .cpp by using the MAKE command $(SOURCE:.cpp=.obj). This substitution does not redefine the macro.

Rules for macro substitution:

MAKE also lets you use macros within substitution macros. For example,
MYEXT=.C
SOURCE=f1.cpp f2.cpp f3.cpp
$(SOURCE:.cpp=$(MYEXT))         #Changes f1.cpp to f1.C, etc.


Default MAKE macros

MAKE contains several default macros you can use in your makefiles. The following table lists the macro definition and what it expands to in explicit and implicit rules.

Macro Expands in implicit Expands in explicit
$* path\dependent file path\target file
$< path\dependent file+ext path\target file+ext
$: path for dependents path for target
$. dependent file+ext target file + ext
$& dependent file target file
$@ path\target file+ext path\target file+ext
$** path\dependent file+ext all dependents file+ext
$? path\dependent file+ext old dependents

Macro Expands to Comment
_ _MSDOS_ _ 1 If running under DOS
_ _MAKE_ _ 0x0370 MAKE's hex version number
MAKE make MAKE's executable file name
MAKEFLAGS options The options typed on the command line
MAKEDIR directory Directory where MAKE.EXE is located


Modifying default MAKE macros

If the default macros don't give you the exact string you want, macro modifiers let you extract parts of the string to suit your purpose. Macro modifiers are usually used with $< or $@.

To modify a default macro, use this syntax:

$(MacroName [modifier])

The following table lists macro modifiers and provides examples of their use.

Modifier Part of file name expanded Example Result
D Drive and directory $(<D) C:\PROJECTA\
F Base and extension $(<F) MYSOURCE.C
B Base only $(<B) MYSOURCE
R Drive, directory, and base $(<R) C:\PROJA\SOURCE


Using MAKE directives

MAKE directives resemble directives in languages such as C and Pascal. In MAKE, they perform various control functions, such as displaying commands onscreen before executing them. MAKE directives begin either with an exclamation point or a period, and they override any options given on the command line.

The following table lists the MAKE directives and their corresponding command-line options:
Directive Option Description
.autodepend -a Turns on autodependency checking
.cacheautodepend -c Turns on autodependency caching
!cmdswitches Uses + or - followed by non-string option letters to turn each option on or off. Spaces or tabs must appear before the + or - operator, none can appear between the operator and the option letters.
!elif Acts like a C else if
!else Acts like a C else
!endif Ends an !if, !ifdef, or !ifndef statement
!error Stops MAKE and prints an error message
!if Begins a conditional statement
!ifdef Acts like a C #ifdef, testing whether a given macro has been defined
!ifndef Acts like a C #ifndef, testing whether a given macro is undefined
.ignore -i MAKE ignores the return value of a command
!include Acts like a C #include, specifying a file to include in the makefile
.keep -K Keeps temporary files that MAKE creates (MAKE usually deletes them)
!message Prints a message to stdout while MAKE runs the makefile
.noautodepend -a- Turns off autodependency checking
.nocacheautodepend -c- Turns off autodependency caching
.noIgnore -i- Turns off .Ignore
.nokeep -K- Does not keep temporary files that MAKE creates
.nosilent -s- Displays commands before MAKE executes them
.noswap -S- Tells MAKE not to swap itself out of memory before executing a command
.path.ext Tells MAKE to search for files with the extension .ext in path directories
.precious Saves the target or targets even if the build fails
.silent -s MAKE executes commands without printing them first
.suffixes Determines the implicit rule for ambiguous dependencies
.swap -S Tells MAKE to swap itself out of memory before executing a command
!undef Clears the definition of a macro. After this, the macro is undefined


.autodepend

Autodependencies are the files that are automatically included in the targets you build, such as the header files included in your C++ source code. With .autodepend on, MAKE compares the dates and times of all the files used to build the .OBJ, including the autodependency files. If the dates or times of the files used to build the .OBJ are newer than the date/time stamp of the .OBJ file, the .OBJ file is recompiled. You can use .autodepend (or - a) in place of forming linked dependencies.


!error

The syntax of the !error directive is:
!error message

MAKE stops processing and prints the following string when it encounters this directive:

Fatal makefile exit code: Error directive: message

Embed !error in conditional statements to abort processing and print an error message, as shown in the following example:

!if !$d(MYMACRO)
#if MYMACRO isn't defined
!error MYMACRO isn't defined
!endif

If MYMACRO isn't defined, MAKE terminates and prints:

Fatal makefile 4: Error directive: MYMACRO isn't defined

Error-checking controls

MAKE offers four different controls to control error checking:


!if and other conditional directives

The !if directive works like C if statements. As shown here, the syntax of !if and the other conditional directives resembles compiler conditionals:
!if condition !if condition !if condition !ifdef macro
!endif !else !elif condition !endif
!endif !endif
The following expressions are equivalent:
!ifdef macro and !if $d(macro)
ifndef macro and !if !$d(macro)

These rules apply to conditional directives:

The following information can be included between !if and !endif directives:

In an if statement, a conditional expression consists of decimal, octal, or hexadecimal constants and the operators shown in the following table.

Operator Description Operator Description
- Negation ?: Conditional expression
~ Bit complement ! Logical NOT
+ Addition >> Right shift
- Subtraction << Left shift
* Multiplication & Bitwise AND
/ Division | Bitwise OR
% Remainder ^ Bitwise XOR
&& Logical AND >= Greater than or equal*
|| Logical OR <= Less than or equal*
> Greater than == Equality*
< Less than != Inequality*
*Operator also works with string expressions.

MAKE evaluates a conditional expression as either a 32-bit signed integer or a character string.


!include

This directive is like the #include preprocessor directive for the C or C++ language-it lets you include the text of another file in the makefile:
!include filename

You can enclose filename in quotation marks (" ") or angle brackets (< >) and nest directives to unlimited depth, but writing duplicate !include directives in a makefile isn't permitted-you'll get the error message cycle in the include file.

Rules, commands, or directives must be complete within a single source file; you can't start a command in an !include file, then finish it in the makefile.

MAKE searches for !include files in the current directory unless you've specified another directory with the -I command-line option.


!message

The !message directive lets you send messages to the screen from a makefile. You can use these messages to help debug a makefile that isn't working properly. For example, if you're having trouble with a macro definition, you could put this line in your makefile:
!message The macro is defined here as: $(MacroName)

When MAKE interprets this line, it will print onscreen (assuming the macro expands to .CPP):

The macro is defined here as: .CPP


.path.ext

The .path.ext directive tells MAKE where to look for files with a certain extension. The following example tells MAKE to look for files with the .c extension in C:\SOURCE or C:\CFILES and to look for files with the .obj extension in C:\OBJS.
.path.c = C:\CSOURCE;C:\CFILES
.path.obj = C:\OBJS


.precious

If a MAKE build fails, MAKE deletes the target file. The .precious directive prevents the file deletion, which you might desire for certain kinds of targets. For example, if your build fails to add a module to a library, you might not want the library to be deleted.

The syntax for .precious is

.precious: target [target ...]


.suffixes

The .suffixes directive tells MAKE the order (by file extensions) for building implicit rules.

The syntax of .suffixes is

.suffixes: .ext [.ext ...]

where .ext represents the dependent file extensions you list in your implicit rules. For example, you could include the line .suffixes: .asm .c .cpp to tell MAKE to interpret implicit rules beginning with the ones dependent on .ASM files, then .C files, then .CPP files, regardless of what order they appear in the makefile.

The following .suffixes example tells MAKE to look for a source file first with an .ASM extension, next with a .C extension, and finally with a .CPP extension. If MAKE finds MYPROG.ASM, it builds MYPROG.OBJ from the assembler file by calling TASM. MAKE then calls TLINK; otherwise, MAKE searches for MYPROG.C to build the .OBJ file or it searches for MYPROG.CPP.

.suffixes: .asm .c .cpp

myprog.exe: myprog.obj
bcc myprog.obj

.cpp.obj:
bcc -P -c $<
.asm.obj:
tasm /mx $<
.c.obj:
bcc -P- -c $<


!undef

!undef (undefine) clears the given macro, causing an !ifdef MacroName test to fail.

The syntax of the !undef directive is

!undef MacroName


Using macros in directives

You can use the $d macro with the !if conditional directive to perform some processing if a specific macro is defined. Follow the $d with macro name enclosed in parentheses or braces, as shown in the following example:
!if $d(DEBUG)                #If DEBUG is defined,
bcc -v f1.cpp f2.cpp         #compile with debug information;
!else                        #otherwise
bcc -v- f1.cpp f2.cpp        #don't include debug information.
!endif


Null macros

While an undefined macro name causes an !ifdef MacroName test to return false, MacroName defined as null will return true. You define a null macro by following the equal sign in the macro definition with either spaces or a return character. For example, the following line defines a null macro in a makefile:
NULLMACRO =

Either of the following lines can define a null macro on the MAKE command line:

NULLMACRO=""
-DNULLMACRO