caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Jason Hickey <jyh@cs.caltech.edu>
To: caml-list@inria.fr
Cc: Martin Jambon <martin_jambon@emailuser.net>
Subject: Re: [Caml-list] Building large and portable projects
Date: Fri, 21 Nov 2003 09:05:22 -0800	[thread overview]
Message-ID: <3FBE45D2.5070309@cs.caltech.edu> (raw)
In-Reply-To: <Pine.LNX.4.58.0311201830340.3787@localhost>

[-- Attachment #1: Type: text/plain, Size: 2662 bytes --]

Martin Jambon wrote:
> Is there a convenient way to develop OCaml code, and be sure that 
> this code will be configurable, compilable, installable and 
> executable without changes, on any environment where OCaml is available?

We have been using omake to build several large projects, primarily on 
Linux and Windows.  omake is written in OCaml, and provides a build 
system with syntax similar to make, but project-wide dependency 
analysis.  Here are some features:

     - omake runs on Unix, Windows, MacOS, and presumably
       other architectures where OCaml is available.
     - dependency analysis is project-wide (like cons),
       based on MD5 digests
     - automated dependency analysis
     - there is builtin support for OCaml and C code,
       and it is easy to add support for other kinds
       of files (just like make).
     - the OMakefile syntax is similar to GNU make, but
         - omake has user-defined functions
         - OMakefile programs are functional
         - the .SUBDIRS target is used to define
           the project hierarchy
         - different parts of the project can have
           different configuration.

omake is available by anonynous CVS from cvs.metaprl.org.
    % cvs -d :pserver:anoncvs@cvs.metaprl.org:/cvsroot login
    The password is anoncvs.
    % cvs -d :pserver:anoncvs@cvs.metaprl.org:/cvsroot checkout omake

Alternatively, RPMs are available at rpm.nogin.org.

Here is a short description.  Every project must have an OMakeroot file 
in the project root.  It is usually boilerplate; this is typical:

    # Include the standard configuration
    include $(STDROOT)

    # Include the OMakefile
    .SUBDIRS: .

The project commands are then placed in an OMakefile.  To build a 
standalone OCaml program from files a.ml b.ml and c.ml, you just need 
one line.  The OCamlProgram function is defined in the system OMakeroot.

    OCamlProgram(foo, a b c)

You can choose the byte-compiler, native-code compiler, or both.

    BYTE_ENABLED = true
    NATIVE_ENABLED = true
    OCamlProgram(foo, a b c)

Maybe you have some C files you need to include in your compile as well. 
  Perhaps f.c is a generated file.

    f.c: f1.c f2.c
	cat $+ > $@
    StaticCLibrary(bar, d e f)
    LIBS = bar
    OCamlProgram(foo, a b c)

Perhaps you use the C-preprocessor on some .mlp files:

    %.ml: %.mlp
	$(CPP) $*.mlp > $@

The system sources contain more examples, and the MetaPRL system, also 
available at cvs.metaprl.org, provides a very large, complex, example.

Jason

-- 
Jason Hickey                  http://www.cs.caltech.edu/~jyh
Caltech Computer Science      Tel: 626-395-6568 FAX: 626-792-4257

[-- Attachment #2: omake.txt --]
[-- Type: text/plain, Size: 13997 bytes --]

omake(1)                    MCC Programmer’s Manual                   omake(1)



NAME
       omake - the omake build system

SYNOPSIS
       omake is a replacement for the make(1) build program.  The omake system
       provides the following additional features.

       Recursive builds

       Omake(1) is designed for building projects that might have source files
       in  several  directories.   In  Omake,  projects are normally specified
       using an OMakefile in each of the project directories, and an OMakeroot
       file in the root directory.  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, merging rules from all of the OMakefiles.  The  project  is  then
       built from the entire collection of build rules.

       Automatic dependency analysis.

       Dependency  analysis  has always been problematic with the make(1) pro-
       gram.  Omake addresses this by adding the .SCANNER target, which speci-
       fies a command to produce dependencies.  For example, the rule

          .SCANNER: %.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.

       Content-based dependency analysis.

       Dependency  analysis  in  omake  uses  MD5 digests to determine whether
       files have changed.  After each run, omake stores the dependency infor-
       mation 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.

OMakefile
       The OMakefile has a formal similar to Makefile.  An OMakefile has three
       kinds  of  syntac  objects: variable definitions, function definitions,
       and rule definitions.

       Variables

       Variables are defined with the  following  syntax.   The  name  is  any
       sequence of alphanumeric characters, underscore ’_’, and hyphen ’-’.

          <name> = <value>

       Values are represented as a sequence of literal characters and variable
       expansions.  A variable expansion has the form "$(<name>)," which  rep-
       resents  the value of the "<name>" variable in the current environment.
       Some examples are shown below.

          CC = gcc
          CFLAGS = -Wall -g
          COMMAND = $(CC) $(CFLAGS) -O2

       In this example, the value of the COMMAND variable is the  string  "gcc
       -Wall -g -O2".

       Unlike  make,  variable  expansion  is eager, and functional.  That is,
       variable values are expanded immediately and new  variable  definitions
       to  not  affect old ones.  For example, consider the following variable
       definitions.

          X = $(COMMAND)
          COMMAND = $(COMMAND) -O3
          Y = $(COMMAND)

       In this example, the value of the X variable is the string  "gcc  -Wall
       -g -O2" as before, and the value of the Y variable is "gcc -Wall -g -O2
       -O3".

       Functions

       Functions are defined using the following syntax.

          <name>(<params>) = <indented-body>

       The parameters are a comma-separated list of identifiers, and the  body
       must  be  placed  on a separate set of lines that are indented from the
       function definition itself.  For example, the following text defines  a
       function that concatenates its arguments.

          CONCAT(a, b) =
             $(a)$(b)

       Functions  are  called  using  the GNU-make syntax, "$(<name> <args))",
       where "<args>" is a comma-separated list of values.

       Built-in functions

       addsuffix The addsuffix function adds a suffix to each component  of  a
          white-space separated list of strings.  Double-quotes may be used to
          delimit components that contain spaces.

       $(addsuffix <suffix>, <names))
       For example, $(addsuffix .c, a b "c d") expands to a.c b.c "c d".c.

       addprefix The addprefix function adds a prefix to each component  of  a
          white-space separated list of strings.  Double-quotes may be used to
          delimit components that contain spaces.

       $(addprefix <prefix>, <names))
       For example, $(addprefix foo/, a b "c d") expands to foo/a foo/b foo/"c
       d".

       replacesuffixes  The  replacesuffixes  function  modifies the suffix in
          each component of a white-space separated list of strings.

       $(replacesuffixes <old-suffixes>, <new-suffixes>, <names))
       For example, $(replacesuffixes, .h .c, .o .o, a.c b.h c.z)  expands  to
       a.o b.o c.z.

       set  The  set  function  sorts  a set of string components, eliminating
          duplicates.  Note that the quote symbol in  a  string  component  is
          significant.

       $(set <names>)
       For example, $(set z y z "m n" w a) expands to "m n" a w y z.

       not  Boolean  values  in  omake  are  represented  by  case-insensitive
          strings.  The false value can be represented by the  strings  false,
          no, nil, undefined or 0, and everything else is true.  The not func-
          tion negates a Boolean value.

       $(not <value>)
       For example, $(not false) expands to the string true, and  $(not  hello
       world) expands to false.

       equal The equal function tests for equality of two values.

       $(equal <value1>, <value2>)
       For  example  $(equal  a, b) expands to false, and $(equal hello world,
       hello world) expands to true.

       if The if function represents a conditional based on a Boolean value.

       $(if <test>, <value1> <value2>)
       For example $(if $(equal a, b), c, d) expands to d.

       filter-out The filter-out function removes a component  from  a  white-
          space separated list of strings.

       $(filter-out <value>, <names>)$
       For  example $(filter-out a, c d a "hello world") expands to c d "hello
       world".

       file The file and dir functions define location-independent  references
          to  files and directories.  In omake, the commands to build a target
          are executed in the target’s directory.  Since  there  may  be  many
          directories  in  an omake project, the build system provdes a way to
          construct a reference to a file in one  directory,  and  use  it  in
          another  without  explicitly modifying the file name.  The functions
          have the following syntax, where the name should refer to a file  or
          directory.

       $(file <name>) , $(dir <name>)
       For  example,  we can construct a reference to a file "foo" in the cur-
       rent directory.

          FOO = $(file foo)
          .SUBDIRS: bar

       If the FOO variable is expanded in the bar subdirectory, it will expand
       to ../foo.

       These  commands  are  often  used in the top-level OMakefile to provide
       location-independent references to top-level directories, so that build
       commands may refer to these directories as if they were absolute.

          ROOT = $(dir .)
          LIB  = $(dir lib)
          BIN  = $(dir bin)

       Once these variables are defined, they can be used in build commands in
       subdirectories as follows, where $(BIN) will expand to the location  of
       the bin directory relative to the command being executed.

          install: hello
            cp hello $(BIN)


       in  The  in  function is closely related to the dir and file functions.
          It takes a directory and a file, and  gives  the  filename  expanded
          relative  to that directory.  For example, one common way to install
          a file is to define a symbol link, where the value of  the  link  is
          relative to the directory where the link is created.

       $(in <dir>, <file>)
       The following commands create links in the $(LIB) directory.

           FOO = $(file foo)
           install:
              ln -s $(in $(LIB), $(FOO)) $(LIB)/foo

       Rules

       Rules  specify commands to solve a file dependency.  At its simplest, a
       rule has the following form.

       <file>: <files>
          <commands>

       For example, the  following  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 hello.c file.  If
       the hello.c file is newer, 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 individual com-
       mand lines are executed independently by the shell sh(1).  The commands
       do  not  have  to  begin with a tab, but they must be indented from the
       dependency line.

       Rules can also be implicit. That is, the  files  may  be  specified  by
       wildcard  patterns.  The wildcard character is %. For example, the fol-
       lowing rule specifies a generic way to build .o files.

       %.o: %.c
          $(CC) $(CFLAGS) -c -o $@ $*.c

       This rule is a general rule to build an arbitrry  .o  file  from  a  .c
       file.   The  variables  $@ and $* are special.  The following variables
       may be used in rules.

       $*: the target name, without a suffix.
       $@: the target name.
       $^: a list of the sources, with duplicates removed.
       $+: a list of the sources, dpulicates are not removed.
       $<: the first source

       Unlike normal values, the variables in a rule body are expanded 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  set
       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 variable expansion "$,(OFILES)" specifies that
       eager expansion should be used on the OFILES variable.

       Special targets

       .PHONY The ".PHONY" target specifies that a target name does not  actu-
          ally  correspond to a file.  Phony targets are often used to specify
          extra dependencies.  For example, the  "all"  target  is  frequently
          used  to  specify  a  set  of  files  that  should be constructed by
          default, but the "all" target does not correspond to a file.
             .PHONY: all
             all: hello.o

       .DEFAULT Omake does not build the target specified by the first rule in
          an  OMakefile  (since  there  are several OMakefiles).  The .DEFAULT
          phony target specifies what targets should be built by default.
             .DEFAULT: hello.o

       .SCANNER The ".SCANNER" target specifies a command  to  produce  depen-
          dency  information  for  a  file.  The command should produce output
          that is compatible with omake.  For example, the following rule uses
          gcc(1) to generate dependencies for .c files.
             .SCANNER: %.c
               $(CC) $(CFLAGS) -MM $^

       .SUBDIRS  The  ".SUBDIRS" target is used to specify subdirectories con-
          taining omake projects.  Each of the subdirectories should  have  an
          OMakefile.  For example, the following line specifies a project with
          three sub-projects: foo, bar, and baz.
             .SUBDIRS: foo bar baz
          The current environment is inherited by  the  subdirectories.   This
          can  be useful if different options are ot be used in different sub-
          directories.  For example, the  following  lines  specify  that  foo
          should  be  built  in  debug mode, while bar and baz should be opti-
          mized.
             CFLAGS = -g
             .SUBDIRS: foo
             CFLAGS = -O2
             .SUBDIRS: bar baz

NOTES
       Variables in omake are functional, and new variable definitions  shadow
       old  ones.  In some cases it is convenient to specify a separate set of
       variables for different build targets.  A frequent idiom in  this  case
       is to use a trivial conditional to define a separate scope.
          if 1
             CFLAGS = -g
             .SUBDIRS: foo
          .SUBDIRS: bar baz

       The  "CFLAGS  = -g" variable is defined in a scope used only by the foo
       subdirectory, not by the bar and baz directories.

       It is generally suspected that omake contains a special prize ^_^

FLAGS
       -k: do no stop when an error is encountered.
       -j <jobs>: specify the maximum number of parallel jobs to run.
       -n: do not execute the commands to build the  target,  but  print  what
       would be executed instead.
       -s: be silent and do not print commands as they are executed.
       -t: "touch" the database to make it seem that all files are up to date.
       -U: flush the dependency cache and rebuild all files from scratch.
       -u: a weaker version of the above that keeps the dependency  cache  but
       requires that the OMakefile configuration tree be re-read.

FILES
       OMakefile, OMakeroot

SEE ALSO
       make(1)



LibMojave                         2003-04-12                          omake(1)

  parent reply	other threads:[~2003-11-21 17:05 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-11-20 18:47 Martin Jambon
2003-11-20 19:56 ` sylvain.le-gall
2003-11-21  1:45   ` Nicolas Cannasse
2003-11-21  5:25     ` David Brown
2003-11-21  5:48       ` Nicolas Cannasse
2003-11-21  6:45         ` David Brown
2003-11-21  6:49         ` sylvain.le-gall
2003-11-21 16:12           ` skaller
2003-11-21 17:53             ` Eric Dahlman
2003-11-22 14:45               ` skaller
2003-11-21 19:04             ` sylvain.le-gall
2003-11-22 14:34               ` skaller
2003-11-22 18:50                 ` sylvain.le-gall
2003-11-22 14:32             ` Martin Berger
2003-11-22 14:55               ` skaller
2003-11-22 17:08             ` David Brown
2003-11-22 16:48               ` skaller
2003-11-23  3:25               ` Nicolas Cannasse
2003-11-23  4:29                 ` David Brown
2003-11-23 17:21                 ` skaller
2003-11-22 17:13             ` David Brown
2003-11-24 18:02             ` Ken Rose
2003-11-24 19:04               ` Christian Lindig
2003-11-21 16:32           ` Martin Jambon
2003-11-21 18:57             ` sylvain.le-gall
2003-11-21  9:14       ` Christian Lindig
2003-11-21  9:28 ` Richard Jones
2003-11-21 15:35 ` skaller
2003-11-21 17:05 ` Jason Hickey [this message]
2003-11-21 18:55   ` sylvain.le-gall
2003-11-21 19:30     ` [Caml-list] Omake [Was: Building large and portable projects] Aleksey Nogin
2003-11-21 20:39       ` Damien
2003-11-22  3:30         ` Aleksey Nogin
2003-11-21 23:48       ` sylvain.le-gall
2003-11-22  1:32         ` Nicolas Cannasse
2003-11-22  3:51         ` Aleksey Nogin
2003-11-28 16:29   ` [Caml-list] Building large and portable projects David Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3FBE45D2.5070309@cs.caltech.edu \
    --to=jyh@cs.caltech.edu \
    --cc=caml-list@inria.fr \
    --cc=martin_jambon@emailuser.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).