A macro is a makefile line that consists of a macro name, an equal sign ( = ), and a macro value. In the makefile, a macro reference is an expression of the form $(name) or ${name}. The reference is macro-expanded to produce value. When name is a single character, the ( ) or { } around name are optional; for example, $X, $(X), and ${X} all specify the value of macro X. The macro character ($), always instructs omake to expand the macro that follows. When you need a dollar sign in your makefile, you must use $$.
In the following makefile, the text main.obj io.obj
occurs more than once. To reduce the amount of repeated text, you can use a macro definition to assign a symbol to the text.
project.exe : main.obj io.obj
link /out main.obj io.obj
main.obj : main.c
cl /c main.c
io.obj : io.c
cl /c io.c
Here is the same makefile written with the introduction of four macros:
OBJS = main.obj io.obj
CC = cl
CFLAGS = /c
project.exe : $(OBJS)
link $(OBJS) /out : project.exe
main.obj : main.c
$(CC) $(CFLAGS) main.c
io.obj : io.c
$(CC) $(CFLAGS) io.c
The value of the OBJS macro is the list of object files to be compiled. The macro definitions for CC and CFLAGS make it easier to change the name of the C compiler and its options.
omake imports environment variables as macros, so you can refer to things like $(COMSPEC) or $(PATH) in your makefile without having to define them in the makefile.
Macros can be defined in makefiles, defined on the command line, or predefined by omake. omake also accesses the values of environment variables as if they were macros.
Where a macro is defined determines its precedence. To redefine an existing macro, the new definition must have at least as high a precedence. This is the order of precedence:
Macros predefined by omake
Command-line definition
Environment definition (with -e command-line option)
makefile (and make.ini) definition
Environment definition (default)
By default, the lowest precedence for a macro is the environment definition. The -e command-line option gives the environment definition a higher precedence than the makefile definition. With this option, a macro definition in a makefile does not redefine a macro from the environment.
Macros are defined at read time in a makefile with macro definition lines of the form
name |
= [ text ] | standard definition |
name |
?= [ text ] | conditional definition |
name |
:= [ text ] | expanded definition |
name |
+= [ text ] | appended definition |
where name is the macro name starting in the first column of the makefile. The name can include any characters except the equal sign (=), the colon (:), and white space. By convention, the name is composed of uppercase letters, periods (.), and underscores (_). Any macro references in name are expanded; if you want a literal dollar sign in name you must use $$.
The text is arbitrary text and can reference the value of other macros with expressions of the form $(other_macro). There are four forms of macro definition:
At read time, some parts of a makefile are macro-expanded; other parts are not expanded until later.
For macro definitions, expansion depends on the separator between the macro name and the value:
= | macro name is expanded; value is not expanded until referenced |
?= | macro name is expanded; value is not expanded until referenced |
+= | macro name is expanded; value is not expanded until referenced |
:= | macro name is expanded; value is expanded |
The makefile can also contain conditional directives such as these:
%if condition
%elif condition
The condition is macro-expanded and evaluated only if the previous enclosing condition is true. For example:
%if condition_1 | (expanded & evaluated) |
% if condition_2 | (expanded & evaluated only if condition_1 is true) |
% endif | |
%else | |
% if condition_3 | (expanded & evaluated only if condition_1 is false) |
% endif | |
%endif |
This definition defines macro name and sets its value to text. If text is not given, the value of the macro is the null string, "". White space before or after the = is ignored.
This definition is like the standard macro definition, but the macro is defined only if it isn't already defined. White space between name and ?= and between ?= and text is ignored.
This definition defines macro name and sets its value to the macro-expansion of text. The text is arbitrary text and can refer to the value of other macros with expressions of the form $(other_macro), which are expanded. If text is not given, the value of the macro is the null string (""). White space between name and := and between := and text is ignored. Expanded macro definitions are useful when the text is expensive to calculate (it may require reading a file, for example).
This definition appends text to the current value of macro name. White space between name and += is ignored. If there is no white space between += and text, the new value is OLDVALUEtext. Otherwise, the new value is OLDVALUE <SPACE> text (with one intervening space). If name is an undefined macro, this definition is the same as a standard macro definition.
By default, for Windows NT omake macro names are case-insensitive. The .CASE_MACRO and .NOCASE_MACRO directives turn case-sensitivity on and off.
By convention, macro definitions appear at the beginning of the makefile. Macros must be defined before they are expanded; if they are not, their expanded value is the null string.
Usually name starts in the first column of the makefile line, but macro definitions can be indented (for example, inside an %if...%endif conditional directive). Indenting is allowed only before the first target in the makefile, or after a nonindented macro definition. This restriction is a consequence of omake's use of indenting to indicate a target's build scripts.
Macros can be undefined with the %undef directive at read time:
%undef CFLAGS
Some macros that omake predefines cannot be undefined with this directive.
This defines the macro OBJS as main.obj sub.obj. $(OBJS) is main.obj sub.obj.
OBJS = main.obj sub.obj
This defines PROJECT as $$/Make. $$ is a literal dollar sign. This means that $(PROJECT) is $/Make.
PROJECT = $$/Make
These define the macro DEBUG as 7 and the macro CFLAGS as -Z$(DEBUG). $(DEBUG) is 7 and $(CFLAGS) is -Z7.
|
| (defined as 7) |
|
| (not redefined) |
|
|
This shows an appended macro definition inside a conditional directive. If the OPT macro is defined, the CFLAGS macro's value has <SPACE>-Od appended to it. The new value of CFLAGS is -Z$(DEBUG) -Od and $(CFLAGS) is -Z7 -Od.
%if defined(OPT)
CFLAGS += -Od
%endif
This defines macro OBJSLIST as project.lst and then defines OBJS. The := causes the right side to be expanded. OBJSLIST is expanded, producing project.lst and the @ macro modifier (see Macro Modifiers) reads the file project.lst. The contents of this file is the value of OBJS. The expression := is useful here because reading the file is a relatively slow process that you want done only once. If OBJS is defined with a standard macro definition, each occurrence of $(OBJS) causes omake to read project.lst. By using :=, project.lst is read only once, when OBJS is defined.
OBJSLIST = project.lst
OBJS := $(OBJSLIST,@)
Macros can be defined on the command line, and the value of the command-line macro overrides a makefile macro or environment definition with the same name. Only standard macro definitions are allowed on the command line. A command-line macro that contains spaces must be enclosed in double quotes. (To include a literal double quote, use \".) For example, the command line
omake BSCFLAGS=/n "CFLAGS=-Zi -Od"
runs omake with BSCFLAGS defined with the value -n and CFLAGS defined with the value -Zi -Od.
omake defines some special macros whose values are dynamic. These run-time macros return information about the current target being built. For example, the .TARGET macro is name of the current target, the .SOURCE macro is the name of the inferred dependency (from an inference rule) or the first of the explicit dependencies, and the .SOURCES macro is the list of all dependencies.
Using run-time macros, the example can be written as follows:
OBJS = main.obj io.obj
CC = cl
CFLAGS =
project.exe : $(OBJS)
link /out:$(.TARGET) $(OBJS)
main.obj : main.c
$(CC) $(CFLAGS) -c $(.SOURCE)
io.obj : io.c
$(CC) $(CFLAGS) -c $(.SOURCE)
As you can see, the build scripts that update main.obj and io.obj are identical when dynamic macros are used. Dynamic macros are important for generalizing the build process with inference rules, as shown in Inference Rules.
Macros can be used to reduce the amount of repeated text. They are also used at run time to generalize the build process with inference rules. You often want to start with the value of a macro and modify it in some manner. For example, to get the list of source files from the OBJS macro you can define this macro:
SRCS = $(OBJS,.obj=.c)
This definition uses the from=to macro modifier to replace the from text in the expansion of OBJS with the to text. The result is that $(SRCS) is main.c io.c. In general, to modify a macro, expand it with
$(name,modifier[,modifier ...])
Each modifier is applied in succession to the expanded value of name. Separate modifier with comma.
There is a complete set of macro modifiers for accessing parts of file names. For example, with this macro definition:
SRCS = \src\main.c parse.l
Table 1 lists some of the modifiers.
Modifier and description | Example | Value |
---|---|---|
D, the directory | $(SRCS,D) | \src . |
E, the extension (or suffix) | $(SRCS,E) | .c.l |
F, the file name | $(SRCS,F) | main.c parse.l |
The Wstr modifier replaces white space between elements of the macro with str, a string. The str can be a mix of regular characters and special sequences, the most important sequence being \n, which represents a newline character (like pressing the <ENTER> key). For example:
$(OBJS,W +\n) is main.obj +
io.obj
Other modifiers include @ (include file contents), LC (lowercase), UC (uppercase), M (member), and N (nonmember). The M and N modifiers and the S (substitute) modifier use regular expressions for powerful and flexible pattern-matching. See Macro Modifiers for more information.
Environment variables are placed into the environment with this command:
set name=value
NOTE: This example applies to cmd.exe; the command varies depending on the shell you use.
By default, omake preloads all environment variables as macros. The .NOENVMACROS directive prevents this loading and hence prevents omake from accessing the value of any environment variables.
Expanding a macro also expands any macro references recursively. For example:
CDEFS = -DDEBUG -DNT
COPTS = -Ot
CFLAGS = -Zi $(CDEFS) $(COPTS)
The expression $(CFLAGS) evaluates to -Zi -DDEBUG -DNT -Ot.
In a macro reference $(name), name can reference other macros. For example, given the definitions
SYS = NT
NTFLAGS = -DNT -UNT
the expression $($(SYS)FLAGS) evaluates to -DNT -UNT.
Macros in build scripts are expanded immediately before the build scripts are executed. There are several macros whose values change dynamically at run time. They are discussed in Predefined Macros: Run-Time Macros.
NOTE: NMAKE supports recursive macro definitions as shown in this section. When omake is emulating NMAKE, recursive macro definitions are supported.
A macro value may reference other macros. If the value circularly references itself, omake displays a warning message when the macro is expanded. For example, the values
A = A $B
B = B1 $A B2
%echo $A
omake: file (line num): Recursive macro 'A = A $B' (warning).
A B1 B2
The expression $A expands to A expansion_of_B. In turn, the expansion of B is B1 expansion_of_A B2. When omake tries to expand a macro that is already being expanded, it displays the warning message and ignores the recursive expansion. The file and num depend on where the example lines were defined.
You can make this kind of recursive reference by using the expanded macro definition:
B := B1 $A B2
This type of definition expands any references in the right side before the macro definition of B occurs.
Feedback on the documentation in this site? We welcome any comments!
Copyright © 2001 by Rational Software Corporation. All rights reserved. |