omake-quickstart(1)

NAME

omake is a flexible build system designed for building a
wide variety of projects. This document presents a sequence of
examples intended for getting started using omake. For an
overview of omake, see the omake(1) man page.

OMAKE QUICKSTART GUIDE

FOR USERS ALREADY FAMILIAR WITH MAKE
For users already familiar with the make(1) command, here
is a list of differences to keep in mind when using omake.
* In omake, you are much less likely to define build
rules of your own. The system provides many standard function
(like StaticCLibrary and CProgram) to specify these builds more
simply.
* Implicit rules using .SUFFIXES and the .suf1.suf2:
are not supported. You should use wildcard patterns instead
%.suf2: %.suf1.
* Scoping is significant: you should define variables
and .PHONY targets before they are used.
* Subdirectories are incorporated into a project us
ing the .SUBDIRS: target.
BUILDING A SMALL C PROGRAM
To start a new project, the easiest method is to change
directories to the project root and use the command omake --in
stall to install default OMakefiles.

$ cd ~/newproject
$ omake --install
*** omake: creating OMakeroot
*** omake: creating OMakefile
*** omake: project files OMakefile and OMakeroot have
been installed
*** omake: you should edit these files before continu
ing
The default OMakefile contains sections for building C and
OCaml programs. For now, we'll build a simple C project.
Suppose we have a C file called hello_code.c containing
the following code:

#include <stdio.h>
int main(int argc, char **argv)
{
printf("Hello world0);
return 0;
}
To build the program a program hello from this file, we
can use the CProgram function. The OMakefile contains just one
line that specifies that the program hello is to be built from
the source code in the hello_code.c file (note that file suffixes
are not passed to these functions).

CProgram(hello, hello_code)
Now we can run omake to build the project. Note that the
first time we run omake, it both scans the hello_code.c file for
dependencies, and compiles it using the cc compiler. The status
line printed at the end indicates how many files were scanned,
how many were built, and how many MD5 digests were computed.

$ omake hello
*** omake: reading OMakefiles
*** omake: finished reading OMakefiles (0.0 sec)
- scan . hello_code.o
+ cc -I. -MM hello_code.c
- build . hello_code.o
+ cc -I. -c -o hello_code.o hello_code.c
- build . hello
+ cc -o hello hello_code.o
*** omake: done (0.5 sec, 1/6 scans, 2/6 rules, 5/22
digests)
$ omake
*** omake: reading OMakefiles
*** omake: finished reading OMakefiles (0.1 sec)
*** omake: done (0.1 sec, 0/4 scans, 0/4 rules, 0/9
digests)
If we want to change the compile options, we can redefine
the CC and CFLAGS variables before the CProgram line. In this ex
ample, we will use the gcc compiler with the -g option. In addi
tion, we will specify a .DEFAULT target to be built by default.
The EXE variable is defined to be .exe on Win32 systems; it is
empty otherwise.

CC = gcc
CFLAGS += -g
CProgram(hello, hello_code)
.DEFAULT: hello$(EXE)
Here is the corresponding run for omake.

$ omake
*** omake: reading OMakefiles
*** omake: finished reading OMakefiles (0.0 sec)
- scan . hello_code.o
+ gcc -g -I. -MM hello_code.c
- build . hello_code.o
+ gcc -g -I. -c -o hello_code.o hello_code.c
- build . hello
+ gcc -g -o hello hello_code.o
*** omake: done (0.4 sec, 1/7 scans, 2/7 rules, 3/22
digests)
We can, of course, include multiple files in the program.
Suppose we write a new file hello_helper.c. We would include this
in the project as follows.

CC = gcc
CFLAGS += -g
CProgram(hello, hello_code hello_helper)
.DEFAULT: hello$(EXE)
LARGER PROJECTS
As the project grows it is likely that we will want to
build libraries of code. Libraries can be built using the Stat
icCLibrary function. Here is an example of an OMakefile with two
libraries.

CC = gcc
CFLAGS += -g
FOO_FILES = foo_a foo_b
BAR_FILES = bar_a bar_b bar_c
StaticCLibrary(libfoo, $(FOO_FILES))
StaticCLibrary(libbar, $(BAR_FILES))
# The hello program is linked with both libraries
LIBS = libfoo libbar
CProgram(hello, hello_code hello_helper)
.DEFAULT: hello$(EXE)
SUBDIRECTORIES
As the project grows even further, it is a good idea to
split it into several directories. Suppose we place the libfoo
and libbar into subdirectories.
In each subdirectory, we define an OMakefile for that di
rectory. For example, here is an example OMakefile for the foo
subdirectory.

INCLUDES += .. ../bar
FOO_FILES = foo_a foo_b
StaticCLibrary(libfoo, $(FOO_FILES))
Note the the INCLUDES variable is defined to include the
other directories in the project.
Now, the next step is to link the subdirectories into the
main project. The project OMakefile should be modified to include
a .SUBDIRS: target.

# Project configuration
CC = gcc
CFLAGS += -g
# Subdirectories
.SUBDIRS: foo bar
# The libraries are now in subdirectories
LIBS = foo/libfoo bar/libbar
CProgram(hello, hello_code hello_helper)
.DEFAULT: hello$(EXE)
Note that the variables CC and CFLAGS are defined before
the .SUBDIRS target. These variables remain defined in the subdi
rectories, so that libfoo and libbar use gcc -g.
If the two directories are to be configured differently,
we have two choices. The OMakefile in each subdirectory can be
modified with its configuration (this is how it would normally be
done). Alternatively, we can also place the change in the root
OMakefile.

# Default project configuration
CC = gcc
CFLAGS += -g
# libfoo uses the default configuration
.SUBDIRS: foo
# libbar uses the optimizing compiler
CFLAGS += -O3
.SUBDIRS: bar
# Main program
LIBS = foo/libfoo bar/libbar
CProgram(hello, hello_code hello_helper)
.DEFAULT: hello$(EXE)
Note that the way we have specified it, the CFLAGS vari
able also contains the -O3 option for the CProgram, and hel
lo_code.c and hello_helper.c file will both be compiled with the
-O3 option. If we want to make the change truly local to libbar,
we can put the bar subdirectory in its own scope using the sec
tion form.

# Default project configuration
CC = gcc
CFLAGS += -g
# libfoo uses the default configuration
.SUBDIRS: foo
# libbar uses the optimizing compiler
section
CFLAGS += -O3
.SUBDIRS: bar
# Main program does not use the optimizing compiler
LIBS = foo/libfoo bar/libbar
CProgram(hello, hello_code hello_helper)
.DEFAULT: hello$(EXE)
Later, suppose we decide to port this project to Win32,
and we discover that we need different compiler flags and an ad
ditional library.

# Default project configuration
if $(equal $(OSTYPE), Win32)
CC = cl /nologo
CFLAGS += /DWIN32 /MT
export
else
CC = gcc
CFLAGS += -g
export
# libfoo uses the default configuration
.SUBDIRS: foo
# libbar uses the optimizing compiler
section
CFLAGS += $(if $(equal $(OSTYPE), Win32), $(EMP
TY), -O3)
.SUBDIRS: bar
# Default libraries
LIBS = foo/libfoo bar/libbar
# We need libwin32 only on Win32
if $(equal $(OSTYPE), Win32)
LIBS += win32/libwin32
.SUBDIRS: win32
export
# Main program does not use the optimizing compiler
CProgram(hello, hello_code hello_helper)
.DEFAULT: hello$(EXE)
Note the use of the export directives to export the vari
able definitions from the if-statements. Variables in omake are
scoped---variables in nested blocks (blocks with greater indenta
tion), are not normally defined in outer blocks. The export di
rective specifies that the variable definitions in the nested
blocks should be exported to their parent block.
Finally, for this example, we decide to copy all libraries
into a common lib directory. We first define a directory vari
able, and replace occurrences of the lib string with the vari
able.

# The common lib directory
LIB = $(dir lib)
# phony target to build just the libraries
.PHONY: makelibs
# Default project configuration
if $(equal $(OSTYPE), Win32)
CC = cl /nologo
CFLAGS += /DWIN32 /MT
export
else
CC = gcc
CFLAGS += -g
export
# libfoo uses the default configuration
.SUBDIRS: foo
# libbar uses the optimizing compiler
section
CFLAGS += $(if $(equal $(OSTYPE), Win32), $(EMP
TY), -O3)
.SUBDIRS: bar
# Default libraries
LIBS = $(LIB)/libfoo $(LIB)/libbar
# We need libwin32 only on Win32
if $(equal $(OSTYPE), Win32)
LIBS += $(LIB)/libwin32
.SUBDIRS: win32
export
# Main program does not use the optimizing compiler
CProgram(hello, hello_code hello_helper)
.DEFAULT: hello$(EXE)
In each subdirectory, we modify the OMakefiles in the li
brary directories to install them into the $(LIB) directory. Here
is the relevant change to foo/OMakefile.

INCLUDES += .. ../bar
FOO_FILES = foo_a foo_b
StaticCLibraryInstall(makelib, $(LIB), libfoo,
$(FOO_FILES))
Directory (and file names) evaluate to relative pathnames.
Within the foo directory, the $(LIB) variable evaluates to
../lib.
As another example, instead of defining the INCLUDES vari
able separately in each subdirectory, we can define it in the
toplevel as follows.

INCLUDES = $(ROOT) $(dir foo bar win32)
In the foo directory, the INCLUDES variable will evaluate
to the string .. . ../bar ../win32. In the bar directory, it
would be .. ../foo . ../win32. In the root directory it would be
. foo bar win32.
OTHER THINGS TO CONSIDER
omake also handles recursive subdirectories. For example,
suppose the foo directory itself contains several subdirectories.
The foo/OMakefile would then contain its own .SUBDIRS target, and
each of its subdirectories would contain its own OMakefile.
BUILDING OCAML PROGRAMS
By default, omake is also configured with functions for
building OCaml programs. The functions for OCaml program use the
OCaml prefix. For example, suppose we reconstruct the previous
example in OCaml, and we have a file called hello_code.ml that
contains the following code.

open Printf
let () = printf "Hello world0
An example OMakefile for this simple project would contain
the following.

# Use the byte-code compiler
BYTE_ENABLED = true
NATIVE_ENABLED = false
OCAMLCFLAGS += -g
# Build the program
OCamlProgram(hello, hello_code)
.DEFAULT: hello.run
Next, suppose the we have two library subdirectories: the
foo subdirectory is written in C, the bar directory is written in
OCaml, and we need to use the standard OCaml Unix module.

# Default project configuration
if $(equal $(OSTYPE), Win32)
CC = cl /nologo
CFLAGS += /DWIN32 /MT
export
else
CC = gcc
CFLAGS += -g
export
# Use the byte-code compiler
BYTE_ENABLED = true
NATIVE_ENABLED = false
OCAMLCFLAGS += -g
# library subdirectories
INCLUDES += $(dir foo bar)
OCAMLINCLUDES += $(dir foo bar)
.SUBDIRS: foo bar
# C libraries
LIBS = foo/libfoo
# OCaml libraries
OCAML_LIBS = bar/libbar
# Also use the Unix module
OCAML_OTHER_LIBS = unix
# The main program
OCamlProgram(hello, hello_code hello_helper)
.DEFAULT: hello
The foo/OMakefile would be configured as a C library.

FOO_FILES = foo_a foo_b
StaticCLibrary(libfoo, $(FOO_FILES))
The bar/OMakefile would build an ML library.

BAR_FILES = bar_a bar_b bar_c
OCamlLibrary(libbar, $(BAR_FILES))

NOTES

THE OMAKEFILE AND OMAKEROOT FILES
OMake uses the OMakefile and OMakeroot files for configur
ing a project. The syntax of these files is the same, but their
role is slightly different. For one thing, every project must
have exactly one OMakeroot file in the project root directory.
This file serves to identify the project root, and it contains
code that sets up the project. In contrast, a multi-directory
project will often have an OMakefile in each of the project sub
directories, specifying how to build the files in that subdirec
tory.
Normally, the OMakeroot file is boilerplate. The following
listing is a typical example.

include $(STDLIB)/build/Common
include $(STDLIB)/build/C
include $(STDLIB)/build/OCaml
include $(STDLIB)/build/LaTeX
# Redefine the command-line variables
DefineCommandVars(.)
# The current directory is part of the project
.SUBDIRS: .
The include lines include the standard configuration files
needed for the project. The $(STDLIB) represents the omake li
brary directory. The only required configuration file is Common.
The others are optional; for example, the $(STDLIB)/build/OCaml
file is needed only when the project contains programs written in
OCaml.
The DefineCommandVars function defines any variables spec
ified on the command line (as arguments of the form VAR=<value>).
The .SUBDIRS line specifies that the current directory is part of
the project (so the OMakefile should be read).
Normally, the OMakeroot file should be small and project
independent. Any project-specific configuration should be placed
in the OMakefiles of the project.

MULTIPLE VERSION SUPPORT

OMake version 0.9.6 introduced preliminary support for
multiple, simultaneous versions of a project. Versioning uses the
vmount(dir1, dir2) function, which defines a ``virtual mount'' of
directory dir1 over directory dir2. A ``virtual mount'' is like a
transparent mount in Unix, where the files from dir1 appear in
the dir2 namespace, but new files are created in dir2. More pre
cisely, the filename dir2/foo refers to: a) the file dir1/foo if
it exists, or b) dir2/foo otherwise.
The vmount function makes it easy to specify multiple ver
sions of a project. Suppose we have a project where the source
files are in the directory src/, and we want to compile two ver
sions, one with debugging support and one optimized. We create
two directories, debug and opt, and mount the src directory over
them.

section
CFLAGS += -g
vmount(-l, src, debug)
.SUBDIRS: debug
section
CFLAGS += -O3
vmount(-l, src, opt)
.SUBDIRS: opt
Here, we are using section blocks to define the scope of
the vmount---you may not need them in your project.
The -l option is optional. It specifies that files form
the src directory should be linked into the target directories
(or copied, if the system is Win32). The links are added as files
are referenced. If no options are given, then files are not
copied or linked, but filenames are translated to refer directly
to the src/ files.
Now, when a file is referenced in the debug directory, it
is linked from the src directory if it exists. For example, when
the file debug/OMakefile is read, the src/OMakefile is linked in
to the debug/ directory.
The vmount model is fairly transparent. The OMakefiles can
be written as if referring to files in the src/ directory---they
need not be aware of mounting. However, there are a few points
to keep in mind.
NOTES
* When using the vmount function for versioning, it
wise to keep the source files distinct from the compiled ver
sions. For example, suppose the source directory contained a file
src/foo.o. When mounted, the foo.o file will be the same in all
versions, which is probably not what you want. It is better to
keep the src/ directory pristine, containing no compiled code.
* When using the vmount -l option, files are linked
into the version directory only if they are referenced in the
project. Functions that examine the filesystem (like $(ls ...))
may produce unexpected results.

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 OMAKE
Copyright © 2010-2025 Platon Technologies, s.r.o.           Index | Man stránky | tLDP | Dokumenty | Utilitky | O projekte
Design by styleshout