#
# Required version of omake
#
OMakeVersion(0.9.4, 0.9.4)

########################################################################
# General configuration.
#
# Copyright (C) 2003-2004 Jason Hickey and Mojave Group
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this file, to deal in the File without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the File, and to permit persons to whom the File
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the File.
#
# THE FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# FILE OR THE USE OR OTHER DEALINGS IN THE FILE.

########################################################################
# Mention a few of the other standard variables here.
#
# \begin{doc}
# \section{The OMakeroot file}
#
# The standard \File{OMakeroot} file defines the functions are rules
# for building standard projects.
#
# \subsection{Variables}
# \begin{description}
# \item[ROOT] The root directory of the current project.
# \item[CWD] The current working directory (the directory is set for each \File{OMakefile} in the project).
# \item[EMPTY] The empty string.
# \item[STDROOT] The name of the standard installed \File{OMakeroot} file.
# \end{description}
# \end{doc}
#
ROOT  = $(dir .)
LIB   = $(dir lib)
BIN   = $(dir bin)
EMPTY =

#
# A default sort rule
#
.ORDER: .BUILDORDER

########################################################################
# Generic Unix section
#

#
# \begin{doc}
# \subsection{System variables}
#
# \begin{description}\setlength{\itemsep}{0in}
# \item[CP] The copy command (\verb+cp+ on \verb+Unix+, \verb+copy+ on \verb+Win32+).
# \item[RM] The removal command (\verb+rm+ on \verb+Unix+, \verb+del /f+ on \verb+Win32+).
# \item[MKDIR] The command to create a directory (\verb+mkdir+).
# \item[CHMOD] The command to change permissions on a file (\verb+chmod+ on Unix, disabled on \verb+Win32+).
# \item[INSTALL] The command to install a program (\verb+install+ on \verb+Unix+, \verb+copy+ on \verb+Win32+).
# \item[PATHSEP] The normal path separator (\verb+:+ on \verb+Unix+, \verb+;+ on \verb+Win32+).
# \item[DIRSEP] The normal directory separator (\verb+/+ on \verb+Unix+, \verb+\+ on \verb+Win32+).
# \end{description}
# \end{doc}
#

#
# These commands are builtin, and they are the same on all platforms.
#
CP = cp
MV = mv
RM = rm -f
MKDIR = mkdir
RMDIR = rmdir
CHMOD = chmod

if $(equal $(OSTYPE), Win32)
    #
    # Command names
    #
    INSTALL = $(CP)
    PATHSEP = ;
    DIRSEP = \\

    #
    # Use copy instead of symlinks on Windows.
    #
    symlink(src, dst) =
        return($(CP) $(src) $(dst))

    export
else
    #
    # Command names
    #
    LN = ln -sf
    INSTALL = install
    PATHSEP = :
    DIRSEP = /

    #
    # When creating a symlink, make sure the path to
    # the source is viewed from the directory of the
    # destination.
    #
    symlink(src, dst) =
       src = $(file $(src))
       dst = $(file $(dst))
       return($(LN) $(in $(dirof $(dst)), $(src)) $(dst))

    export

########################################################################
# C section
#

#
# \begin{doc}
# \section{Building C programs}
#
# \Prog{omake} provides extensive support for building C programs.
#
# \subsection{C configuration variables}
#
# The following variables can be redefined in your project.
#
# \begin{description}
# \item[CC] The name of the C compiler (defaults to \verb+cc+ on \verb+Unix+, and \verb+cl+ on \verb+Win32+).
# \item[CPP] The name of the C preprocessor (defaults to \verb+cpp+ on \verb+Unix+, and \verb+cl /E+ on \verb+Win32+).
# \item[CFLAGS] Compilation flags to pass to the C compiler (default empty on \verb+Unix+, and \verb+/DWIN32+ on \verb+Win32+).
# \item[INCLUDES] Additional directories that specify the search path to the C compiler (default is \verb+.+).
#   The directories are passed to the C compiler with the \verb+-I+ option.
#   The include path with \verb+-I+ prefixes is defined in the \verb+PREFIXED_INCLUDES+ variable.
# \item[LIBS] Additional libraries needed when building a program (default is empty).
# \item[AS] The name of the assember (defaults to \verb+as+ on \verb+Unix+, and \verb+ml+ on \verb+Win32+).
# \item[ASFLAGS] Flags to pass to the assembler (default is empty on \verb+Unix+, and \verb+/c /coff+ on \verb+Win32+).
# \item[AR] The name of the program to create static libraries (defaults to \verb+ar cq+ on \verb+Unix+,
#     and \verb+lib+ on \verb+Win32+).
# \item[AROUT] The option string that specifies the output file for \verb+AR+.
# \item[RANLIB] The name of the command to postprocess the output of \verb+AR+ (defaults to \verb+ranlib+ on \verb+Unix+,
#    empty on \verb+Win32+).
# \item[LD] The name of the linker (defaults to \verb+ld+ on \verb+Unix+, and \verb+cl+ on \verb+Win32+).
# \item[LDFLAGS] Options to pass to the linker (default is empty).
# \item[EXT\_LIB] File suffix for a static library (default is \verb+.a+ on \verb+Unix+, and \verb+.lib+ on \verb+Win32+).
# \item[EXT\_OBJ] File suffix for an object file (default is \verb+.o+ on \verb+Unix+, and \verb+.obj+ on \verb+Win32+).
# \item[EXT\_ASM] File suffix for an assembly file (default is \verb+.s+ on \verb+Unix+, and \verb+.asm+ on \verb+Win32+).
# \item[EXE] File suffix for executables (default is empty for \verb+Unix+, and \verb+.exe+ on \verb+Win32+ and \verb+Cygwin+).
# \item[YACC] The name of the \verb+yacc+ parser generator (default is \verb+yacc+ on \verb+Unix+, empty on \verb+Win32+).
# \item[LEX] The name of the \verb+lex+ lexer generator (default is \verb+lex+ on \verb+Unix+, empty on \verb+Win32+).
# \end{description}
# \end{doc}
#
if $(equal $(OSTYPE), Win32)
    CC = cl /nologo
    CPP = cl /nologo /E
    CFLAGS = /DWIN32
    AR(name) =
        return(lib /nologo /debugtype:CV /out:$(name))
    LD = cl
    INCLUDES[] = .
    INCLUDES_OPT = /I
    YACC = echo yacc
    LEX = echo lex
    LIBS =
    LDFLAGS =

    AS = ml /nologo
    ASOUT = /Fo
    ASFLAGS = /c /coff

    #
    # Common suffixes for files
    #
    EXT_LIB = .lib
    EXT_OBJ = .obj
    EXT_ASM = .asm
    EXE = .exe

    export
else
    CC = cc
    CPP = cpp
    CFLAGS =
    AR(name) =
        return(ar cq $(name))
    RANLIB = ranlib
    LD = ld
    INCLUDES[] = .
    INCLUDES_OPT = -I
    YACC = yacc
    LEX = lex
    LIBS =
    LDFLAGS =

    AS = as
    ASOUT = $(array -o)
    ASFLAGS =

    #
    # Common suffixes for files
    #
    EXT_LIB = .a
    EXT_OBJ = .o
    EXT_ASM = .s
    EXE =

    export

#
# Add the -I option to the includes lazily.
# Don't redefine this variable unless you know what you are doing.
#
PREFIXED_INCLUDES = $`(addprefix $(INCLUDES_OPT), $(INCLUDES))

#
# Common suffixes for files
#
if $(equal $(OSTYPE), Cygwin)
   EXE = .exe
   export

#
# Special flags for compiling C files for use in OCaml
#
BYTE_CFLAGS =
NATIVE_CFLAGS =

#
# Generic build rules
#
#
%$(EXT_OBJ): %.c
    $(CC) $(CFLAGS) $(PREFIXED_INCLUDES) -c -o $@ $*.c

%$(EXT_OBJ): %$(EXT_ASM)
    $(AS) $(ASFLAGS) $(PREFIXED_INCLUDES) $(ASOUT)$@ $*$(EXT_ASM)

%.c: %.y
    $(YACC) $*.y

%.c: %.l
    $(LEX) $*.l

#
# Default C scanner
#
if $(equal $(OSTYPE), Win32)
    #
    # Somehow Win32 doesn't have good dependency analysis,
    # so we try to construct it by extracting the #line
    # directives from the preprocessor.
    #
    Shell. +=
        builtin-cpp-filenames(argv) =
           fsubst($(argv))
           case $'^[^"]*\("[^"]+"\).*'
              return $1

        builtin-cc-depend(argv) =
           filename = $(nth 0, $(argv))
           pipeline =\
              $(CC) $(CFLAGS) $(PREFIXED_INCLUDES) -E $(argv) |\
              grep "^#(line)? [0-9]" |\
              builtin-cpp-filenames |\
              grep "^[^<]"
           depends = $(set $(shell $(pipeline)))
           objname = $(rootname $(filename))$(EXT_OBJ)
           println($(string $(objname): $(depends)))

    .SCANNER: %$(EXT_OBJ): %.c
        builtin-cc-depend $<
    export
else
    .SCANNER: %$(EXT_OBJ): %.c
        $(CC) $(CFLAGS) $(PREFIXED_INCLUDES) -MM $<
    export

#
# Define a function to build a C-library
#
# \begin{doc}
# \subsection{StaticCLibrary}
#
# The \verb+StaticCLibrary+ builds a static library.
#
# \verb+StaticCLibrary(<target>, <files>)+
#
# The \verb+<target>+ does \emph{not} include the library suffix, and
# The \verb+<files>+ list does not include the object suffix.  These
# are obtained from the \verb+EXT_LIB+ and \verb+EXT_OBJ+ variables.
#
# The following command builds the library \verb+libfoo.a+ from the
# files \verb+a.o b.o c.o+ on \verb+Unix+, or the library
# \verb+libfoo.lib+ from the files \verb+a.obj b.obj c.obj+
# on \verb+Win32+.
#
# \begin{verbatim}
# StaticCLibrary(libfoo, a b c)
# \end{verbatim}
# \end{doc}
#
StaticCLibrary(name, files) =
    #
    # Generic library that can be used on byte and native-code
    #
    OFILES = $(addsuffix $(EXT_OBJ), $(files))

    #
    # Names of libs
    #
    NORMALLIB = $(file $(name)$(EXT_LIB))

    if $(equal $(OSTYPE), Win32)
        $(NORMALLIB): $(OFILES)
            echo $(OFILES) > $@.tmp
            $(AR $@) @$@.tmp
            $(RM) $@.tmp

    else
        $(NORMALLIB): $(OFILES)
            $(RM) $@
            $(AR $@) $(OFILES)
            $(RANLIB) $@

#
# Copy to an install directory
#
# \begin{doc}
# \subsection{StaticCLibraryCopy}
#
# The \verb+StaticCLibraryCopy+ function copies the static library
# to an install location.
#
# \verb+StaticCLibraryCopy(<tag>, <dir>, <lib>)+
#
# The \verb+<tag>+ is the name of a target (typically a \verb+.PHONY+ target);
# the \verb+<dir>+ is the installation directory, and \verb+<lib>+ is
# the library to be copied (without the library suffix).
#
# For example, the following code copies the library
# \verb+libfoo.a+ to the \verb+/usr/lib+ directory.
#
# \begin{verbatim}
# .PHONY: install
#
# StaticCLibraryCopy(install, /usr/lib, libfoo)
# \end{verbatim}
# \end{doc}
#
StaticCLibraryCopy(tag, lib, name) =
    #
    # Names of libs
    #
    NORMALLIB = $(file $(name)$(EXT_LIB))

    LIBNORMAL = $(file $(lib)/$(name)$(EXT_LIB))

    #
    # Linking the library into the root lib dir
    #
    $(LIBNORMAL): $(NORMALLIB)
        $(symlink $<, $@)

    #
    # Add dependency to the tag
    #
    $(tag): $(LIBNORMAL)

#
# We often use them together
#
# \begin{doc}
# \subsection{StaticCLibraryInstall}
#
# The \verb+StaticCLibraryInstall+ function builds a library, and
# sets the install location in one step.
#
# \verb+StaticCLibraryInstall(<tag>, <dir>, <libname>, <files>)+
#
# \begin{verbatim}
# StaticCLibraryInstall(install, /usr/lib, libfoo, a b c)
# \end{verbatim}
# \end{doc}
#
StaticCLibraryInstall(tag, lib, name, files) =
    StaticCLibrary($(name), $(files))
    StaticCLibraryCopy($(tag), $(lib), $(name))

#
# Build a .o file.  This is like a library,
# but use the linker instead.
#
# \begin{doc}
# \subsection{StaticCObject, StaticCObjectCopy, StaticCObjectInstall}
#
# These functions mirror the \verb+StaticCLibrary+, \verb+StaticCLibraryCopy+,
# and \verb+StaticCLibraryInstall+ functions, but they build an \emph{object}
# file (a \verb+.o+ file on \verb+Unix+, and a \verb+.obj+ file on \verb+Win32+).
# \end{doc}
#
StaticCObject(name, files) =
    #
    # Generic library that can be used on byte and native-code
    #
    OFILES = $(addsuffix $(EXT_OBJ), $(files))

    #
    # Names of libs
    #
    NORMALLIB = $(file $(name)$(EXT_OBJ))

    $(NORMALLIB): $(OFILES)
        $(LD) $(LDFLAGS) -r -o $@ $(OFILES)

#
# Copy to an install directory
#
StaticCObjectCopy(tag, lib, name) =
    #
    # Names of libs
    #
    NORMALLIB = $(file $(name)$(EXT_OBJ))

    LIBNORMAL = $(file $(lib)/$(name)$(EXT_OBJ))

    #
    # Linking the library into the root lib dir
    #
    $(LIBNORMAL): $(NORMALLIB)
        $(symlink $<, $@)

    #
    # Add dependency to the tag
    #
    $(tag): $(LIBNORMAL)

#
# We often use them together
#
StaticCObjectInstall(tag, lib, name, files) =
    StaticCObject($(name), $(files))
    StaticCObjectCopy($(tag), $(lib), $(name))

#
# Define a function to build a C-program
#
# \begin{doc}
# \subsection{CProgram}
#
# The \verb+CProgram+ function builds a C program from a set
# of object files and libraries.
#
# \verb+CProgram(<name>, <files>)+
#
# The \verb+<name>+ argument specifies the name of the program to be built;
# the \verb+<files>+ argument specifies the files to be linked.
#
# Additional options can be passed through the following variables.
# \begin{description}
# \item[CFLAGS] Flags used by the C compiler during the link step.
# \item[LDFLAGS] Flags to pass to the loader.
# \item[LIBS] Additional libraries to be linked.
# \end{description}
#
# For example, the following code specifies that the program
# \verb+foo+ is to be produced by linking the files \verb+bar.o+
# and \verb+baz.o+ and libraries \verb+libfoo.a+.
#
# \begin{verbatim}
# section
#    LIBS = libfoo$(EXT_LIB)
#    CProgram(foo, bar baz)
# \end{verbatim}
# \end{doc}
#
CProgram(name, files) =
   #
   # Generic program
   #
   OFILES = $(addsuffix $(EXT_OBJ), $(files))
   NAME   = $(file $(name))

   $(NAME): $(OFILES)
        $(CC) $(CFLAGS) -o $@ $,(OFILES) $(LIBS) $(LDFLAGS)

#
# Copy to a bin directory
#
# \begin{doc}
# \subsection{CProgramCopy}
#
# The \verb+CProgramCopy+ function copies a file to an install location.
#
# \verb+CProgramCopy(<tag>, <dir>, <program>)+
#
# \begin{verbatim}
# CProgramCopy(install, /usr/bin, foo)
# \end{verbatim}
# \end{doc}
#
CProgramCopy(tag, bin, name) =
   #
   # Name of the program
   #
   NAME   = $(file $(name)$(EXE))
   BINNAME = $(file $(bin)/$(name)$(EXE))

   #
   # Linking the program into the root bin dir
   #
   $(BINNAME): $(NAME)
      $(symlink $<, $@)

   #
   # Add the dependency to the tag
   #
   $(tag): $(BINNAME)

#
# We often use them together
#
# \begin{doc}
# \subsection{CProgramInstall}
#
# The \verb+CProgramInstall+ function specifies a program to build,
# and a location to install, simultaneously.
#
# \verb+CProgramInstall(<tag>, <dir>, <name>, <files>)+
#
# \begin{verbatim}
# section
#    LIBS = libfoo$(EXT_LIB)
#    CProgramInstall(install, /usr/bin, foo, bar baz)
# \end{verbatim}
# \end{doc}
#
CProgramInstall(tag, bin, name, files) =
   CProgram($(name), $(files))
   CProgramCopy($(tag), $(bin), $(name))

########################################################################
# OCaml section
#
# \begin{doc}
# \section{Building OCaml programs}
#
# \subsection{Variables for OCaml programs}
#
# The following variables can be redefined in your project.
# \begin{description}
# \item[USE\_OCAMLFIND] Whether to use the ocamlfind utility (default \verb+true\+
#    if \verb+ocamlfind+ exists, \verb+false\+ otherwise).
# \item[OCAMLC] The OCaml bytecode compiler (default \verb+ocamlc.opt+ if it exists
#    and \verb+USE_OCAMLFIND+ is not set, otherwise \verb+ocamlc+).
# \item[OCAMLOPT] The OCaml native-code compiler (default \verb+ocamlopt.opt+ if it
#    exists and \verb+USE_OCAMLFIND+ is not set, otherwise \verb+ocamlopt+).
# \item[CAMLP4] The \verb+camlp4+ preprocessor (default \verb+camlp4+).
# \item[OCAMLLEX] The OCaml lexer generator (default \verb+ocamllex+).
# \item[OCAMLYACC] The OCaml parser generator (default \verb+ocamlyacc+).
# \item[OCAMLDEP] The OCaml dependency analyzer (default \verb+ocamldep+).
# \item[OCAMLMKTOP] The OCaml toploop compiler (default \verb+ocamlmktop+).
# \item[OCAMLLINK] The OCaml bytecode linker (default \verb+$(OCAMLC)+).
# \item[OCAMLOPTLINK] The OCaml native-code linker (default \verb+$(OCAMLOPT)+).
# \item[OCAMLINCLUDES] Search path to pass to the OCaml compilers (default \verb+.+).
#    The search path with the \verb+-I+ prefix is defined by the \verb+PREFIXED_OCAMLINCLUDES+
#    variable.
# \item[OCAMLFIND] The \verb+ocamlfind+ utility (default \verb+ocamlfind+ if
#     \verb+USE_OCAMLFIND+ is set, otherwise empty).
# \item[OCAMLPACKS] Package names to pass to \verb+ocamlfind\verb+ (\verb+OCAMLFIND+ must be set).
# \item[BYTE\_ENABLED] Flag indicating whether to use the bytecode compiler (default \verb+false+).
# \item[NATIVE\_ENABLED] Flag indicating whether to use the native-code compiler (default \verb+true+).
#    Both \verb+BYTE_ENABLED+ and \verb+NATIVE_ENABLED+ can be set to true;
#    at least one should be set to true.
# \end{description}
# \end{doc}
#
USE_OCAMLFIND = $(exists-in-path ocamlfind)
OCAMLFIND = $`(if $(USE_OCAMLFIND), ocamlfind, $(EMPTY))
OCAMLC = $(if $(exists-in-path ocamlc.opt), $`(if $(USE_OCAMLFIND), ocamlc, ocamlc.opt), ocamlc)
OCAMLOPT = $(if $(exists-in-path ocamlopt.opt), $`(if $(USE_OCAMLFIND), ocamlopt, ocamlopt.opt), ocamlopt)

CAMLP4 = camlp4
OCAMLLEX = ocamllex
OCAMLYACC = ocamlyacc
OCAMLDEP = ocamldep
OCAMLMKTOP = ocamlmktop
OCAMLLINK = $`(OCAMLC)
OCAMLOPTLINK = $`(OCAMLOPT)

#
# Include path
#
OCAMLINCLUDES[] = .
PREFIXED_OCAMLINCLUDES = $`(mapprefix -I, $(OCAMLINCLUDES))

#
# Packages
#
OCAMLPACKS[] =
PREFIXED_OCAMLPACKS = $`(if $(and $(USE_OCAMLFIND) $(gt $(length $(OCAMLPACKS)), 0)),\
             -package \"$(concat \,, $(OCAMLPACKS))\",\
             $(EMPTY))

#
# Compile native or byte code?
#
BYTE_ENABLED = false
NATIVE_ENABLED = true

#
# Various options
#
# BUG JYH: The OCAMLDEPFLAGS is a hack: use the -native flag if
# we are producing native code.  The OCaml distribution does
# not provide a working ocamldep.
#
# \begin{doc}
# \subsection{OCaml command flags}
#
# The following variables specify additional options to be passed to
# the OCaml tools.
# \begin{description}
# \item[OCAMLDEPFLAGS] Flags to pass to \verb+OCAMLDEP+.
# \item[OCAMLPPFLAGS] Flags to pass to \verb+CAMLP4+.
# \item[OCAMLCFLAGS] Flags to pass to the byte-code compiler (default \verb+-g+).
# \item[OCAMLOPTFLAGS] Flags to pass to the native-code compiler (default empty).
# \item[OCAMLFLAGS] Flags to pass to either compiler (default \verb+-warn-error A+).
# \item[OCAMLINCLUDES] Include path (default \verb+.+).
# \item[OCAML\_BYTE\_LINK\_FLAGS] Flags to pass to the byte-code linker (default empty).
# \item[OCAML\_NATIVE\_LINK\_FLAGS] Flags to pass to the native-code linker (default empty).
# \item[OCAML\_LINK\_FLAGS] Flags to pass to either linker.
# \end{description}
# \end{doc}
#
OCAMLDEPFLAGS = $`(if $(NATIVE_ENABLED), -native, $(EMPTY))
OCAMLPPFLAGS  =
OCAMLFLAGS    = -warn-error A
OCAMLCFLAGS   = -g
OCAMLOPTFLAGS =
OCAMLCPPFLAGS =
OCAML_LINK_FLAGS = $`(if $(and $(USE_OCAMLFIND) $(gt $(length $(OCAMLPACKS)), 0)), -linkpkg, $(EMPTY))
OCAML_BYTE_LINK_FLAGS = -custom
OCAML_NATIVE_LINK_FLAGS =

#
# OCAML_LIBS contains libraries that are used as dependencies
# OCAML_OTHER_LIBS contains other libraries (like unix.cma)
# The lists do not include suffixes.
#
# OCAML_LINK_FLAGS contains extra linking information
#
# \begin{doc}
# \subsection{Library variables}
#
# The following variables are used during linking.
#
# \begin{description}
# \item[OCAML\_LIBS] Libraries to pass to the linker.  These libraries become dependencies
#    of the link step.
# \item[OCAML\_OTHER\_LIBS] Additional libraries to pass to the linker.  These libraries are
#    \emph{not} included as dependencies to the link step.  Typical use is for the OCaml
#    standard libraries like \verb+unix+ or \verb+str+.
# \item[OCAML\_CLIBS] C libraries to pass to the linker.
# \item[OCAML\_LIB\_FLAGS] Extra flags for the library.
# \end{description}
# \end{doc}
#
OCAML_LIBS =
OCAML_CLIBS =
OCAML_OTHER_LIBS =
OCAML_LIB_FLAGS =

#
# Generic build rules.
#
# The order of the %.cmi rules is important.
# The most recent definition is used first, if it applies.
#    1. The .cmi is generated from the .mli, if it exists
#    2. Otherwise it is generated from the .ml
#
# In case 2, make sure to use the same command text that is used for
# generating the .cmo or .cmx file.  This will prevent the compiler
# from being called twice: once to generate the .cmi file, and again
# for the .cmo or .cmx file.
#
%.cmx: %.ml
    section rule
        if $(not $(NATIVE_ENABLED))
            eprintln(!!! You are trying to build OCaml native code file: %.cmx)
            eprintln(!!! However\, the NATIVE_ENABLED flag is not set.)
            eprintln(!!! Include the following definition in your OMakefile)
            eprintln(!!! if you really want to build this file.)
            eprintln(NATIVE_ENABLED = true)
            exit(1)
        if $(or $(target-exists %.mli), $(BYTE_ENABLED))
            %.cmx: %.ml %.cmi :effects: %$(EXT_OBJ)
                $(OCAMLFIND) $(OCAMLOPT) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) \
                        $(OCAMLOPTFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<
        else
            %.cmx: %.ml :effects: %.cmi %$(EXT_OBJ)
                $(OCAMLFIND) $(OCAMLOPT) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) \
			$(OCAMLOPTFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<

%$(EXT_OBJ): %.ml
    section rule
        if $(not $(NATIVE_ENABLED))
            eprintln(!!! You are trying to build OCaml native code file: %$(EXT_OBJ))
            eprintln(!!! However\, the NATIVE_ENABLED flag is not set.)
            eprintln(!!! Include the following definition in your OMakefile)
            eprintln(!!! if you really want to build this file.)
            eprintln(NATIVE_ENABLED = true)
            exit(1)
        if $(or $(target-exists %.mli), $(BYTE_ENABLED))
            %$(EXT_OBJ): %.ml %.cmi :effects: %.cmx
                $(OCAMLFIND) $(OCAMLOPT) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) \
                        $(OCAMLOPTFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<
        else
            %$(EXT_OBJ): %.ml :effects: %.cmi %.cmx
                $(OCAMLFIND) $(OCAMLOPT) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) \
                        $(OCAMLOPTFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<

%.cmo: %.ml
    section rule
        if $(not $(BYTE_ENABLED))
            eprintln(!!! You are trying to build bytecode file: %.cmo)
            eprintln(!!! However\, the BYTE_ENABLED flag is not set.)
            eprintln(!!! Include the following definition in your OMakefile)
            eprintln(!!! if you really want to build this file.)
            eprintln(BYTE_ENABLED = true)
            exit(1)
        if $(target-exists %.mli)
            %.cmo: %.ml %.cmi
                $(OCAMLFIND) $(OCAMLC) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) \
                        $(OCAMLCFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<
        else
            %.cmo: %.ml :effects: %.cmi
                $(OCAMLFIND) $(OCAMLC) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) \
                        $(OCAMLCFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<

%.cmi: %.ml
    section rule
        if $(BYTE_ENABLED)
            %.cmi: %.ml :effects: %.cmo
                $(OCAMLFIND) $(OCAMLC) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) \
                        $(OCAMLCFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<
        else
            %.cmi: %.ml :effects: %.cmx %$(EXT_OBJ)
                $(OCAMLFIND) $(OCAMLOPT) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) $(OCAMLOPTFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<

%.cmi: %.mli
    $(OCAMLFIND) $(OCAMLC) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) \
        $(OCAMLCFLAGS) $(OCAMLPPFLAGS) $(PREFIXED_OCAMLINCLUDES) -c $<

%.ml: %.mll
    $(OCAMLLEX) $<

%.ml %.mli: %.mly
    $(OCAMLYACC) $<

%.ml %.mli: %.mlz
    $(symlink $<, $*.ml)
    $(symlink $<, $*.mli)

%.ml: %.mlp %.h
    @$(RM) -f $@
    @echo "(* CAUTION: this is a generated file.  If you edit it, all changes will be lost! *)" > $@
    $(CPP) $(OCAMLCPPFLAGS) -imacros $*.h $*.mlp >> $@
    @$(CHMOD) 444 $@

#
# Generic scanners
#
.SCANNER: %.cmi: %.mli
    $(OCAMLFIND) $(OCAMLDEP) $(PREFIXED_OCAMLPACKS) $(OCAMLDEPFLAGS) \
        $(PREFIXED_OCAMLINCLUDES) $*.mli

.SCANNER: %.cmo %.cmx: %.ml :exists: %.mli
    $(OCAMLFIND) $(OCAMLDEP) $(PREFIXED_OCAMLPACKS) $(OCAMLDEPFLAGS) \
        $(PREFIXED_OCAMLINCLUDES) $*.ml

#
# Make sure generated files are built before scanning
#
OCamlGeneratedFiles(files) =
   .SCANNER: %.cmi: $(files)
   .SCANNER: %.cmo %.cmx: $(files)
   export

#
# Define a link order for OCaml files.
# If a file depends on a %.cmi, it also depends on %.cmo
#
.ORDER: .OCAMLLINK

.OCAMLLINK: %.cmi: %.cmo
.OCAMLLINK: %.cmx: %.cmo

ABORT_ON_DEPENDENCY_ERRORS = false

OCamlLinkSort(nodes) =
   if $(ABORT_ON_DEPENDENCY_ERRORS)
      nodes = $(file-check-sort .OCAMLLINK, $(nodes))
      return($(nodes))
   else
      nodes = $(file-sort .OCAMLLINK, $(nodes))
      return($(nodes))

#
# Generic rule to build an ML library
#
# \begin{doc}
# \subsection{OCamlLibrary}
#
# The \verb+OCamlLibrary+ function builds an OCaml library.
#
# \verb+OCamlLibrary(<libname>, <files>)+
#
# The \verb+<libname>+ and \verb+<files>+ are listed \emph{without} suffixes.
#
# Additional variables used by the function:
# \begin{description}
# \item[ABORT\_ON\_DEPENDENCY\_ERRORS] The linker requires that the files to be
#   listed in dependecy order.  If this variable is true, the order of
#   the files is determined by the command line, but \Prog{omake} will
#   abort with an error message if the order is illegal.  Otherwise,
#   the files are sorted automatically.
# \end{description}
#
# The following code builds the \verb+libfoo.cmxa+ library from the files \verb+foo.cmx+
# and \verb+bar.cmx+ (if \verb+NATIVE_ENABLED+ is set), and \verb+libfoo.cma+ from
# \verb+foo.cmo+ and \verb+bar.cmo+ (if \verb+BYTE_ENABLED+ is set).
#
# \begin{verbatim}
# OCamlLibrary(libfoo, foo bar)
# \end{verbatim}
# \end{doc}
#
OCamlLibrary(name, files) =
   OFILES   = $(addsuffix $(EXT_OBJ), $(files))
   CMOFILES = $(addsuffix .cmo, $(files))
   CMXFILES = $(addsuffix .cmx, $(files))

   CLIB      = $(file $(name)$(EXT_LIB))
   BYTELIB   = $(file $(name).cma)
   NATIVELIB = $(file $(name).cmxa)

   #
   # Link commands
   #
   $(BYTELIB): $(CMOFILES)
        $(OCAMLFIND) $(OCAMLLINK) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) $(OCAMLCFLAGS) \
                $(OCAML_LIB_FLAGS) -a -o $@ $(OCamlLinkSort $(CMOFILES))

   $(NATIVELIB) $(CLIB): $(CMXFILES) $(OFILES)
        $(OCAMLFIND) $(OCAMLOPTLINK) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) $(OCAMLOPTFLAGS) \
                $(OCAML_LIB_FLAGS) -a -o $(NATIVELIB) $(OCamlLinkSort $(CMXFILES))

#
# If the interfaces are to be installed,
# define this variable to be true.
#
INSTALL_INTERFACES = false

#
# Install the library
#
# \begin{doc}
# \subsection{OCamlLibraryCopy}
#
# The \verb+OCamlLibraryCopy+ function copies a library to an install location.
#
# \verb+OCamlLibraryCopy(<tag>, <libdir>, <libname>, <interface-files>)+
#
# The \verb+<interface-files>+ specify additional interface files
# to be copied if the \verb+INSTALL_INTERFACES+ variable is true.
# \end{doc}
#
OCamlLibraryCopy(tag, lib, name, ifiles) =
   #
   # Copy interfaces
   #
   if $(INSTALL_INTERFACES)
      MLIFILES  = $(addprefix $(lib)/, $(filter-targets $(addsuffix .mli, $(ifiles))))
      CMIFILES  = $(addprefix $(lib)/, $(addsuffix .cmi, $(ifiles)))

      $(MLIFILES) $(CMIFILES): $(lib)/%: %
          $(symlink $<, $@)

      # Add to the install tag
      $(tag): $(MLIFILES) $(CMIFILES)

   #
   # Also install libraries
   #
   CLIB      = $(file $(name)$(EXT_LIB))
   BYTELIB   = $(file $(name).cma)
   NATIVELIB = $(file $(name).cmxa)

   LIBCLIB   = $(file $(lib)/$(name)$(EXT_LIB))
   LIBBYTE   = $(file $(lib)/$(name).cma)
   LIBNATIVE = $(file $(lib)/$(name).cmxa)

   #
   # Link libraries into lib directory
   #
   $(LIBBYTE): $(BYTELIB)
        $(symlink $<, $@)

   $(LIBNATIVE): $(NATIVELIB)
        $(symlink $<, $@)

   $(LIBCLIB): $(CLIB)
        $(symlink $<, $@)

   #
   # Add dependencies to the target tag
   #
   if $(BYTE_ENABLED)
      $(tag): $(LIBBYTE)

   if $(NATIVE_ENABLED)
      $(tag): $(LIBNATIVE) $(LIBCLIB)

#
# We often use them together
#
# \begin{doc}
# \subsection{OCamlLibraryInstall}
#
# The \verb+OCamlLibraryInstall+ function builds a libary
# and copies it to an install location in one step.
#
# \verb+OCamlLibraryInstall(<tag>, <libdir>, <libname>, <files>)+
# \end{doc}
#
OCamlLibraryInstall(tag, lib, name, files) =
    OCamlLibrary($(name), $(files))
    OCamlLibraryCopy($(tag), $(lib), $(name), $(files))

#
# Generic rule to build an OCaml program
#    name: the name of the target, without a suffix
#    files: names of the object files, without suffixes
#
# Other variables:
#    OCAML_LIBS: OCaml libraries target depends on, without suffix
#    OCAML_CLIBS: C libraries we depend on, without suffix
#    OCAML_OTHER_LIBS: OCaml libraries, without dependencies, without suffix
#    OCAML_BYTE_LINK_FLAGS: additional flags for byte compiler
#    OCAML_NATIVE_LINK_FLAGS: additional flags for native-code compiler
#    OCAML_LINK_FLAGS: general additional options (usually the -cclib options)
#
# \begin{doc}
# \subsection{OCamlProgram}
#
# The \verb+OCamlProgram+ function builds an OCaml program.
#
# \verb+OCamlProgram(<name>, <files>)+
#
# Additonal variables used:
# \begin{description}
# \item[OCAML\_LIBS] Additional libraries passed to the linker, without suffix.  These files
#    become dependencies of the target program.
# \item[OCAML\_OTHER\_LIBS] Additional libraries passed to the linker, without suffix.  These
#    files do \emph{not} become dependencies of the target program.
# \item[OCAML\_CLIBS] C libraries to pass to the linker.
# \item[OCAML\_BYTE\_LINK\_FLAGS] Flags to pass to the bytecode linker.
# \item[OCAML\_NATIVE\_LINK\_FLAGS] Flags to pass to the native code linker.
# \item[OCAML\_LINK\_FLAGS] Flags to pass to both linkers.
# \end{description}
# \end{doc}
#
OCamlProgram(name, files) =
   CMOFILES  = $(addsuffix .cmo, $(files))
   CMXFILES  = $(addsuffix .cmx, $(files))
   OFILES    = $(addsuffix $(EXT_OBJ),   $(files))

   CMAFILES  = $(addsuffix .cma,  $(OCAML_LIBS))
   CMXAFILES = $(addsuffix .cmxa, $(OCAML_LIBS))
   ARFILES   = $(addsuffix $(EXT_LIB), $(OCAML_LIBS))
   CMA_OTHER_FILES = $(addsuffix .cma, $(OCAML_OTHER_LIBS))
   CMXA_OTHER_FILES = $(addsuffix .cmxa, $(OCAML_OTHER_LIBS))

   BYTE_CLIBS = $(addsuffix $(EXT_LIB), $(OCAML_CLIBS))
   NATIVE_CLIBS = $(addsuffix $(EXT_LIB), $(OCAML_CLIBS))
   CLIBS = $(addsuffix $(EXT_LIB), $(LIBS))

   PROG     = $(file $(name)$(EXE))
   BYTEPROG = $(file $(name).run)
   OPTPROG  = $(file $(name).opt)

   #
   # Rules to build byte-code and native targets
   #
   $(BYTEPROG): $(CMAFILES) $(CMOFILES) $(BYTE_CLIBS) $(CLIBS)
        $(OCAMLFIND) $(OCAMLLINK) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) $(OCAMLCFLAGS)\
                $(PREFIXED_OCAMLINCLUDES) $(OCAML_BYTE_LINK_FLAGS)\
                -o $@ $(CMA_OTHER_FILES) $(CMAFILES) $(OCamlLinkSort $(CMOFILES))\
                $(BYTE_CLIBS) $(CLIBS) $(OCAML_LINK_FLAGS)

   $(OPTPROG): $(CMXAFILES) $(ARFILES) $(CMXFILES) $(OFILES) $(NATIVE_CLIBS) $(CLIBS)
        $(OCAMLFIND) $(OCAMLOPTLINK) $(PREFIXED_OCAMLPACKS) $(OCAMLFLAGS) $(OCAMLOPTFLAGS)\
                $(PREFIXED_OCAMLINCLUDES) $(OCAML_NATIVE_LINK_FLAGS)\
                -o $@ $(CMXA_OTHER_FILES) $(CMXAFILES) $(OCamlLinkSort $(CMXFILES))\
                $(NATIVE_CLIBS) $(CLIBS) $(OCAML_LINK_FLAGS)

   #
   # Link the actual executables.
   # Always prefer native executables.
   #
   if $(NATIVE_ENABLED)
        $(PROG): $(OPTPROG)
            $(symlink $<, $@)
   else
        $(PROG): $(BYTEPROG)
            $(symlink $<, $@)

#
# Copy to $(BIN) directory
#
# \begin{doc}
# \subsection{OCamlProgramCopy}
#
# The \verb+OCamlProgramCopy+ function copies an OCaml program to an install location.
#
# \verb+OCamlProgramCopy(<tag>, <bindir>, <name>)+
#
# Additional variables used:
# \begin{description}
# \item[NATIVE\_ENABLED]  If \verb+NATIVE_ENABLED+ is set, the native-code executable
#    is copied; otherwise the byte-code executable is copied.
# \end{description}
# \end{doc}
#
OCamlProgramCopy(tag, bin, name) =
   BYTEPROG = $(file $(name).run)
   OPTPROG  = $(file $(name).opt)

   SRCNAME  = $(if $(NATIVE_ENABLED), $(OPTPROG), $(BYTEPROG))
   BINNAME  = $(file $(bin)/$(name)$(EXE))

   #
   # Link the actual executables.
   # Always prefer native executables.
   #
   $(BINNAME): $(SRCNAME)
      $(symlink $<, $@)

   # Add to phony tag.
   $(tag): $(BINNAME)

#
# We often use them together
#
# \begin{doc}
# \subsection{OCamlProgramInstall}
#
# The \verb+OCamlProgramInstall+ function builds a programs and copies it to
# an install location in one step.
#
# \verb+OCamlProgramInstall(<tag>, <bindir>, <name>, <files>)+
# \end{doc}
#
OCamlProgramInstall(tag, bin, name, files) =
    OCamlProgram($(name), $(files))
    OCamlProgramCopy($(tag), $(bin), $(name))

########################################################################
# LaTeX Section
#

#
# LaTeX config
#
# \begin{doc}
# \section{Building \LaTeX\ programs}
#
# \subsection{Configuration variables}
#
# The following variables can be modifed in your project.
# \begin{description}
# \item[LATEX] The \LaTeX\ command (default \verb+latex -interaction=errorstopmode+).
# \item[BIBTEX] The BibTeX command (default \verb+bibtex+).
# \item[MAKEINDEX] The command to build an index (default \verb+makeindex+).
# \item[DVIPS] The \verb+.dvi+ to PostScript converter (default \verb+dvips+).
# \item[DVIPDFM] The \verb+.dvi+ to \verb+.pdf+ converter (default \verb+dvipdfm+).
# \end{description}
# \end{doc}
#
LATEX = latex -interaction=errorstopmode
BIBTEX = bibtex
MAKEINDEX = makeindex
DVIPS = dvips
DVIPDFM = dvipdfm

#
# Dynamically defined list of files that the TeX source depends on.
#
TEXDEPS =

#
# Directories in the search path.
# Split them at colons to get a directory list.
#
TEXINPUTS = $(split :, $(getenv TEXINPUTS, .))

#
# Rules for building TeX documents.
#
# name: the name of the document
# texfiles: the TeX source files, without suffix
#
# Dynamic variables:
#    TEXINPUTS: extra directories to include in the search path
#    TEXDEPS: files that are implicitly included, including suffixes
#
# BUG: this only works on Unix for now
#
# \begin{doc}
# \subsection{LaTeXDocument}
#
# The \verb+LaTeXDocument+ produces a \LaTeX\ document.
#
# \verb+LaTeXDocument(<name>, <texfiles>)+
#
# The document \verb+<name>+ and \verb+<texfiles>+ are listed without suffixes.
#
# Additional variables used:
# \begin{description}
# \item[TEXINPUTS] The \LaTeX\ search path.
# \item[TEXDEPS] Additional files this document depends on.
# \end{description}
# \end{doc}
#
LaTeXDocument(name, texfiles) =
    #
    # TeX files all have the .tex suffix
    #
    TEXFILES = $(name).tex $(addsuffix .tex, $(texfiles))

    #
    # Setting the proper TEXINPUTS environment
    #
    TEXINPUTS = $(concat $(PATHSEP), $(TEXINPUTS)):
    TEXINPUTS_ENV = TEXINPUTS="$(TEXINPUTS)" BIBINPUTS="$(TEXINPUTS)"

    $(name).aux $(name).dvi $(name).log: $(TEXDEPS) $(TEXFILES)
        $(TEXINPUTS_ENV) $(LATEX) $(name)
        if $(grep q, $'\\citation', $(name).aux)
            $(TEXINPUTS_ENV) $(BIBTEX) $(name)
            $(TEXINPUTS_ENV) $(LATEX) $(name)
        if $(grep q, $'Label.s. may have changed', $(name).log)
            $(TEXINPUTS_ENV) $(LATEX) $(name)
        if $(grep q, $'Label.s. may have changed', $(name).log)
            $(TEXINPUTS_ENV) $(LATEX) $(name)
        if $(grep q, $'Label.s. may have changed', $(name).log)
            $(TEXINPUTS_ENV) $(LATEX) $(name)

    $(name).ind: $(name).aux
        $(TEXINPUTS_ENV) $(MAKEINDEX) $(name)

    $(name).pdf: $(name).dvi
        $(DVIPDFM) -p letter -o $@ $(name).dvi

    $(name).ps: $(name).dvi
        $(DVIPS) -t letter -o $@ $(name).dvi

#
# Copy the document to a library directory
#
# \begin{doc}
# \subsection{LaTeXDocumentCopy}
#
# The \verb+LaTeXDocumentCopy+ copies the document to an install location.
#
# \verb+LaTeXDocumentCopy(<tag>, <libdir>, <installname>, <docname>)+
#
# This function copies just the \verb+.pdf+ and \verb+.ps+ files.
# \end{doc}
#
LaTeXDocumentCopy(tag, lib, dst, src) =
    $(lib)/$(dst).pdf: $(src).pdf
        $(CP) $< $@

    $(lib)/$(dst).ps: $(src).ps
        $(CP) $< $@

    $(tag): $(lib)/$(dst).pdf $(lib)/$(dst).ps

#
# Build the document and copy it
#
# \begin{doc}
# \subsection{LaTeXDocumentInstall}
#
# The \verb+LaTeXDocumentInstall+ builds a document and copies it to an
# install location in one step.
#
# \verb+LaTeXDocumentInstall(<tag>, <libdir>, <installname>, <docname>, <files>)+
# \end{doc}
#
LaTeXDocumentInstall(tag, lib, dst, src, texfiles) =
    LaTeXDocument($(src), $(texfiles))
    LaTeXDocumentCopy($(tag), $(lib), $(dst), $(src))

########################################################################
# Define the command vars here
#
DefineCommandVars(.)

