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:
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 -?.
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.
-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
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
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
The general syntax for MAKE is
MAKE [options...] [target[target]]
where:
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. |
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.
<<FileName.Ext text ... <<KEEP
If you don't want to keep a temporary file, type NOKEEP or type only the temporary (optional) file name. If you don't type a file name, MAKE creates a name for you. If you use NOKEEP, it will override the -K command-line option.
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 rules follow this syntax:
target [target...]:[:][{path}] [dependent[s]...] [commands]
where:
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
.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
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:
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.
.c.obj: bcc -c $< #This command uses a macro $< described later myprog.obj: #This explicit rule uses the command: bcc -c myprog.cThe implicit rule command tells MAKE to compile MYPROG.C (the macro $< replaces the name myprog.obj with myprog.c).
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
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. |
diff.exe : diff.obj @bcc diff.obj
In the following example, MAKE continues processing if BCC returns errors:
target.exe : target.obj target.obj : target.cpp -bcc -c target.cpp
copyall : file1.cpp file2.cpp © $** 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.
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. |
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:
MacroName = expansion_text.
where:
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
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:
MYEXT=.C SOURCE=f1.cpp f2.cpp f3.cpp $(SOURCE:.cpp=$(MYEXT)) #Changes f1.cpp to f1.C, etc.
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 |
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 |
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 |
!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
!if condition | !if condition | !if condition | !ifdef macro |
!endif | !else | !elif condition | !endif |
!endif | !endif |
!ifdef macro and !if $d(macro) ifndef macro and !if !$d(macro)
These rules apply to conditional 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 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 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.c = C:\CSOURCE;C:\CFILES .path.obj = C:\OBJS
The syntax for .precious is
.precious: target [target ...]
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 $<
The syntax of the !undef directive is
!undef MacroName
!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
NULLMACRO =
Either of the following lines can define a null macro on the MAKE command line:
NULLMACRO="" -DNULLMACRO