OMAKE-QUICKSTART(1)              Build Tools               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  Static-
              CLibrary and CProgram) to specify these builds more simply.

       *      Implicit  rules using .SUFFIXES and the .suf1.suf2: are not sup-
              ported.   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 using  the  .SUB-
              DIRS: 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 --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 pro-
       grams.  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)



   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)



   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  sub-
       directories.

       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 directo-
       ries 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  con-
       tains   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 sub-
       directory 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 defini-
       tions 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  vari-
       able  definitions in the nested blocks should be exported to their par-
       ent block.

       Finally, for this example, we decide to copy all libraries into a  com-
       mon  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  directo-
       ries  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 sepa-
       rately in each subdirectory, we can define it in the toplevel  as  fol-
       lows.

           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 subdirecto-
       ries 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 world\n"


       An  example OMakefile for this simple project would contain the follow-
       ing.

           # 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 subdirec-
       tory  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 configuring a project.
       The  syntax of these files is the same, but their role is slightly dif-
       ferent. 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  con-
       trast,  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.


MULTIPLE VERSION SUPPORT
       OMake version 0.9.6 introduced preliminary support for multiple, simul-
       taneous 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  direc-
       tory  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.


   NOTES
       *      When  using  the vmount function for versioning, it wise to keep
              the source files distinct from the compiled versions. For  exam-
              ple,  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  ver-
              sion directory only if they are referenced in the project. Func-
              tions 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 License as published  by  the
       Free  Software Foundation; either version 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  warranty  of MER-
       CHANTABILITY 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 Software 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-QUICKSTART(1)
