This file has been translated from LaTeX by HeVeA.
   

File: omake-doc, Node: Top,	Next: Chapter 1,	Up: (dir)
  
  OMake manual:  
The OMake user guide and reference manual (version 0.10.3)
**********************************************************
Jason Hickey, Aleksey Nogin, et. al.
====================================
4^thNovember, 2017
==================
  
   All the documentation on a single page (23*Note Notes 0::)
  OMake table of contents

Contents
********
    
* Menu:

* Chapter 1::	Guide
* Chapter 2::	OMake quickstart guide
* Chapter 3::	Additional build examples
* Chapter 4::	OMake concepts and syntax
* Chapter 5::	Variables and Naming
* Chapter 6::	Expressions and values
* Chapter 7::	Additional language examples
* Chapter 8::	Rules
* Chapter 9::	Base library
* Chapter 10::	File, I/O and system operations
* Chapter 11::	Shell commands
* Chapter 12::	The standard objects
* Chapter 13::	Build functions and utilities
* Chapter 14::	Autoconfiguration functions and variables
* Chapter 15::	The OSH shell
* Appendix A::	Synopsis
* Appendix B::	OMake grammar
* Appendix C::	Index
* Appendix D::	Index of variables
* Appendix E::	Index of functions and special forms
* Appendix F::	Index of objects
* Appendix G::	Index of special targets
* Appendix H::	Index of options
* Appendix I::	References



-------------------------------------
This file has been translated from LaTeX by HeVeA.


File: omake-doc, Node: Notes 0,	Up: Top
 -----------------------------------
 
(1) ../index.html
(2) omake.html
(3) omake-doc.html
(4) omake-toc.html
(5) omake-contents.html
(6) omake-all-index.html
(7) omake-var-index.html
(8) omake-fun-index.html
(9) omake-obj-index.html
(10) omake-target-index.html
(11) omake-option-index.html
(12) ../index.html
(13) omake.html
(14) omake-doc.html
(15) omake-toc.html
(16) omake-contents.html
(17) omake-all-index.html
(18) omake-var-index.html
(19) omake-fun-index.html
(20) omake-obj-index.html
(21) omake-target-index.html
(22) omake-option-index.html
(23) omake-doc.html

File: omake-doc, Node: Chapter 1,	Next: Chapter 2,	Prev: Top,	Up: Top
  

Chapter 1     Guide
*******************
     
  If you are new to OMake, you the
omake-quickstart (1*Note Notes 1::) presents a short introduction
that describes how to set up a project. The
omake-build-examples (2*Note Notes 1::) gives larger examples of
build projects, and omake-language-examples (3*Note Notes 1::)
presents programming examples.
  
  
 Quickstart 2*Note Chapter 2::  A quickstart guide to
   using omake. 
 Build examples 3*Note Chapter 3::  Advanced build
   examples. 
 The OMake language 4*Note Chapter 4::  The omake language,
   including a description of objects, expressions, and values. 
 Variables and naming 5*Note Chapter 5::  Variables, names,
   and environments. 
 Language discussion 6*Note Chapter 6::  Further discussion on
   the language, including scoping, evaluation, and objects. 
 Language examples 7*Note Chapter 7::  Additional
   language examples. 
 Build rules 8*Note Chapter 8::  Defining and using rules to
   build programs. 
 Base builtin functions 9*Note Chapter 9::  Functions and
   variables in the core standard library. 
 System functions 10*Note Chapter 10::  Functions on files,
   input/output, and system commands. 
 Shell commands 11*Note Chapter 11::  Using the omake shell for
   command-line interpretation. 
 The standard objects 12*Note Chapter 12::  Pervasives
   defines the built-in objects. 
 Standard build definitions 13*Note Chapter 13::  The build
   specifications for programming languages in the OMake standard
   library. 
 Standard autoconfiguration functions and
   variables 14*Note Chapter 14::  The utilities provoded by
   the OMake standard library to simplify programming of
   autoconfiguration tests. 
 The interactive command interpreter 15*Note Chapter 15::  The osh
   command-line interpreter. 
 Appendices  
     
    OMake command-line options A*Note Appendix A:: 
      Command-line options for omake. 
    The OMake language grammar B*Note Appendix B::  A more
      precise specification of the OMake language. 
  
 All the documentation on a single page (4*Note Notes 1::)  All the
   OMake documentation in a single page. 
  
   

File: omake-doc, Node: Notes 1,	Up: Top
 
-----------------------------------

 
(1) omake-quickstart.html
(2) omake-build-examples.html
(3) omake-language-examples.html
(4) omake-doc.html

File: omake-doc, Node: Chapter 2,	Next: Chapter 3,	Prev: Chapter 1,	Up: Top
  

Chapter 2     OMake quickstart guide
************************************
    
* Menu:

* Section 2-1::	Description
* Section 2-2::	For users already familiar with make
* Section 2-3::	Building a small C program
* Section 2-4::	Larger projects
* Section 2-5::	Subdirectories
* Section 2-6::	Other things to consider
* Section 2-7::	Building OCaml programs
* Section 2-8::	The OMakefile and OMakeroot files
* Section 2-9::	Multiple version support
* Section 2-10::	Notes


File: omake-doc, Node: Section 2-1,	Next: Section 2-2,	Up: Chapter 2
  

2.1   Description
*****************

  
  omake is designed for building projects that might have source files
in several directories. Projects are normally specified using an
OMakefile in each of the project directories, and an OMakeroot file in
the root directory of the project. The OMakeroot file specifies general
build rules, and the OMakefiles specify the build parameters specific to
each of the subdirectories. When omake runs, it walks the configuration
tree, evaluating rules from all of the OMakefiles. The project is then
built from the entire collection of build rules.
* Menu:

* Subsection 2-1-1::	Automatic dependency analysis
* Subsection 2-1-2::	Content-based dependency analysis


File: omake-doc, Node: Subsection 2-1-1,	Next: Subsection 2-1-2,	Up: Section 2-1
  

2.1.1   Automatic dependency analysis
=====================================
  
  Dependency analysis has always been problematic with the make(1)
program. omake addresses this by adding the .SCANNER target, which
specifies a command to produce dependencies. For example, the following
rule
<<    .SCANNER: %.o: %.c
          $(CC) $(INCLUDE) -MM $<
>>
  
  is the standard way to generate dependencies for .c files. omake will
automatically run the scanner when it needs to determine dependencies
for a file.

File: omake-doc, Node: Subsection 2-1-2,	Prev: Subsection 2-1-1,	Up: Section 2-1
  

2.1.2   Content-based dependency analysis
=========================================
  
  Dependency analysis in omake uses MD5 digests to determine whether
files have changed. After each run, omake stores the dependency
information in a file called .omakedb in the project root directory.
When a rule is considered for execution, the command is not executed if
the target, dependencies, and command sequence are unchanged since the
last run of omake. As an optimization, omake does not recompute the
digest for a file that has an unchanged modification time, size, and
inode number.

File: omake-doc, Node: Section 2-2,	Next: Section 2-3,	Prev: Section 2-1,	Up: Chapter 2
  

2.2   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 functions (like
   'StaticCLibrary' and 'CProgram'), described in
   Chapter 13*Note Chapter 13::, 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 (see Section 8.10*Note Section 8-10::) before they are
   used. 
   - Subdirectories are incorporated into a project using the .SUBDIRS:
   target (see Section 8.8*Note Section 8-8::). 
  

File: omake-doc, Node: Section 2-3,	Next: Section 2-4,	Prev: Section 2-2,	Up: Chapter 2
  

2.3   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 --install 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 continuing
>>
  
  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 world\n");
          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 example, we will use
the gcc compiler with the -g option. In addition, 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)
>>
  

File: omake-doc, Node: Section 2-4,	Next: Section 2-5,	Prev: Section 2-3,	Up: Chapter 2
  

2.4   Larger projects
*********************

  
  As the project grows it is likely that we will want to build libraries
of code. Libraries can be built using the StaticCLibrary 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)
>>
  

File: omake-doc, Node: Section 2-5,	Next: Section 2-6,	Prev: Section 2-4,	Up: Chapter 2
  

2.5   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 directory. 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 subdirectories, 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 variable also
contains the -O3 option for the CProgram, and hello_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 section 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 additional
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), $(EMPTY), -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 variable
definitions from the if-statements. Variables in omake are
scoped---variables in nested blocks (blocks with greater indentation),
are not normally defined in outer blocks. The export directive 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 variable, and replace
occurrences of the lib string with the variable.
<<    # 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), $(EMPTY), -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 library
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 variable
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.

File: omake-doc, Node: Section 2-6,	Next: Section 2-7,	Prev: Section 2-5,	Up: Chapter 2
  

2.6   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.

File: omake-doc, Node: Section 2-7,	Next: Section 2-8,	Prev: Section 2-6,	Up: Chapter 2
  

2.7   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 world\n"
>>
  
  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))
>>
  

File: omake-doc, Node: Section 2-8,	Next: Section 2-9,	Prev: Section 2-7,	Up: Chapter 2
  

2.8   The OMakefile and OMakeroot files
***************************************

    

  OMake uses the OMakefile and OMakeroot files for configuring 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 subdirectories, specifying how to build
the files in that subdirectory.
  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 library 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 specified 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.

File: omake-doc, Node: Section 2-9,	Next: Section 2-10,	Prev: Section 2-8,	Up: Chapter 2
  

2.9   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 precisely, 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 versions of a
project. Suppose we have a project where the source files are in the
directory src/, and we want to compile two versions, 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 into 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.

File: omake-doc, Node: Section 2-10,	Prev: Section 2-9,	Up: Chapter 2
  

2.10   Notes
************

  
  
  
   - When using the vmount function for versioning, it wise to keep the
   source files distinct from the compiled versions. 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. 
  
   

File: omake-doc, Node: Chapter 3,	Next: Chapter 4,	Prev: Chapter 2,	Up: Top
  

Chapter 3     Additional build examples
***************************************
     
  Let's explain the OMake build model a bit more. One issue that
dominates this discussion is that OMake is based on global project
analysis. That means you define a configuration for the entire project,
and you run one instance of omake.
  For single-directory projects this doesn't mean much. For
multi-directory projects it means a lot. With GNU make, you would
usually invoke the make program recursively for each directory in the
project. For example, suppose you had a project with some project root
directory, containing a directory of sources src, which in turn contains
subdirectories lib and main. So your project looks like this nice piece
of ASCII art.
<<    my_project/
      |--> Makefile
      `--> src/
           |---> Makefile
           |---> lib/
           |     |---> Makefile
           |     `---> source files...
           `---> main/
                 |---> Makefile
                 `---> source files...
>>
  
  Typically, with GNU make, you would start an instance of make in
my_project/; this would in term start an instance of make in the src/
directory; and this would start new instances in lib/ and main/.
Basically, you count up the number of Makefiles in the project, and that
is the number of instances of make processes that will be created.
  The number of processes is no big deal with today's machines
(sometimes contrary the the author's opinion, we no longer live in the
1970s). The problem with the scheme was that each make process had a
separate configuration, and it took a lot of work to make sure that
everything was consistent. Furthermore, suppose the programmer runs make
in the main/ directory, but the lib/ is out-of-date. In this case, make
would happily crank away, perhaps trying to rebuild files in lib/,
perhaps just giving up.
  With OMake this changes entirely. Well, not entirely. The source
structure is quite similar, we merely add some Os to the ASCII art.
<<    my_project/
      |--> OMakeroot   (or Root.om)
      |--> OMakefile
      `--> src/
           |---> OMakefile
           |---> lib/
           |     |---> OMakefile
           |     `---> source files...
           `---> main/
                 |---> OMakefile
                 `---> source files...
>>
  
  The role of each
<dir>/OMakefile plays the same role as each <dir>/Makefile: it describes
how to build the source files in <dir>. The OMakefile retains much of
syntax and structure of the Makefile, but in most cases it is much
simpler.
  One minor difference is the presence of the OMakeroot in the project
root. The main purpose of this file is to indicate where the project
root is in the first place (in case omake is invoked from a
subdirectory). The OMakeroot serves as the bootstrap file; omake starts
by reading this file first. Otherwise, the syntax and evaluation of
OMakeroot is no different from any other OMakefile.
  The big difference is that OMake performs a global analysis. Here is
what happens when omake starts.
 
  
   1. omake locates that OMakeroot file, and reads it. 
   2. Each OMakefile points to its subdirectory OMakefiles using the
   .SUBDIRS target. For example, my_project/OMakefile has a rule,
   <<    .SUBDIRS: src
   >>
 
 and the my_project/src/OMakefile has a rule,
   <<    .SUBDIRS: lib main
   >>
 
 omake uses these rules to read and evaluate every OMakefile in the
   project. Reading and evaluation is fast. This part of the process is
   cheap.
 
   3. Now that the entire configuration is read, omake determines which
   files are out-of-date (using a global analysis), and starts the build
   process. This may take a while, depending on what exactly needs to be
   done. 
  
  There are several advantages to this model. First, since analysis is
global, it is much easier to ensure that the build configuration is
consistent--after all, there is only one configuration. Another benefit
is that the build configuration is inherited, and can be re-used, down
the hierarchy. Typically, the root OMakefile defines some standard
boilerplate and configuration, and this is inherited by subdirectories
that tweak and modify it (but do not need to restate it entirely). The
disadvantage of course is space, since this is global analysis after
all. In practice rarely seems to be a concern; omake takes up much less
space than your web browser even on large projects.
  Some notes to the GNU/BSD make user. 
  
   - OMakefiles are a lot like Makefiles. The syntax is similar, and
   there many of the builtin functions are similar. However, the two
   build systems are not the same. Some evil features (in the authors'
   opinions) have been dropped in OMake, and some new features have been
   added.
 
   - OMake works the same way on all platforms, including Win32. The
   standard configuration does the right thing, but if you care about
   porting your code to multiple platforms, and you use some tricky
   features, you may need to condition parts of your build config on the
   $(OSTYPE) variable.
 
   - A minor issue is that OMake dependency analysis is based on MD5
   file digests. That is, dependencies are based on file contents, not
   file modification times. Say goodbye to false rebuilds based on
   spurious timestamp changes and mismatches between local time and
   fileserver time. 
  
* Menu:

* Section 3-1::	OMakeroot vs. OMakefile
* Section 3-2::	An example C project
* Section 3-3::	An example OCaml project
* Section 3-4::	Handling new languages
* Section 3-5::	Collapsing the hierarchy, .SUBDIRS bodies


File: omake-doc, Node: Section 3-1,	Next: Section 3-2,	Up: Chapter 3
  

3.1   OMakeroot vs. OMakefile
*****************************

  
  Before we begin with examples, let's ask the first question, "What is
the difference between the project root OMakeroot and OMakefile?" A
short answer is, there is no difference, but you must have an OMakeroot
file (or Root.om file).
  However, the normal style is that OMakeroot is boilerplate and is
more-or-less the same for all projects. The OMakefile is where you put
all your project-specific stuff.
  To get started, you don't have to do this yourself. In most cases you
just perform the following step in your project root directory.
  
  
   - Run omake --install in your project root. 
  
  This will create the initial OMakeroot and OMakefile files that you
can edit to get started.

File: omake-doc, Node: Section 3-2,	Next: Section 3-3,	Prev: Section 3-1,	Up: Chapter 3
  

3.2   An example C project
**************************

  
  To begin, let's start with a simple example. Let's say that we have a
full directory tree, containing the following files.
<<    my_project/
      |--> OMakeroot
      |--> OMakefile
      `--> src/
           |---> OMakefile
           |---> lib/
           |     |---> OMakefile
           |     |---> ouch.c
           |     |---> ouch.h
           |     `---> bandaid.c
           `---> main/
                 |---> OMakefile
                 |---> horsefly.c
                 |---> horsefly.h
                 `---> main.c
>>
  
  Here is an example listing.
<<my_project/OMakeroot:
      # Include the standard configuration for C applications
      open build/C
      
      # Process the command-line vars
      DefineCommandVars()
      
      # Include the OMakefile in this directory.
      .SUBDIRS: .
  
  my_project/OMakefile:
      # Set up the standard configuration
      CFLAGS += -g
  
      # Include the src subdirectory
      .SUBDIRS: src
  
  my_project/src/OMakefile:
      # Add any extra options you like
      CFLAGS += -O2
  
      # Include the subdirectories
      .SUBDIRS: lib main
  
  my_project/src/lib/OMakefile:
      # Build the library as a static library.
      # This builds libbug.a on Unix/OSX, or libbug.lib on Win32.
      # Note that the source files are listed _without_ suffix.
      StaticCLibrary(libbug, ouch bandaid)
  
  my_project/src/main/OMakefile:
      # Some files include the .h files in ../lib
      INCLUDES += ../lib
  
      # Indicate which libraries we want to link against.
      LIBS[] +=
          ../lib/libbug
  
      # Build the program.
      # Builds horsefly.exe on Win32, and horsefly on Unix.
      # The first argument is the name of the executable.
      # The second argument is an array of object files (without suffix)
      # that are part of the program.
      CProgram(horsefly, horsefly main)
  
      # Build the program by default (in case omake is called
      # without any arguments).  EXE is defined as .exe on Win32,
      # otherwise it is empty.
      .DEFAULT: horsefly$(EXE)
>>
  
  Most of the configuration here is defined in the file build/C.om
(which is part of the OMake distribution). This file takes care of a lot
of work, including: 
  
   - Defining the StaticCLibrary and CProgram functions, which describe
   the canonical way to build C libraries and programs. 
   - Defining a mechanism for scanning each of the source programs to
   discover dependencies. That is, it defines .SCANNER rules for C
   source files. 
  
  Variables are inherited down the hierarchy, so for example, the value
of CFLAGS in src/main/OMakefile is "-g -O2".

File: omake-doc, Node: Section 3-3,	Next: Section 3-4,	Prev: Section 3-2,	Up: Chapter 3
  

3.3   An example OCaml project
******************************

  
  Let's repeat the example, assuming we are using OCaml instead of C.
This time, the directory tree looks like this.
<<    my_project/
      |--> OMakeroot
      |--> OMakefile
      `--> src/
           |---> OMakefile
           |---> lib/
           |     |---> OMakefile
           |     |---> ouch.ml
           |     |---> ouch.mli
           |     `---> bandaid.ml
           `---> main/
                 |---> OMakefile
                 |---> horsefly.ml
                 |---> horsefly.mli
                 `---> main.ml
>>
  
  The listing is only a bit different.
<<my_project/OMakeroot:
      # Include the standard configuration for OCaml applications
      open build/OCaml
      
      # Process the command-line vars
      DefineCommandVars()
      
      # Include the OMakefile in this directory.
      .SUBDIRS: .
  
  my_project/OMakefile:
      # Set up the standard configuration
      OCAMLFLAGS += -Wa
  
      # Do we want to use the bytecode compiler,
      # or the native-code one?  Let's use both for
      # this example.
      NATIVE_ENABLED = true
      BYTE_ENABLED = true
  
      # Include the src subdirectory
      .SUBDIRS: src
  
  my_project/src/OMakefile:
      # Include the subdirectories
      .SUBDIRS: lib main
  
  my_project/src/lib/OMakefile:
      # Let's do aggressive inlining on native code
      OCAMLOPTFLAGS += -inline 10
  
      # Build the library as a static library.
      # This builds libbug.a on Unix/OSX, or libbug.lib on Win32.
      # Note that the source files are listed _without_ suffix.
      OCamlLibrary(libbug, ouch bandaid)
  
  my_project/src/main/OMakefile:
      # These files depend on the interfaces in ../lib
      OCAMLINCLUDES += ../lib
  
      # Indicate which libraries we want to link against.
      OCAML_LIBS[] +=
          ../lib/libbug
  
      # Build the program.
      # Builds horsefly.exe on Win32, and horsefly on Unix.
      # The first argument is the name of the executable.
      # The second argument is an array of object files (without suffix)
      # that are part of the program.
      OCamlProgram(horsefly, horsefly main)
  
      # Build the program by default (in case omake is called
      # without any arguments).  EXE is defined as .exe on Win32,
      # otherwise it is empty.
      .DEFAULT: horsefly$(EXE)
>>
  
  In this case, most of the configuration here is defined in the file
build/OCaml.om. In this particular configuration, files in
my_project/src/lib are compiled aggressively with the option -inline 10,
but files in my_project/src/lib are compiled normally.

File: omake-doc, Node: Section 3-4,	Next: Section 3-5,	Prev: Section 3-3,	Up: Chapter 3
  

3.4   Handling new languages
****************************

   
  The previous two examples seem to be easy enough, but they rely on the
OMake standard library (the files build/C and build/OCaml) to do all the
work. What happens if we want to write a build configuration for a
language that is not already supported in the OMake standard library?
  For this example, let's suppose we are adopting a new language. The
language uses the standard compile/link model, but is not in the OMake
standard library. Specifically, let's say we have the following setup.
  
  
   - Source files are defined in files with a .cat suffix (for
   Categorical Abstract Terminology). 
   - .cat files are compiled with the catc compiler to produce .woof
   files (Wicked Object-Oriented Format). 
   - .woof files are linked by the catc compiler with the -c option to
   produce a .dog executable (Digital Object Group). The catc also
   defines a -a option to combine several .woof files into a library. 
   - Each .cat can refer to other source files. If a source file a.cat
   contains a line open b, then a.cat depends on the file b.woof, and
   a.cat must be recompiled if b.woof changes. The catc function takes a
   -I option to define a search path for dependencies. 
  
  To define a build configuration, we have to do three things. 
  
   1. Define a .SCANNER rule for discovering dependency information for
   the source files. 
   2. Define a generic rule for compiling a .cat file to a .woof file. 
   3. Define a rule (as a function) for linking .woof files to produce a
   .dog executable. 
  
  Initially, these definitions will be placed in the project root
OMakefile.
* Menu:

* Subsection 3-4-1::	Defining a default compilation rule
* Subsection 3-4-2::	Defining a rule for linking
* Subsection 3-4-3::	Dependency scanning
* Subsection 3-4-4::	Pulling it all together
* Subsection 3-4-5::	Finishing up


File: omake-doc, Node: Subsection 3-4-1,	Next: Subsection 3-4-2,	Up: Section 3-4
  

3.4.1   Defining a default compilation rule
===========================================
  
  Let's start with part 2, defining a generic compilation rule. We'll
define the build rule as an implicit rule. To handle the include path,
we'll define a variable CAT_INCLUDES that specifies the include path.
This will be an array of directories. To define the options, we'll use a
lazy variable (Section 7.7*Note Section 7-7::). In case there are
any other standard flags, we'll define a CAT_FLAGS variable.
<<   # Define the catc command, in case we ever want to override it
     CATC = catc
  
     # The default flags are empty
     CAT_FLAGS =
     
     # The directories in the include path (empty by default)
     INCLUDES[] =
  
     # Compute the include options from the include path
     PREFIXED_INCLUDES[] = $`(mapprefix -I, $(INCLUDES))
  
     # The default way to build a .woof file
     %.woof: %.cat
         $(CATC) $(PREFIXED_INCLUDES) $(CAT_FLAGS) -c $<
>>
  
  The final part is the build rule itself, where we call the catc
compiler with the include path, and the CAT_FLAGS that have been
defined. The $< variable represents the source file.

File: omake-doc, Node: Subsection 3-4-2,	Next: Subsection 3-4-3,	Prev: Subsection 3-4-1,	Up: Section 3-4
  

3.4.2   Defining a rule for linking
===================================
  
  For linking, we'll define another rule describing how to perform
linking. Instead of defining an implicit rule, we'll define a function
that describes the linking step. The function will take two arguments;
the first is the name of the executable (without suffix), and the second
is the files to link (also without suffixes). Here is the code fragment.
<<    # Optional link options
      CAT_LINK_FLAGS =
  
      # The function that defines how to build a .dog program
      CatProgram(program, files) =
          # Add the suffixes
          file_names = $(addsuffix .woof, $(files))
          prog_name = $(addsuffix .dog, $(program))
  
          # The build rule
          $(prog_name): $(file_names)
              $(CATC) $(PREFIXED_INCLUDES) $(CAT_FLAGS)
$(CAT_LINK_FLAGS) -o $@ $+
  
          # Return the program name
          value $(prog_name)
>>
  
  The CAT_LINK_FLAGS variable is defined just in case we want to pass
additional flags specific to the link step. Now that this function is
defined, whenever we want to define a rule for building a program, we
simply call the rule. The previous implicit rule specifies how to
compile each source file, and the CatProgram function specifies how to
build the executable.
<<    # Build a rover.dog program from the source
      # files neko.cat and chat.cat.
      # Compile it by default.
      .DEFAULT: $(CatProgram rover, neko chat)
>>
  

File: omake-doc, Node: Subsection 3-4-3,	Next: Subsection 3-4-4,	Prev: Subsection 3-4-2,	Up: Section 3-4
  

3.4.3   Dependency scanning
===========================
   
  That's it, almost. The part we left out was automated dependency
scanning. This is one of the nicer features of OMake, and one that makes
build specifications easier to write and more robust. Strictly speaking,
it isn't required, but you definitely want to do it.
  The mechanism is to define a .SCANNER rule, which is like a normal
rule, but it specifies how to compute dependencies, not the target
itself. In this case, we want to define a .SCANNER rule of the following
form.
<<    .SCANNER: %.woof: %.cat
          <commands>
>>
  
  This rule specifies that a .woof file may have additional dependencies
that can be extracted from the corresponding .cat file by executing the
<commands>. The result of executing the <commands> should be a sequence
of dependencies in OMake format, printed to the standard output.
  As we mentioned, each .cat file specifies dependencies on .woof files
with an open directive. For example, if the neko.cat file contains a
line open chat, then neko.woof depends on chat.woof. In this case, the
<commands> should print the following line.
<<    neko.woof: chat.woof
>>
  
  For an analogy that might make this clearer, consider the C
programming language, where a .o file is produced by compiling a .c
file. If a file foo.c contains a line like #include "fum.h", then foo.c
should be recompiled whenever fum.h changes. That is, the file foo.o
depends on the file fum.h. In the OMake parlance, this is called an
implicit dependency, and the .SCANNER <commands> would print a line like
the following.
<<    foo.o: fum.h
>>
  
 Now, returning to the animal world, to compute
the dependencies of neko.woof, we should scan neko.cat, line-by-line,
looking for lines of the form open <name>. We could do this by writing a
program, but it is easy enough to do it in omake itself. We can use the
builtin 'awk' function to scan the source file. One slight complication
is that the dependencies depend on the INCLUDE path. We'll use the
'find-in-path' function to find them. Here we go.
<<    .SCANNER: %.woof: %.cat
          section
              # Scan the file
              deps[] =
              awk($<)
              case $'^open'
                  deps[] += $2
                  export
  
              # Remove duplicates, and find the files in the include
path
              deps = $(find-in-path $(INCLUDES), $(set $(deps)))
  
              # Print the dependencies
              println($"$@: $(deps)")
>>
  
  Let's look at the parts. First, the entire body is defined in a
section because we are computing it internally, not as a sequence of
shell commands.
  We use the deps variable to collect all the dependencies. The awk
function scans the source file ($<) line-by-line. For lines that match
the regular expression ^open (meaning that the line begins with the word
open), we add the second word on the line to the deps variable. For
example, if the input line is open chat, then we would add the chat
string to the deps array. All other lines in the source file are
ignored.
  Next, the $(set $(deps)) expression removes any duplicate values in
the deps array (sorting the array alphabetically in the process). The
find-in-path function then finds the actual location of each file in the
include path.
  The final step is print the result as the string $"$@: $(deps)" The
quotations are added to flatten the deps array to a simple string.

File: omake-doc, Node: Subsection 3-4-4,	Next: Subsection 3-4-5,	Prev: Subsection 3-4-3,	Up: Section 3-4
  

3.4.4   Pulling it all together
===============================
  
  To complete the example, let's pull it all together into a single
project, much like our previous example.
<<    my_project/
      |--> OMakeroot
      |--> OMakefile
      `--> src/
           |---> OMakefile
           |---> lib/
           |     |---> OMakefile
           |     |---> neko.cat
           |     `---> chat.cat
           `---> main/
                 |---> OMakefile
                 `---> main.cat
>>
  
  The listing for the entire project is as follows. Here, we also
include a function CatLibrary to link several .woof files into a
library.
<<my_project/OMakeroot:
      # Process the command-line vars
      DefineCommandVars()
      
      # Include the OMakefile in this directory.
      .SUBDIRS: .
  
  my_project/OMakefile:
    
########################################################################
     # Standard config for compiling .cat files
     #
  
     # Define the catc command, in case we ever want to override it
     CATC = catc
  
     # The default flags are empty
     CAT_FLAGS =
     
     # The directories in the include path (empty by default)
     INCLUDES[] =
  
     # Compute the include options from the include path
     PREFIXED_INCLUDES[] = $`(mapprefix -I, $(INCLUDES))
  
     # Dependency scanner for .cat files
     .SCANNER: %.woof: %.cat
          section
              # Scan the file
              deps[] =
              awk($<)
              case $'^open'
                  deps[] += $2
                  export
  
              # Remove duplicates, and find the files in the include
path
              deps = $(find-in-path $(INCLUDES), $(set $(deps)))
  
              # Print the dependencies
              println($"$@: $(deps)")
  
     # The default way to compile a .cat file
     %.woof: %.cat
         $(CATC) $(PREFIXED_INCLUDES) $(CAT_FLAGS) -c $<
  
     # Optional link options
     CAT_LINK_FLAGS =
  
     # Build a library for several .woof files
     CatLibrary(lib, files) =
         # Add the suffixes
         file_names = $(addsuffix .woof, $(files))
         lib_name = $(addsuffix .woof, $(lib))
  
         # The build rule
         $(lib_name): $(file_names)
             $(CATC) $(PREFIXED_INCLUDES) $(CAT_FLAGS) $(CAT_LINK_FLAGS)
-a $@ $+
  
         # Return the program name
         value $(lib_name)
  
     # The function that defines how to build a .dog program
     CatProgram(program, files) =
         # Add the suffixes
         file_names = $(addsuffix .woof, $(files))
         prog_name = $(addsuffix .dog, $(program))
  
         # The build rule
         $(prog_name): $(file_names)
             $(CATC) $(PREFIXED_INCLUDES) $(CAT_FLAGS) $(CAT_LINK_FLAGS)
-o $@ $+
  
         # Return the program name
         value $(prog_name)
  
    
########################################################################
     # Now the program proper
     #
  
     # Include the src subdirectory
     .SUBDIRS: src
  
  my_project/src/OMakefile:
     .SUBDIRS: lib main
  
  my_project/src/lib/OMakefile:
     CatLibrary(cats, neko chat)
  
  my_project/src/main/OMakefile:
     # Allow includes from the ../lib directory
     INCLUDES[] += ../lib
  
     # Build the program
     .DEFAULT: $(CatProgram main, main ../cats)
>>
  
  Some notes. The configuration in the project OMakeroot defines the
standard configuration, including the dependency scanner, the default
rule for compiling source files, and functions for building libraries
and programs.
  These rules and functions are inherited by subdirectories, so the
.SCANNER and build rules are used automatically in each subdirectory, so
you don't need to repeat them.

File: omake-doc, Node: Subsection 3-4-5,	Prev: Subsection 3-4-4,	Up: Section 3-4
  

3.4.5   Finishing up
====================
  
  At this point we are done, but there are a few things we can consider.
  First, the rules for building cat programs is defined in the project
OMakefile. If you had another cat project somewhere, you would need to
copy the OMakeroot (and modify it as needed). Instead of that, you
should consider moving the configuration to a shared library directory,
in a file like Cat.om. That way, instead of copying the code, you could
include the shared copy with an OMake command open Cat. The share
directory should be added to your OMAKEPATH environment variable to
ensure that omake knows how to find it.
  Better yet, if you are happy with your work, consider submitting it as
a standard configuration (by sending a request to omake@metaprl.org) so
that others can make use of it too.

File: omake-doc, Node: Section 3-5,	Prev: Section 3-4,	Up: Chapter 3
  

3.5   Collapsing the hierarchy, .SUBDIRS bodies
***********************************************

   
  Some projects have many subdirectories that all have the same
configuration. For instance, suppose you have a project with many
subdirectories, each containing a set of images that are to be composed
into a web page. Apart from the specific images, the configuration of
each file is the same.
  To make this more concrete, suppose the project has four
subdirectories page1, page2, page3, and page4. Each contains two files
image1.jpg and image2.jpg that are part of a web page generated by a
program genhtml.
  Instead of of defining a OMakefile in each directory, we can define it
as a body to the .SUBDIRS command.
<<    .SUBDIRS: page1 page2 page3 page4
          index.html: image1.jpg image2jpg
              genhtml $+ > $@
>>
  
  The body of the .SUBDIRS is interpreted exactly as if it were the
OMakefile, and it can contain any of the normal statements. The body is
evaluated in the subdirectory for each of the subdirectories. We can see
this if we add a statement that prints the current directory ($(CWD)).
<<    .SUBDIRS: page1 page2 page3 page4
          println($(absname $(CWD)))
          index.html: image1.jpg image2jpg
              genhtml $+ > $@
    # prints
      /home/jyh/.../page1
      /home/jyh/.../page2
      /home/jyh/.../page3
      /home/jyh/.../page4
>>
  
* Menu:

* Subsection 3-5-1::	Using glob patterns
* Subsection 3-5-2::	Simplified sub-configurations
* Subsection 3-5-3::	Computing the subdirectory list
* Subsection 3-5-4::	Temporary directories

