omake-rules(1)

NAME

omake is a flexible build system designed for building a
wide variety of projects. This document describes the syntax and
semantics of rule definitions, which specify commands to build
files in a project. For an overview of omake, see the omake(1)
man page.

RULES

Rules are used by OMake to specify how to build files. At
its simplest, a rule has the following form.

<target>: <dependencies>
<commands>
The <target> is the name of a file to be built. The <de
pendencies> are a list of files that are needed before the <tar
get> can be built. The <commands> are a list of indented lines
specifying commands to build the target. For example, the follow
ing rule specifies how to compile a file hello.c.

hello.o: hello.c
$(CC) $(CFLAGS) -c -o hello.o hello.c
This rule states that the hello.o file depends on the hel
lo.c file. If the hello.c file has changed, the command $(CC)
$(CFLAGS) -c -o hello.o hello.c is to be executed to update the
target file hello.o.
A rule can have an arbitrary number of commands. The indi
vidual command lines are executed independently by the command
shell. The commands do not have to begin with a tab, but they
must be indented from the dependency line.
In addition to normal variables, the following special
variables may be used in the body of a rule.
* $*: the target name, without a suffix.
* $@: the target name.
* $^: a list of the sources, in alphabetical order,
with duplicates removed.
* $+: all the sources, in the original order.
* $<: the first source.
For example, the above hello.c rule may be simplified as
follows.

hello.o: hello.c
$(CC) $(CFLAGS) -c -o $@ $<
Unlike normal values, the variables in a rule body are ex
panded lazily, and binding is dynamic. The following function
definition illustrates some of the issues.

CLibrary(name, files) =
OFILES = $(addsuffix .o, $(files))
$(name).a: $(OFILES)
$(AR) cq $@ $(OFILES)
This function defines a rule to build a program called
$(name) from a list of .o files. The files in the argument are
specified without a suffix, so the first line of the function
definition defines a variable OFILES that adds the .o suffix to
each of the file names. The next step defines a rule to build a
target library $(name).a from the $(OFILES) files. The expression
$(AR) is evaluated when the function is called, and the value of
the variable AR is taken from the caller's scope (see also the
section on Scoping).
IMPLICIT RULES
Rules may also be implicit. That is, the files may be
specified by wildcard patterns. The wildcard character is %. For
example, the following rule specifies a default rule for building
.o files.

%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $*.c
This rule is a template for building an arbitrary .o file
from a .c file.
By default, implicit rules are only used for the targets
in the current directory. However subdirectories included via the
.SUBDIRS rules inherit all the implicit rules that are in scope
(see also the section on Scoping).
BOUNDED IMPLICIT RULES
Implicit rules may specify the set of files they apply to.
The following syntax is used.

<targets>: <pattern>: <dependencies>
<commands>
For example, the following rule applies only to the files
a.o and b.o.

a.o b.o: %.o: %.c
$(CC) $(CFLAGS) -DSPECIAL -c $*.c
SECTION
Frequently, the commands in a rule body are expressions to
be evaluated by the shell. omake also allows expressions to be
evaluated by omake itself.
The syntax of these ``computed rules'' uses the section
expression. The following rule uses the omake IO functions to
produce the target hello.c.

hello.c:
section
FP = fopen(hello.c, w)
fprintln($(FP), $""#include <stdio.h> int
main() { printf("Hello world0); }"")
close($(FP))
This example uses the quotation $""..."" to quote the text
being printed. These quotes are not included in the output file.
The fopen, fprintln, and close functions perform file IO as dis
cussed in the IO section.
In addition, commands that are function calls, or special
expressions, are interpreted correctly. Since the fprintln func
tion can take a file directly, the above rule can be abbreviated
as follows.

hello.c:
fprintln($@, $""#include <stdio.h> int main() {
printf("Hello world0); }"")
SECTION RULE
Rules can also be computed using the section rule form,
where a rule body is expected instead of an expression. In the
following rule, the file a.c is copied onto the hello.c file if
it exists, otherwise hello.c is created from the file default.c.

hello.c:
section rule
if $(target-exists a.c)
hello.c: a.c
cat a.c > hello.c
else
hello.c: default.c
cp default.c hello.c

SPECIAL DEPENDENCIES

:EXISTS:
In some cases, the contents of a dependency do not matter,
only whether the file exists or not. In this case, the :exists:
qualifier can be used for the dependency.

foo.c: a.c :exists: .flag
if $(test -e .flag)
$(CP) a.c $@
:EFFECTS:
Some commands produce files by side-effect. For example,
the latex(1) command produces a .aux file as a side-effect of
producing a .dvi file. In this case, the :effects: qualifier can
be used to list the side-effect explicitly. omake is careful to
avoid simultaneously running programs that have overlapping side
effects.

paper.dvi: paper.tex :effects: paper.aux
latex paper
:VALUE:
The :value: dependency is used to specify that the rule
execution depends on the value of an expression. For example, the
following rule

a: b c :value: $(X)
...
specifies that ``a'' should be recompiled if the value of
$(X) changes (X does not have to be a filename). This is intended
to allow greater control over dependencies.
In addition, it can be used instead of other kinds of de
pendencies. For example, the following rule:

a: b :exists: c
commands
is the same as

a: b :value: $(target-exists c)
commands
Notes:
* The values are arbitrary (they are not limited to
variables)
* The values are evaluated at rule expansion time, so
expressions containing variables like $@, $^, etc are legal.
Scanner rules define a way to specify automatic dependency
scanning. A .SCANNER rule has the following form.

.SCANNER: target: dependencies
commands
The rule is used to compute additional dependencies that
might be defined in the source files for the specified target.
The scanner produces dependencies for the specified target (which
may be a pattern) by running the commands, which must produce
output that is compatible with omake. For example, on GNU sys
tems the gcc -MM foo.c produces dependencies for the file foo.c
(based on #include information).
We can use this to specify a scanner for C files that adds
the scanned dependencies for the .o file. The following scanner
specifies that dependencies for a file, say foo.o can be computed
by running gcc -MM foo.c. Furthermore, foo.c is a dependency, so
the scanner should be recomputed whenever the foo.c file changes.

.SCANNER: %.o: %.c
gcc -MM $<
Let's suppose that the command gcc -MM foo.c prints the
following line.

foo.o: foo.h /usr/include/stdio.h
The result is that the files foo.h and /usr/in
clude/stdio.h are considered to be dependencies of foo.o---that
is, foo.o should be rebuilt if either of these files changes.
This works, to an extent. One nice feature is that the
scanner will be re-run whenever the foo.c file changes. However,
one problem is that dependencies in C are recursive. That is, if
the file foo.h is modified, it might include other files, estab
lishing further dependencies. What we need is to re-run the scan
ner if foo.h changes too.
We can do this with a value dependency. The variable $& is
defined as the dependency results from any previous scan. We can
add these as dependencies using the digest function, which com
putes an MD5 digest of the files.

.SCANNER: %.o: %.c :value: $(digest $&)
gcc -MM $<
Now, when the file foo.h changes, its digest will also
change, and the scanner will be re-run because of the value de
pendency (since $& will include foo.h).
This still is not quite right. The problem is that the C
compiler uses a search-path for include files. There may be sev
eral versions of the file foo.h, and the one that is chosen de
pends on the include path. What we need is to base the dependen
cies on the search path.
The $(digest-in-path-optional ...) function computes the
digest based on a search path, giving us a solution that works.

.SCANNER: %.o: %.c :value: $(digest-in-path-optional
$(INCLUDES), $&)
gcc -MM $(addprefix -I, $(INCLUDES)) $<
NAMED SCANNERS, AND THE :SCANNER: TARGET
Sometimes it may be useful to specify explicitly which
scanner should be used in a rule. For example, we might compile
.c files with different options, or (heaven help us) we may be
using both gcc and the Microsoft Visual C++ compiler cl. In gen
eral, the target of a .SCANNER is not tied to a particular tar
get, and we may name it as we like.

.SCANNER: scan-gcc-%.c: %.c :value: $(digest-in-path
optional $(INCLUDES), $&)
gcc -MM $(addprefix -I, $(INCLUDES)) $<
.SCANNER: scan-cl-%.c: %.c :value: $(digest-in-path
optional $(INCLUDES), $&)
cl --scan-dependencies-or-something $(addprefix
/I, $(INCLUDES)) $<
The next step is to define explicit scanner dependencies.
The :scanner: dependency is used for this. In this case, the
scanner dependencies are specified explicitly.

$(GCC_FILES): %.o: %.c :scanner: scan-gcc-%c
gcc ...
$(CL_FILES): %.obj: %.c :scanner: scan-cl-%c
cl ...
Explicit :scanner: scanner specification may also be used
to state that a single .SCANNER rule should be used to generate
dependencies for more than one target. For example,

.SCANNER: scan-all-c: $(GCC_FILES) :value: $(digest
in-path-optional $(INCLUDES), $&)
gcc -MM $(addprefix -I, $(INCLUDES)) $(GCC_FILES)
$(GCC_FILES): %.o: %.c :scanner: scan-all-c
...
The above has the advantage of only running gcc once and a
disadvantage that when a single source file changes, all the
files will end up being re-scanned.
NOTES
In most cases, you won't need to define scanners of your
own. The standard installation includes default scanners (both
explicitly and implicitly named ones) for C, OCaml, and LaTeX
files.
The SCANNER_MODE variable controls the usage of implicit
scanner dependencies. See the documentation for the SCANNER_MODE
variable in omake-root(1) for detail.
The explicit :scanner: dependencies reduce the chances of
scanner mis-specifications. In large complicated projects it
might be a good idea to set SCANNER_MODE to error and use only
the named .SCANNER rules and explicit :scanner: specifications.

OTHER SPECIAL TARGETS

There are several other special targets that define spe
cial actions to be take by omake.
.DEFAULT
The .DEFAULT target specifies a target to be built by de
fault if omake is run without explicit targets. The following
rule instructs omake to build the program hello by default

.DEFAULT: hello
.SUBDIRS
The .SUBDIRS target is used to specify a set of subdirec
tories that are part of the project. Each subdirectory should
have its own OMakefile, which is evaluated in the context of the
current environment.

.SUBDIRS: src doc tests
This rule specifies that the OMakefiles in each of the
src, doc, and tests directories should be read.
In some cases, especially when the OMakefiles are very
similar in a large number of subdirectories, it is inconvenient
to have a separate OMakefile for each directory. If the .SUBDIRS
rule has a body, the body is used instead of the OMakefile.

.SUBDIRS: src1 src2 src3
println(Subdirectory $(CWD))
.DEFAULT: lib.a
In this case, the src1, src2, and src3 files do not need
OMakefiles. Furthermore, if one exists, it is ignored. The fol
lowing includes the file if it exists.

.SUBDIRS: src1 src2 src3
if $(file-exists OMakefile)
include OMakefile
.DEFAULT: lib.a
.INCLUDE
The .INCLUDE target is like the include directive, but it
specifies a rule to build the file if it does not exist.

.INCLUDE: config
echo "CONFIG_READ = true" > config
echo CONFIG_READ is $(CONFIG_READ)
.PHONY
A ``phony'' target is a target that is not a real file,
but exists to collect a set of dependencies. Phony targets are
specified with the .PHONY rule. In the following example, the in
stall target does not correspond to a file, but it corresponds to
some commands that should be run whenever the install target is
built (for example, by running omake install).

.PHONY: install
install: myprogram.exe
cp myprogram.exe /usr/bin

RULE SCOPING

As we have mentioned before, omake is a scoped language.
This provides great flexibility---different parts of the project
can define different configurations without interfering with one
another (for example, one part of the project might be compiled
with CFLAGS=-O3 and another with CFLAGS=-g).
But how is the scope for a target file selected? Suppose
we are building a file dir/foo.o. omake uses the following rules
to determine the scope.
* First, if there is an explicit rule for building
dir/foo.o (a rule with no wildcards), the context for that rule
determines the scope for building the target.
* Otherwise, the directory dir/ must be part of the
project. This normally means that a configuration file dir/OMake
file exists (although, see the .SUBDIRS section for another way
to specify the OMakefile). In this case, the scope of the target
is the scope at the end of the dir/OMakefile.
To illustrate rule scoping, let's go back to the example
of a ``Hello world'' program with two files. Here is an example
OMakefile (the two definitions of CFLAGS are for illustration).

# The executable is compiled with debugging
CFLAGS = -g
hello: hello_code.o hello_lib.o
$(CC) $(CFLAGS) -o $@ $+
# Redefine CFLAGS
CFLAGS += -O3
In this project, the target hello is explicit. The scope
of the hello target is the line beginning with hello:, where the
value of CFLAGS is -g. The other two targets, hello_code.o and
hello_lib.o do not appear as explicit targets, so their scope is
at the end of the OMakefile, where the CFLAGS variable is defined
to be -g -O3. That is, hello will be linked with CFLAGS=-g and
the .o files will be compiled with CFLAGS=-g -O3.
We can change this behavior for any of the targets by
specifying them as explicit targets. For example, suppose we wish
to compile hello_lib.o with a preprocessor variable LIBRARY.

# The executable is compiled with debugging
CFLAGS = -g
hello: hello_code.o hello_lib.o
$(CC) $(CFLAGS) -o $@ $+
# Compile hello_lib.o with CFLAGS = -g -DLIBRARY
section
CFLAGS += -DLIBRARY
hello_lib.o:
# Redefine CFLAGS
CFLAGS += -O3
In this case, hello_lib.o is also mentioned as an explicit
target, in a scope where CFLAGS=-g -DLIBRARY. Since no rule body
is specified, it is compiled using the usual implicit rule for
building .o files (in a context where CFLAGS=-g -DLIBRARY).
SCOPING OF IMPLICIT RULES
Implicit rules (rules containing wildcard patterns) are
not global, they follow the normal scoping convention. This al
lows different parts of a project to have different sets of im
plicit rules. If we like, we can modify the example above to pro
vide a new implicit rule for building hello_lib.o.

# The executable is compiled with debugging
CFLAGS = -g
hello: hello_code.o hello_lib.o
$(CC) $(CFLAGS) -o $@ $+
# Compile hello_lib.o with CFLAGS = -g -DLIBRARY
section
%.o: %.c
$(CC) $(CFLAGS) -DLIBRARY -c $<
hello_lib.o:
# Redefine CFLAGS
CFLAGS += -O3
In this case, the target hello_lib.o is built in a scope
with a new implicit rule for building %.o files. The implicit
rule adds the -DLIBRARY option. This implicit rule is defined on
ly for the target hello_lib.o; the target hello_code.o is built
as normal.
SCOPING OF .SCANNER RULES
Scanner rules are scoped the same way as normal rules. If
the .SCANNER rule is explicit (containing no wildcard patterns),
then the scope of the scan target is the same as the the rule.
If the .SCANNER rule is implicit, then the environment is taken
from the :scanner: dependency.

# The executable is compiled with debugging
CFLAGS = -g
hello: hello_code.o hello_lib.o
$(CC) $(CFLAGS) -o $@ $+
# scanner for .c files
.SCANNER: scan-c-%.c: %.c
$(CC) $(CFLAGS) -MM $<
# Compile hello_lib.o with CFLAGS = -g -DLIBRARY
section
CFLAGS += -DLIBRARY
hello_lib.o: hello_lib.c :scanner: scan-c-hel
lo_lib.c
$(CC) $(CFLAGS) -c $<
# Compile hello_code.c with CFLAGS = -g -O3
section
CFLAGS += -O3
hello_code.o: hello_code.c :scanner: scan-c-hel
lo_code.c
$(CC) $(CFLAGS) -c $<
Again, this is for illustration---it is unlikely you would
need to write a complicated configuration like this! In this
case, the .SCANNER rule specifies that the C-compiler should be
called with the -MM flag to compute dependencies. For the target
hello_lib.o, the scanner is called with CFLAGS=-g -DLIBRARY, and
for hello_code.o it is called with CFLAGS=-g -O3.
SCOPING FOR .PHONY TARGETS
Phony targets (targets that do not correspond to files)
are defined with a .PHONY: rule. Phony targets are scoped as
usual. The following illustrates a common mistake, where the
.PHONY target is declared after it is used.

# This example is broken!
all: hello
hello: hello_code.o hello_lib.o
$(CC) $(CFLAGS) -o $@ $+
.PHONY: all
This doesn't work as expected because the .PHONY declara
tion occurs too late. The proper way to write this example is to
place the .PHONY declaration first.

# Phony targets must be declared before being used
.PHONY: all
all: hello
hello: hello_code.o hello_lib.o
$(CC) $(CFLAGS) -o $@ $+
Phony targets are passed to subdirectories. As a practical
matter, it is wise to declare all .PHONY targets in your root
OMakefile, before any .SUBDIRS. This will ensure that 1) they are
considered as phony targets in each of the sbdirectories, and 2)
you can build them from the project root.

.PHONY: all install clean
.SUBDIRS: src lib clib

REFERENCES

SEE ALSO
omake(1), omake-quickstart(1), omake-options(1), omake
root(1), omake-language(1), omake-shell(1), omake-rules(1),
omake-base(1), omake-system(1), omake-pervasives(1), osh(1),
make(1)
VERSION
Version: 0.9.6.9 of April 11, 2006.
LICENSE AND COPYRIGHT
(C)2003-2006, Mojave Group, Caltech
This program is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public Li
cense as published by the Free Software Foundation; either ver
sion 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied war
ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; if not, write to the Free Soft
ware Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
AUTHOR
Jason Hickey et. al..br Caltech 256-80
Pasadena, CA 91125, USA
Email: omake-devel@metaprl.org WWW: http://www.cs.caltech.edu/~jyh
Build Tools April 11, 2006
Copyright © 2010-2025 Platon Technologies, s.r.o.           Home | Man pages | tLDP | Documents | Utilities | About
Design by styleshout