Commits

james woodyatt committed cf44246

Create the oni-1.00 branch, which has the Conjury library integrated into
the source tree.

Comments (0)

Files changed (15)

.hgsub

-Conjury=https://bitbucket.org/jhw/conjury

.hgsubstate

-4c316f071fba5565bbbcf8c480f127551038a0b8 Conjury
-4c316f071fba5565bbbcf8c480f127551038a0b8 Conjury

Conjury/.hgignore

+# Mercurial file ignore patterns
+syntax: glob
+
+.svn
+*.output	# ocamlyacc grammar output files
+
+# OCaml object files
+*.cmo
+*.cmi
+*.cmx
+*.cma
+*.cmxa
+
+# Mach-O objects
+*.o
+*.a
+
+# OMake compiled module files
+*.omake
+
+# ignore directories
+SAVE
+
+# BBEdit projects
+*.bbproject
+*.orig	# editor backups
+
+syntax: regexp
+
+^\.omakedb$
+^\.omakedb\..*$
+\.DS_Store$

Conjury/Compiler.om

+##############################################################################
+# 
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Open library modules
+open Conjury/Stage
+
+### Abstract base class for compiler command drivers
+Compiler.=
+    class Compiler
+    
+    ###
+    # Abstract members:
+    #   this.DRIVER
+    #   this.add-component(component)
+    #   protected.scanner-digests(files)
+    #   protected.scanner-options(input, output)
+    #   protected.composer-options(input, output)
+    
+    ### Variables
+    OPTIONS=
+    DEPEND=
+    
+    ### Add a component to search paths (no operation in base class)
+    protected.add-component(c)=
+        return $(this)
+    
+    ### Rule to compose output file
+    protected.composer-rule(i, o)=
+        private.command=$(this.DRIVER) $(this.OPTIONS)
+        command+=$(this.composer-options $i, $o)
+        
+        $o: $(this.DEPEND) $i
+            $(command)
+    
+    ### Rule to compose output file
+    protected.effects-composer-rule(i, o, e)=
+        private.command=$(this.DRIVER) $(this.OPTIONS)
+        command+=$(this.composer-options $i, $o)
+        
+        $o $e: $(this.DEPEND) $i :effects: $o $e
+            $(command)
+    
+    ### Rule to scan input file for dependencies
+    protected.scanner-rule(i, o)=
+        private.id=$(file $o).scan
+        private.command=$(this.DRIVER) $(this.OPTIONS)
+        .SCANNER: $(id): $(this.DEPEND) $i :value: $(this.scanner-digests $&)
+            $(command) $(this.scanner-options $i, $o)
+        return $(id)
+    
+    ### Rule to compose output file with scanner
+    protected.scanning-composer-rule(i, o, s)=
+        private.command=$(this.DRIVER) $(this.OPTIONS)
+        command+=$(this.composer-options $i, $o)
+        
+        $o: $(this.DEPEND) $i :scanner: $s
+            $(command)
+    
+    ### Rule to compose output file with scanner
+    protected.scanning-effects-composer-rule(i, o, s, e)=
+        private.command=$(this.DRIVER) $(this.OPTIONS)
+        command+=$(this.composer-options $i, $o)
+        
+        $o: $(this.DEPEND) $i :scanner: $s :effects: $e
+            $(command)
+
+# End $File$

Conjury/Component.om

+##############################################################################
+# 
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Open library modules
+open Conjury/Stage
+
+### The base class for components
+Component.=
+    class Component
+    
+    ### Convert a relative name into an absolute name
+    private.mkname(name)=
+        if $(defined this.ABSNAME)
+            value $(ABSNAME)/$(name)
+        else
+            value $(name)
+    
+    ### Convert a relative name into a relative path
+    private.mkpath(name)=
+        private.n=$(split $"/", $(name))
+        n=$(addsuffix .work, $n)
+        return $(concat $"/", $n)
+    
+    ### Return the stage
+    protected.stage()=
+        if $(defined this.STAGE)
+            value $(this.STAGE)
+        else
+            value $(Stage)
+    
+    ### Exception
+    protected.throw(message)=
+        private.m=$(string $(message))
+        x.=
+            message=$"$m [ABSNAME=$(this.ABSNAME)]"
+        raise $x
+    
+    ### Assert that $c is an instance of Component in context $m
+    assert(c, m)=
+        if $(not $(c.instanceof Component))
+            throw($m)
+        return $c
+    
+    ### Construct a component object by referencing its name
+    ref(name)=
+        private.s=$(this.stage)
+        s.DIR=$(dir $(s.DIR)/$(mkpath $(name)))
+        this.ABSNAME=$(mkname $(name))
+        this.STAGE=$s
+        return $(this)
+    
+    ### Map a sequence of checkpoint names to their timestamp files
+    ck(checkpoints)=
+        return $(this.STAGE.ck $(checkpoints))
+    
+    ### Constructor
+    new(name)=
+        private.s=$(this.stage)
+        this.STAGE=$(s.push $(mkpath $(name)))
+        this.ABSNAME=$(mkname $(name))
+        STAGE.clean()
+        foreach(c, $(CONFIGURATIONS))
+            STAGE.push($c)
+        return $(this)
+
+# End $File$

Conjury/Environment.om

+##############################################################################
+# 
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Set the TOP directory
+TOP=$(dir .)
+
+### Default sort order
+.ORDER: .BUILDORDER
+
+### Standard phony targets
+.PHONY: clean
+
+### Scanner mode
+NOSCANNER=/.PHONY/__Scanner_dummy
+
+.SCANNER: $(NOSCANNER)
+    @
+
+### Private functions
+private.=
+    
+    ### The stage directory
+    stage=$(dir $(TOP)/stage)
+    
+    ### Decode parameters passed in OMAKEFLAGS
+    dequote(var)=
+        match $(getvar $(var))
+        case $'"\(.*\)"'
+            value $1
+        default
+            value $(getvar $(var))
+    
+    ### Unpack a directory
+    dir-unpack(var, subdir)=
+        var=$(uppercase $(var))
+        if $(defined $(var))
+            value $(dir $(dequote $(var)))
+        else
+            value $(dir $(stage)/$(lowercase $(subdir)))
+
+### Acquire the root directories
+AUXROOT=$(dir-unpack AUXROOT, aux)
+OBJROOT=$(dir-unpack OBJROOT, obj)
+FINROOT=$(dir-unpack FINROOT, fin)
+TOOLSDIR=$(dir-unpack TOOLSDIR, tools)
+
+### Set the configurations sequence
+CONFIGURATIONS=
+    if $(defined CONFIGURATIONS)
+        value $(set $(split $(dequote CONFIGURATIONS)))
+    else
+        x.message="No CONFIGURATIONS provided in environment!"
+        raise $x
+
+### Set the products sequence
+PRODUCTS=
+    if $(defined PRODUCTS)
+        value $(set $(split $(dequote PRODUCTS)))
+    else
+        value $(EMPTY)
+
+# End $File$

Conjury/OMakefile.template

+##############################################################################
+# 
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+# End $File$

Conjury/OMakeroot.template

+##############################################################################
+# 
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Required version of omake
+OMakeVersion(0.9.8.5, 0.9.8.5)
+
+### Define the command line variables
+DefineCommandVars()
+
+### Open the project library
+open Conjury/System
+
+### Define the project root directory
+public.SRCROOT= $(dir .)
+
+### Emphemeral targets
+.PHONY: clean test documents install remove
+
+### Include OMakefile from top directory
+.SUBDIRS: .
+
+# End $File$
+###############################################################################
+#
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Open library modules
+open Conjury/Environment
+
+### Base class for staging
+Stage.=
+    class Stage
+    
+    ### Initialize the stage from the object root
+    DIR=$(OBJROOT)
+    
+    ### Create a new stage from a path
+    new(path)=
+        this.DIR=$(dir $(path))
+        
+        $(DIR):
+            mkdir -p $@
+        
+        return $(this)
+    
+    ### Push a subdirectory onto STAGE
+    push(subdir) =
+        match $(subdir)
+        case $"^/.*"
+            eprintln(*** Stage.push: absolute path invalid! $(subdir))
+            exit(-1)
+        return $(this.new $(DIR)/$(subdir))
+    
+    ### Emit a localized clean rule
+    clean() =
+        clean::
+            rm -rf $(DIR)
+    
+    ### Returns the name of the file in the staging area
+    name(files) =
+        value $(file $(addprefix $(DIR)/, $(basename $(files))))
+    
+    ### Return the name of a checkpoint file in the staging area
+    ck(names) =
+        value $(file $(add-wrapper $(DIR)/, .ck, $(basename $(names))))
+    
+    ### Copy a list of files into the stage directory
+    ln-or-cp(src) =
+        foreach(f, $(src))
+            $(name $f): $(DIR) $f
+                rm -f $@
+                ln-or-cp $f $@
+        value $(name $(src))
+    
+    ### Copy a list of files into the stage directory
+    cp(src) =
+        foreach(f, $(src))
+            $(name $f): $(DIR) $f
+                rm -f $@
+                cp $f $@
+        value $(name $(src))
+    
+    ### Copy a list of files into the stage directory
+    install(src, rwx) =
+        foreach(f, $(src))
+            $(name $f): $(DIR) $f
+                rm -f $@
+                cp $f $@
+                chmod $(rwx) $@
+        value $(name $(src))
+    
+    ### Create a checkpoint file for a list of dependencies
+    checkpoint(ckname, depends) =
+        f=$(ck $(ckname))
+        $f: $(depends) $(DIR)
+            date > $@
+        return $f
+    
+### Assert that $c is an instance of Stage in context $m
+AssertStage(s, m)=
+    if $(not $(s.instanceof Stage))
+        x.=
+            message= $"Stage object required [$m]"
+        raise $x
+    return $s
+
+### End $File$

Conjury/System.om

+##############################################################################
+# 
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Open all the library modules
+open Conjury/Environment
+open Conjury/Stage
+open Conjury/Component
+open Conjury/Unit
+open Conjury/Compiler
+
+open Conjury/lang/C
+open Conjury/lang/OCaml
+
+### Rules to insure the construction of the root directories
+private.v=
+foreach (v, AUXROOT OBJROOT FINROOT TOOLSDIR)
+    $(getvar $v):
+        mkdir -p $@
+
+# End $File$
+##############################################################################
+# 
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Open library modules
+open Conjury/Component
+
+### The base class for composition units
+Unit.=
+    class Unit
+    
+    ### Exception
+    protected.throw(message)=
+        exception.=
+            message=$"$(message) [NAME=$(this.NAME)]"
+        raise $(exception)
+    
+    ### Normalize the source description
+    protected.source(src, context)=
+        if $(not $(src.NAME))
+            x.=
+                message= $"Unit.source is anonymous in $(context)"
+            raise $x
+        this.NAME=$(src.NAME)
+        this.COMPONENTS[]=
+        if $(src.object-mem COMPONENTS)
+            private.cs=$(src.COMPONENTS)
+            foreach(c, $(cs))
+                Component.assert($c, $(context))
+            this.COMPONENTS=$(cs)
+            export
+        return $(this)
+
+# End $File$

Conjury/environ.sh

+#!/bin/sh
+
+###############################################################################
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+#
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+this=${0##*/}
+
+usage() {
+    if [ -n "$*" ]; then
+        echo ''
+        echo "${this}: $*"
+    fi
+    cat 1>&2 <<_usage_
+
+Usage:
+    ${this} -h
+    ${this} -[m] [-S ...] [-T ...] [-O ...] [-F ...] [-c ...] products...
+
+  Options:
+    -h          Print this message.
+    -m          Edit search paths to include the tools directories.
+    -d          Do not build release configuration
+    -a          Build all products
+    -c config   Add <config> to the alternative configurations to build
+    -S stage    Specify explicit stage directory (default is \$PWD/stage).
+    -O objects  Specify objects directory (default is \$stage/obj).
+    -T tools    Specify tools directory (default is \$stage/tools, implies -m).
+    -F finish   Specify finishing directory (default is \$stage/fin).
+    -A aux      Specify auxillary directory (default is \$stage/aux).
+    
+    Note: -d requires at least one -c <config> argument.
+_usage_
+
+    exit 1
+}
+
+top=$(cd $(dirname $0)/.. && pwd)
+
+uname=$(uname)
+if [ $uname = Darwin ]; then
+    njobs=$(($(/usr/sbin/sysctl -n hw.ncpu) * 3 / 2))
+    if [ $njobs -lt 2 ]; then njobs=2; fi
+else
+    njobs=2
+fi
+
+# INCOMPLETE! We should remove the results of previous edits before inserting
+# new values.
+
+OMAKEFLAGS=${OMAKEFLAGS:+"${OMAKEFLAGS} "}
+OMAKEFLAGS+="-j$njobs --force-dotomake --dotomake ${top}/.omake"
+
+edit_paths=false
+release_config="release"
+opts='A:F:O:S:T:ac:dhm'
+allproducts=false
+while getopts ${opts} opt; do
+    case ${opt} in
+      A)
+        eval ':'
+        AUXROOT=${OPTARG}
+        ;;
+      F)
+        eval ':'
+        FINROOT=${OPTARG}
+        ;;
+      S)
+        eval ':'
+        stage=${OPTARG}
+        ;;
+      O)
+        eval ':'
+        OBJROOT=${OPTARG}
+        ;;
+      T)
+        eval ':'
+        tools=${OPTARG}
+        edit_paths=true
+        ;;
+      a)
+        allproducts=true
+        ;;
+      c)
+        eval ':'
+        [ -n "${configs}" ] && configs+=' '
+        configs+="${OPTARG}"
+        ;;
+      d)
+        release_config=
+        ;;
+      m)
+        edit_paths=true
+        ;;
+      '?'|h)
+        usage
+        ;;
+    esac
+done
+
+shift $((${OPTIND} -1))
+
+stage=${stage:="$PWD/stage"}
+OMAKEFLAGS+=" OBJROOT=\\\"${OBJROOT:="$stage/obj"}\\\""
+OMAKEFLAGS+=" FINROOT=\\\"${FINROOT:="$stage/fin"}\\\""
+OMAKEFLAGS+=" AUXROOT=\\\"${AUXROOT:="$stage/aux"}\\\""
+
+if [ -n "${release_config}" ]; then
+    [ -n "${configs}" ] && release_config+=' '
+    configs=${release_config}${configs}
+fi
+
+[ "${configs}" = '' ] && usage
+
+OMAKEFLAGS+=" CONFIGURATIONS=\\\"${configs}\\\""
+
+if ${allproducts}; then
+    products=
+    for pfile in ${top}/products/*.om; do
+        if [ -r ${pfile} ]; then
+            products+=$(basename -s .om ${pfile})
+        fi
+    done
+elif [ $# -gt 0 ]; then
+    products=$*
+    for p in ${products}; do
+        pfile=${top}/products/${p}.om
+        if [ ! -r ${pfile} ]; then
+            cat 1>&2 <<_no_product_
+$0: Error: unable to read ${pfile}
+_no_product_
+
+                exit 1
+        fi
+    done
+fi
+
+if [ -n "${products}" ]; then
+    OMAKEFLAGS+=" PRODUCTS=\\\"$products\\\""
+fi
+
+if ${edit_paths}; then
+    toolsdir=${tools:="$stage/tools"}
+    OMAKEFLAGS+=" TOOLSDIR=\\\"$toolsdir\\\""
+    if [ $uname = Darwin ]; then
+        echo "DYLD_LIBRARY_PATH=\"$toolsdir/usr/lib\":$DYLD_LIBRARY_PATH"
+    else
+        echo "LD_LIBRARY_PATH=\"$toolsdir/usr/lib\":$LD_LIBRARY_PATH"
+    fi
+    echo "MANPATH=\"$toolsdir/usr/man\":$MANPATH"
+    echo "PATH=\"$toolsdir/usr/bin\":\"$toolsdir/usr/local/bin\":$PATH"
+fi
+
+echo "OMAKEFLAGS=\"${OMAKEFLAGS}\"; export OMAKEFLAGS"
+exit 0
+
+# End $File$

Conjury/install.sh

+#!/bin/sh
+
+###############################################################################
+# $Change$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+#
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+this=${0##*/}
+
+subdir=$(cd $(dirname $0) && pwd)
+
+if [ "$(basename ${subdir})" != "Conjury" ]; then
+  echo "ERROR: ${this} requires subrepository to be named 'Conjury' at root."
+  exit -1
+fi
+
+cd ${subdir}/..
+
+if [ ! -d .hg ]; then
+  hg init .
+  
+  echo 'Conjury= http://bitbucket/jhw/conjury' > .hgsub
+  hg add .hgsub
+  
+  cp Conjury/.hgignore .hgignore
+  hg add .hgignore
+fi
+
+if [ ! -f OMakeroot ]; then
+  cp Conjury/OMakeroot.template OMakeroot
+  hg add OMakeroot
+fi
+
+if [ ! -f OMakefile ]; then
+  cp Conjury/OMakefile.template OMakefile
+  hg add OMakefile
+fi
+
+exit 0
+
+# End $File$

Conjury/lang/C.om

+##############################################################################
+# 
+# $File$
+# Copyright (C) 2010, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Open library modules
+open Conjury/Environment
+open Conjury/Compiler
+open Conjury/Stage
+open Conjury/Component
+open Conjury/Unit
+
+### The base class for C language compilers
+C_compiler.=
+    class C_compiler
+    extends $(Compiler)
+    
+    ### Initialize the tools stage
+    section
+        tools=$(Stage.new $(TOOLSDIR))
+        tools.push(usr/include)
+        tools.push(usr/lib)
+    
+    ### Variables
+    CPPFLAGS=
+    OBJFLAGS=
+    LDFLAGS=
+    EXTENSION=.o
+    INCLUDE[]=
+        $(TOOLSDIR)/usr/include
+    LDSEARCH[]=
+        $(TOOLSDIR)/usr/lib
+    DEPEND=$(INCLUDE) $(LDSEARCH)
+    
+    ### The verbose flag
+    verbose-flag()=
+        return $(if $(VERBOSE), -v, $(EMPTY))
+    
+    ### Include search options
+    protected.include-search()=
+        return $(addprefix -I, $(INCLUDE))
+    
+    ### Linker search options
+    protected.library-search()=
+        return $(addprefix -L, $(LDSEARCH))
+    
+    ### Search for digests
+    protected.scanner-digests(files)=
+        return $(digest-in-path-optional $(INCLUDE), $(files))
+    
+    ### Replace suffix with object file extension
+    protected.replace-extension(files)=
+        return $(addsuffix $(EXTENSION), $(removesuffix $(files)))
+    
+    ### Scanner rule command driver options
+    protected.scanner-options(src, obj)=
+        return $(CPPFLAGS) $(include-search) -MM -MT $(obj) $(src)
+    
+    ### Composer rule command driver options for compiling objects
+    protected.obj-composer-options(src, obj)=
+        return $(CPPFLAGS) $(OBJFLAGS) $(include-search) -o $(obj) -c $(src)
+    
+    ### Composer rule command driver options for linking products
+    protected.link-composer-options(src, libs, obj)=
+        libs=$(addprefix -l, $(libs))
+        return $(LDFLAGS) $(library-search) $(libs) -o $(obj) $(src)
+    
+    ### Compose object files in staging directory
+    objects(srcfiles, dst)=
+        srcfiles=$(file $(srcfiles))
+        dst=$(dir $(dst))
+        DEPEND+=$(dst)
+        this.composer-options(src, obj)=
+            return $(obj-composer-options $(src), $(obj))
+        private.obj=
+            foreach(i, $(srcfiles))
+                o= $(basename $(addsuffix $(EXTENSION), $(removesuffix $i)))
+                o= $(file $(addprefix $(dst)/, $o))
+                scanning-composer-rule($i, $o, $(scanner-rule $i, $o))
+                value $o
+        return $(obj)
+    
+    ### Compose linker product in staging directory
+    executable(program, objfiles, libs, dst)=
+        private.inputs=$(file $(objfiles))
+        dst=$(dir $(dst))
+        program=$(file $(dst)/$(program))
+        this.composer-options(src, obj)=
+            return $(link-composer-options $(src), $(libs), $(obj))
+        composer-rule($(inputs), $(program))
+        return $(program)
+
+### The C/C++ compiler
+CC.=
+    extends $(C_compiler)
+    DRIVER=cc
+
+### The static archiver
+AR.=
+    extends $(Compiler)
+    
+    ### The default command driver is ar
+    DRIVER=ar
+    
+    ### Compose static archive in staging directory
+    archive(afile, objfiles, dst)=
+        objfiles=$(file $(objfiles))
+        dst=$(dir $(dst))
+        afile=$(file $(dst)/$(afile))
+        $(afile): $(objfiles) $(DEPEND)
+            rm -f $@
+            $(DRIVER) $(OPTIONS) -q -cs $@ $(objfiles)
+        return $(afile)
+
+### Component for staging C/C++ language compositions
+C_component.=
+    class C_component
+    extends $(Component)
+    
+    ### Assert that $c is an instance of C_component in context $m
+    assert(c, m)=
+        if $(not $(c.instanceof C_component))
+            m=$(string $m)
+            x.=
+                message=$"C_component object required [$m]"
+            raise $x
+        return $c
+    
+    ### Construct a new component object and write substaging rules
+    new(name)=
+        this=$(Component::new $(name))
+        STAGE.checkpoint(headers, $(EMPTY))
+        private.hstage=$(STAGE.push include)
+        foreach (config, $(CONFIGURATIONS))
+            private.cstage=$(STAGE.push $(config))
+            cstage.checkpoint(libraries, $(STAGE.ck headers))
+            cstage.checkpoint(programs, $(cstage.ck libraries))
+            
+            .DEFAULT: $(cstage.ck programs)
+            
+        return $(this)
+    
+    ### Return the common header stage for all configurations
+    stage-include()=
+        private.s=$(this.STAGE)
+        s.DIR=$(dir $(this.STAGE.DIR)/include)
+        return $s
+    
+    ### Return the library stage for a named configuration
+    stage-config(config)=
+        private.s=$(this.STAGE)
+        s.DIR=$(dir $(this.STAGE.DIR)/$(config))
+        return $s
+
+### Base class for C language composition units
+C_unit.=
+    class C_unit
+    extends $(Unit)
+    
+    ### Normalize the source description
+    protected.source(src, context)=
+        this=$(Unit::source $(src), $(context))
+        if $(not $(src.CFILES))
+            throw($"C unit has no CFILES member [$(context)]")
+        this.CFILES=$(file $(src.CFILES))
+        return $(this)
+    
+    ### Configure a compiler object
+    protected.configure(cfg)=
+        private.cc=$(this.CC)
+        export cc
+        match $(cfg)
+        case $"debug"
+            cc.OBJFLAGS+=-g -Wall -Werror
+        case $"release"
+            cc.OBJFLAGS+=-O3 -Wall
+            cc.CPPFLAGS+=-DNDEBUG
+        this.CC=$(cc)
+        return $(this)
+    
+    ### Construct a new composer
+    protected.new(name, src, context)=
+        src.NAME=$(name)
+        this=$(source $(src), $(context))
+        return $(this)
+    
+    ### Auxiliary composition method
+    protected.compose-visit-config(cmp, cfg)=
+        private.s=$(cmp.stage-config $(cfg))
+        return $(this.CC.objects $(this.CFILES), $(s.DIR))
+    
+    ### Compose (FIX ME: should be in base class)
+    protected.compose(cmp)=
+        private.outputs=
+        export outputs
+        foreach(cfg, $(this.CONFIGURATIONS))
+            this=$(this.configure $(cfg))
+            outputs+=$(this.compose-visit-config $(cmp), $(cfg))
+        return $(outputs)
+
+### C library composition units
+C_library.=
+    class C_library
+    extends $(C_unit)
+    
+    ### Normalize the source description
+    protected.source(src, context)=
+        this=$(C_unit::source $(src), $(context))
+        this.HPREFIX=$(src.HPREFIX)
+        this.HFILES=$(if $(src.HFILES), $(file $(src.HFILES)), $(EMPTY))
+        return $(this)
+    
+    ### Compose a library
+    compose(cmp)=
+        private.ckinclude=$(cmp.STAGE.ck headers)
+        private.s=$(cmp.stage-include)
+        if $(this.HPREFIX)
+            s=$(s.push $(this.HPREFIX))
+            export s
+        
+        private.outputs=$(s.ln-or-cp $(this.HFILES))
+        
+        $(ckinclude): $(outputs)
+        
+        this.CC.DEPEND+=$(ckinclude)
+        return $(C_unit::compose $(cmp))
+
+### C static library units
+C_static_library.=
+    class C_static_library
+    extends $(C_library)
+    
+    ### Derived auxiliary composition method
+    protected.compose-visit-config(cmp, cfg)=
+        private.objs=$(C_unit::compose-visit-config $(cmp), $(cfg))
+        private.dst=$(cmp.stage-config $(cfg))
+        private.out=$(AR.archive $(this.LIBNAME), $(objs), $(dst.DIR))
+        
+        $(dst.ck libraries): $(out)
+        
+        return $(out)
+    
+    ### Construct a new composer
+    new(name, src)=
+        this=$(C_library::new $(name), $(src), C_static_library.new)
+        this.LIBNAME=$"lib$(this.NAME).a"
+        return $(this)
+
+### C executable program composition units
+C_executable.=
+    class C_executable
+    extends $(C_unit)
+    
+    ### Normalize the source description
+    protected.source(src, context)=
+        this=$(C_unit::source $(src), $(context))
+        private.libs[]=
+        if $(src.object-mem LIBS)
+            libs=$(src.LIBS)
+            export libs
+        this.LIBS=$(libs)
+        return $(this)
+    
+    ### Derived auxiliary composition method
+    protected.compose-visit-config(cmp, cfg)=
+        private.objs=$(C_unit::compose-visit-config $(cmp), $(cfg))
+        private.dst=$(cmp.stage-config $(cfg))
+        private.out= \
+          $(CC.executable $(this.NAME), $(objs), $(this.LIBS), $(dst.DIR))
+        
+        $(dst.ck programs): $(out)
+        
+        return $(out)
+    
+    ### Construct a new composer
+    new(name, src)=
+        return $(C_unit::new $(name), $(src), C_executable.new)
+
+### C executable test program composition units
+C_test_program.=
+    class C_test_program
+    extends $(C_executable)
+    
+    ### Derived auxiliary composition method
+    protected.compose-visit-config(cmp, cfg)=
+        private.prog=$(C_executable::compose-visit-config $(cmp), $(cfg))
+        
+        test: $(prog)
+            $(prog) -verbose
+        
+        return $(out)
+
+# End $Change$

Conjury/lang/OCaml.om

+##############################################################################
+# 
+# $Change$
+# Copyright (C) 2009, james woodyatt
+# All rights reserved.
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 
+#   Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+#   
+#   Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in
+#   the documentation and/or other materials provided with the
+#   distribution
+# 
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+# OF THE POSSIBILITY OF SUCH DAMAGE. 
+
+### Open library modules
+open Conjury/Environment
+open Conjury/Compiler
+open Conjury/Stage
+open Conjury/Component
+open Conjury/Unit
+
+### Select the appropriate OCaml compiler driver
+private.SelectDriver(name)=
+    optname=$"$(name).opt"
+    if $(where $(optname))
+        return $(optname)
+    elseif $(where $(name))
+        return $(name)
+    else
+        eprintln(*** Error: neither $(name) nor $(optname) in PATH)
+        exit(-1)
+
+### Installed drivers
+static.=
+    USE.=
+        ocamldep=$(SelectDriver ocamldep)
+        ocamlc=$(SelectDriver ocamlc)
+        ocamlopt=$(SelectDriver ocamlopt)
+        ocamldoc=$(SelectDriver ocamldoc)
+
+### The Objective Caml native/byte-code compilers
+OCaml_compiler.=
+    class OCaml_compiler
+    extends $(Compiler)
+    
+    ### Initialize the tools stage
+    section
+        tools=$(Stage.new $(TOOLSDIR))
+        tools.push(usr/lib/ocaml)
+    
+    ### Variables
+    SEARCH[]=
+        $(TOOLSDIR)/usr/lib/ocaml
+    PACKAGES[]=
+    PREDICATES[]=
+    CFLAGS=-fPIC -Wall
+    SUPPORT[]=
+    DEPEND=$(SEARCH)
+    
+    ### The verbose flag
+    verbose-flag()=
+        return $(if $(VERBOSE), -verbose, $(EMPTY))
+    
+    ### Dependency scanner command driver
+    protected.cmd-driver(cmd)=
+        private.driver=$(getvar USE.$(cmd))
+        export driver
+        if $(PACKAGES)
+            driver=ocamlfind $(cmd)
+            driver+= -package $(concat $",", $(PACKAGES))
+            if $(PREDICATES)
+                driver+= -predicate $(concat $",", $(PREDICATES))
+        return $(driver)
+    
+    ### Map the -ccopt flag to the CFLAGS variable
+    protected.ccopt-flags()=
+        return $(mapprefix -ccopt, $(CFLAGS))
+    
+    ### Include compiler search options
+    protected.include-search()=
+        return $(mapprefix -I, $(SEARCH))
+    
+    ### Include C linker search options
+    protected.support-library-search()=
+        private.path=$(SEARCH)
+        path=$(addprefix -L, $(path))
+        path=$(mapprefix -cclib, $(path))
+        return $(path)
+    
+    ### Reference the C language support libraries
+    protected.support-libraries()=
+        private.path=$(SUPPORT)
+        path=$(addprefix -l, $(path))
+        path=$(mapprefix -cclib, $(path))
+        return $(path)
+    
+    ### Scanner digests
+    protected.scanner-digests(files)=
+        return $(digest-in-path-optional $(SEARCH), $(files))
+    
+    ### Composer rule command driver options for scanning objects
+    protected.ocaml-scanner-options(src, obj)=
+        return $(include-search) $(src)
+    
+    ### Scanner rule command driver options
+    protected.primitive-scanner-options(src, obj)=
+        return $(include-search) -c -ccopt -MM -ccopt -MT -ccopt $(obj) $(src)
+    
+    ### Composer rule command driver options for compiling objects
+    protected.composer-options(src, obj)=
+        return $(include-search) -o $(obj) -c $(src)
+    
+    ### Scanner output edit line
+    protected.ocaml-scanner-fprint1(fp, d, line)=
+        foreach(j, $(split $(line)))
+            if $(equal $j, \\)
+                fprint($(fp), $(EMPTY))
+            elseif $(equal $j, $(basename $j))
+                export j
+                match $j
+                case $"\.cmi"
+                    if $(this.object-mem CMIDIR)
+                        j=$(addprefix $(CMIDIR)/, $j)
+                    else
+                        j=$(addprefix $d/, $j)
+                default
+                    j=$(addprefix $d/, $j)
+                fprint($(fp), $" $j")
+            else
+                fprint($(fp), $" $j")
+    
+    ### Scanner output
+    protected.ocaml-scanner-fprint(fp, o, lines)=
+        private.d=$(dirname $o)
+        private.o=$(basename $o)
+        start=
+        foreach(line, $(lines))
+            match $(line)
+            case $"^ +\(.*\)"
+                private.text=$1
+                if $(equal $o, $(start))
+                    ocaml-scanner-fprint1($(fp), $d, $(text))
+            case $"^\([^:]+\): \(.*\)"
+                private.text=$2
+                start=$1
+                start=$(basename $(start))
+                if $(equal $(start), $o)
+                    print($"$d/$o: ")
+                    ocaml-scanner-fprint1($(fp), $d, $(text))
+                export
+            default
+                x.=
+                    message=$"unmatched ocamldep output $(line)"
+                raise $x
+            export
+        fprintln($(fp), $" ")
+    
+    ### Scanner output to stdout
+    protected.ocaml-scanner-print(o, lines)=
+        ocaml-scanner-fprint($(stdout), $o, $(lines))
+    
+    ### Specialized rule to scan input file for dependencies
+    protected.ocaml-scanner-rule(i, o)=
+        private.id=$(file $o).scan
+        private.drv=$(this.cmd-driver ocamldep)
+        private.command=$(drv) $(ocaml-scanner-options $i, $o)
+        
+        .SCANNER: $(id): $(DEPEND) $i :value: $(this.scanner-digests $&)
+            ocaml-scanner-print($o, $(shella $(command)))
+        
+        return $(id)
+    
+    ### Specialized rule to scan primitive file for dependencies
+    protected.primitive-scanner-rule(i, o)=
+        private.id=$(file $o).scan
+        
+        .SCANNER: $(id): $(DEPEND) $i :value: $(this.scanner-digests $&)
+            $(this.DRIVER) $(primitive-scanner-options $i, $o)
+        
+        return $(id)
+    
+    ### Compose a single source interface file in staging directory
+    mli-file(ml, dst)=
+        src=$(file $(ml))
+        dst=$(dir $(dst))
+        this.DEPEND+=$(dst)
+        private.mli=$(replacesuffixes .ml, .mli, $(ml))
+        if $(test -f $(mli))
+            return $(mli)
+        else
+            mli=$(file $(addprefix $(dst)/, $(basename $(mli))))
+            composer-rule($(ml), $(mli))
+            return $(mli)
+    
+    ### Compose a single compiled interface file in staging directory
+    cmi-file(mli, dst)=
+        src=$(file $(mli))
+        dst=$(dir $(dst))
+        this.DEPEND+=$(dst)
+        cmi=$(replacesuffixes .mli, .cmi, $(basename $(mli)))
+        cmi=$(file $(addprefix $(dst)/, $(cmi)))
+        scan=$(ocaml-scanner-rule $(mli), $(cmi))
+        scanning-composer-rule($(mli), $(cmi), $(scan))
+        return $(cmi)
+    
+    ### Compose C-language primitive objects
+    c-primitives(srcfiles, dst)=
+        srcfiles=$(file $(srcfiles))
+        dst=$(dir $(dst))
+        this.DEPEND+=$(dst)
+        obj=
+        export obj
+        foreach(i, $(srcfiles))
+            private.o=$(replacesuffixes .c, .o, $(basename $i))
+            o=$(file $(addprefix $(dst)/, $o))
+            s=$(primitive-scanner-rule $i, $o)
+            this.CFLAGS+=-o $o
+            this.OPTIONS+=$(ccopt-flags)
+            scanning-composer-rule($i, $o, $s)
+            obj+= $o
+        return $(obj)
+    
+    ### Compose executable program in staging directory
+    program(name, config, modules, dst)=
+        modules=$(file $(modules))
+        dst=$(dir $(dst))
+        program=$(file $(dst)/$(name))
+        this.DEPEND+=$(dst)
+        if $(PACKAGES)
+            this.OPTIONS+=-linkpkg
+            export
+        this.composer-options(src, obj)=
+            private.opts=$(include-search) $(support-library-search)
+            private.libs=$(support-libraries)
+            return $(opts) -o $(obj) $(src) $(libs)
+        composer-rule($(modules), $(program))
+        return $(program)
+
+### The OCaml byte compiler
+OCAMLC.=
+    class OCaml_byte_compiler
+    extends $(OCaml_compiler)
+    
+    ### Driver
+    DRIVER()=
+        return $(cmd-driver ocamlc)
+    
+    ### Compose a byte compiled module file in staging directory
+    cmo-file(ml, dst)=
+        this.composer-options(src, obj)=
+            return $(include-search) -o $(filter %.cmo, $(obj)) -c $(src)
+        ml=$(file $(ml))
+        private.mli=$(file $(replacesuffixes .ml, .mli, $(ml)))
+        this.DEPEND+=$(dst)
+        private.cmo=$(replacesuffixes .ml, .cmo, $(basename $(ml)))
+        cmo=$(file $(addprefix $(dst)/, $(cmo)))
+        private.cmi=$(file $(replacesuffixes .cmo, .cmi, $(cmo)))
+        private.scan=$(ocaml-scanner-rule $(ml), $(cmo))
+        if $(target-is-proper $(cmi))
+            scanning-composer-rule($(ml), $(cmo), $(scan))
+        else
+            scanning-composer-rule($(ml), $(cmo) $(cmi), $(scan))
+        return $(cmo)
+    
+    ### Compose native compiled library file in staging directory
+    bytecode-library(name, cmofiles, dst)=
+        this.composer-options(src, obj)=
+            return -a $(include-search) $(verbose-flag) -o $(obj) $(src)
+        dst=$(dir $(dst))
+        this.DEPEND+=$(dst)
+        private.cma=$(file $(dst)/$(name).cma)
+        composer-rule($(cmofiles), $(cma))
+        return $(cma)
+
+### The OCaml native compiler
+OCAMLOPT.=
+    class OCaml_native_compiler
+    extends $(OCaml_compiler)
+    
+    ### Driver
+    DRIVER()=
+        return $(cmd-driver ocamlopt)
+    
+    ### Compose a byte compiled module file in staging directory
+    cmx-file(ml, dst)=
+        this.composer-options(src, obj)=
+            return $(include-search) -o $(filter %.cmx, $(obj)) -c $(src)
+        ml=$(file $(ml))
+        this.DEPEND+=$(dst)
+        private.cmx=$(replacesuffixes .ml, .cmx, $(basename $(ml)))
+        cmx=$(file $(addprefix $(dst)/, $(cmx)))
+        private.scan=$(ocaml-scanner-rule $(ml), $(cmx))
+        private.obj=$(file $(replacesuffixes .cmx, .o, $(cmx)))
+        scanning-composer-rule($(ml), $(cmx) $(obj), $(scan))
+        return $(cmx)
+    
+    ### Compose native compiled library file in staging directory
+    native-library(name, src, dst)=
+        this.composer-options(src, obj)=
+            src=$(filter %.cmx, $(src))
+            obj=$(filter %.cmxa, $(obj))
+            return -a $(include-search) $(verbose-flag) -o $(obj) $(src)
+        dst=$(dir $(dst))
+        this.DEPEND+=$(dst)
+        private.cmxa=$(file $(dst)/$(name).cmxa)
+        private.a=$(file $(dst)/$(name).a)
+        private.ofiles=$(file $(replacesuffixes .cmx, .o, $(src)))
+        composer-rule($(src) $(ofiles), $(cmxa) $a)
+        return $(cmxa) $a
+
+### The OCaml lexical analyzer generator
+OCAMLLEX.=
+    extends $(Compiler)
+    
+    ### Driver
+    DRIVER=ocamllex
+    
+    ### The verbose flag
+    protected.verbose-flag()=
+        return $(if $(VERBOSE), $(EMPTY), -q)
+    
+    ### The composer options
+    protected.composer-options(i, o)=
+        return $(verbose-flag) -o $o $i
+    
+    ### Module file
+    generate(src, dst)=
+        src=$(file $(src))
+        dst=$(dir $(dst))
+        this.DEPEND+=$(dst)
+        private.ml=$(replacesuffixes .mll, .ml, $(basename $(src)))
+        ml=$(file $(addprefix $(dst)/, $(ml)))
+        composer-rule($(src), $(ml))
+        return $(ml)
+
+### The OCaml grammar parser generator
+OCAMLYACC.=
+    extends $(Compiler)
+    
+    ### Driver
+    DRIVER=ocamlyacc
+    
+    ### The verbose flag
+    protected.verbose-flag()=
+        return $(if $(VERBOSE), -v, $(EMPTY))
+    
+    ### The composer options
+    protected.composer-options(i, o)=
+        #private.prefix=$(removesuffix $o)
+        return $(verbose-flag) -b $o $i
+    
+    ### Locate generated source file
+    prefix(srcfile, dst)=
+        return $(addprefix $(dst)/, $(basename $(removesuffix $(srcfile))))
+    
+    ### Module file
+    generate(src, dst)=
+        src=$(file $(src))
+        dst=$(dir $(dst))
+        private.p=$(this.prefix $(src), $(dst))
+        this.composer-options(i, o)=
+            return $(verbose-flag) -b $p $i
+        this.DEPEND+=$(dst)
+        private.ml=$(file $(addsuffix .ml, $p))
+        private.mli=$(file $(replacesuffixes .ml, .mli, $(ml)))
+        composer-rule($(src), $(ml) $(mli))
+        return $(ml)
+
+### The OCaml library compiler driver
+OCAMLMKLIB.=
+    extends $(Compiler)
+    
+    ### Driver
+    DRIVER=ocamlmklib
+    SEARCH[]=
+        $(TOOLSDIR)/usr/lib/ocaml
+    SUPPORT[]=
+    
+    ### The verbose flag
+    protected.verbose-flag()=
+        return $(if $(VERBOSE), -verbose, $(EMPTY))
+    
+    ### Linker search options
+    protected.library-search()=
+        return $(addprefix -L, $(SEARCH))
+    
+    ### Linker reference options
+    protected.library-ref()=
+        return $(addprefix -l, $(SUPPORT))
+    
+    ### Composer options
+    protected.mklib-composer-options(i, o)=
+        return $(verbose-flag) -o $o $(library-search) $(library-ref) $i
+        
+    ### Composer rule
+    protected.mklib-composer-rule(name, outputs, inputs, dst)=
+        private.command=$(this.DRIVER) $(OPTIONS)
+        private.inputs=$(file $(inputs))
+        private.outputs=$(file $(addprefix $(dst)/, $(outputs)))
+        
+        $(outputs): $(inputs) $(this.DEPEND)
+            section
+                cd $(dst)
+                $(command) $(mklib-composer-options $(inputs), $(name))
+        
+        return $(outputs)
+    
+    ### Invoke ocamlmklib to make C libraries
+    c-library(name, ofiles, dst)=
+        private.libs=lib$(name).a dll$(name).so
+        return $(mklib-composer-rule $(name), $(libs), $(ofiles), $(dst))
+    
+    ### Invoke ocamlmklib to make bytecode libraries
+    bytecode-library(name, cmofiles, dst)=
+        private.libs=$(name).cma
+        return $(mklib-composer-rule $(name), $(libs), $(cmofiles), $(dst))
+    
+    ### Invoke ocamlmklib to make native libraries
+    native-library(name, cmxfiles, dst)=
+        private.libs=$(name).cmxa $(name).a
+        return $(mklib-composer-rule $(name), $(libs), $(cmxfiles), $(dst))
+
+### The OCaml document generator
+OCAMLDOC.=
+    extends $(OCaml_compiler)
+    
+    ### Driver
+    DRIVER()=
+        return $(cmd-driver ocamldoc)
+    
+    ### The verbose flag
+    verbose-flag()=
+        return $(if $(VERBOSE), -v, $(EMPTY))
+    
+    ### Composer options
+    protected.composer-options(src, index)=
+        private.opts=-html -colorize-code -short-functors
+        private.opts+=$(verbose-flag) $(include-search)
+        return $(opts) -d $(dirname $(index)) $(src)
+    
+    ### Generate HTML documents
+    html-documents(srcfiles, dst)=
+        private.index=$(file $(dst)/index.html)
+        private.mlifiles=$(filter %.mli, $(srcfiles))
+        composer-rule($(mlifiles), $(index))
+        return $(index)
+
+### Component for staging OCaml language compositions
+OCaml_component.=
+    class OCaml_component
+    extends $(Component)
+    
+    ### Assert that $c is an instance of OCaml_component in context $m
+    assert(c, m)=
+        if $(not $(c.instanceof OCaml_component))
+            m=$(string $m)
+            x.=
+                message=$"OCaml_component object required [$m]"
+            raise $x
+        return $c
+    
+    ### Construct a new component object
+    new(name)=
+        this=$(Component::new $(name))
+        private.=
+            cklib=$(STAGE.checkpoint libraries, $(EMPTY))
+            ckbin=$(STAGE.checkpoint programs, $(EMPTY))
+        .DEFAULT: $(cklib) $(ckbin)
+        return $(this)
+    
+    ### Return a structure describing a library
+    library-referers(name)=
+        r.=
+            class OCaml_library_referral
+            cma(config)=
+                return $(file $(STAGE.DIR)/$(config)/$(name).cma)
+            cmxa(config)=
+                return $(file $(STAGE.DIR)/$(config)/$(name).cmxa)
+        return $r
+    
+    ### Add component to document search path for package
+    package-search(p)=
+        p.DOCSEARCH+=$(this.STAGE.DIR)
+        return $p
+
+### Class of objects that refer to an OCaml library in a component
+OCaml_library_referral.=
+    class OCaml_library_referral
+    
+    ### Configuration-specific location
+    protected.location(config)=
+        private.d=$(this.DIR)
+        d=$(if $(this.UNCONFIG), $d, $d/$(config))
+        return $(dir $d)
+    
+    ### Return the location of the bytecode library
+    cma(config)=
+        return $(file $(location $(config))/$(this.NAME).cma)
+    
+    ### Return the location of the native library
+    cmxa(config)=
+        return $(file $(location $(config))/$(this.NAME).cmxa)
+    
+    ### Return the location of the native library
+    archive(config)=
+        return $(file $(location $(config))/$(this.NAME).a)
+    
+    ### Construct a referral object for a component and library name
+    new(c, name, custom)=
+        c=$(OCaml_component.assert $c, $"OCaml_library_referral")
+        this.DIR=$(c.STAGE.DIR)
+        this.NAME=$(name)
+        this.UNCONFIG=false
+        switch $(custom)
+        case $"pure"
+            this.MIXED=false
+            export
+        case $"mixed"
+            this.MIXED=true
+            export
+        default
+            eprintln(*** OCaml_library_referral.new: $(custom) != pure/mixed)
+            exit(-1)
+        return $(this)
+    
+    ### Construct a referral object for a tool library
+    tool(name)=
+        this.DIR=$(TOOLSDIR)/usr/lib/ocaml
+        this.NAME=$(name)
+        this.MIXED=false    # but, we always have the TOOLSDIR in the path
+        this.UNCONFIG=true
+        return $(this)
+
+### Base class for OCaml language composition units
+OCaml_unit.=
+    class OCaml_unit
+    extends $(Unit)
+    
+    ### Module files by extension
+    protected.module-file-by-extension(extension, modules)=
+        outfiles=
+        export outfiles
+        foreach(i, $(modules))
+            i=$(file $(addsuffix $(extension), $i))
+            if $(test -f $i)
+                outfiles+=$i
+        return $(outfiles)
+    
+    ### Normalize the source description
+    protected.source(src, context)=
+        this=$(Unit::source $(src), $(context))
+        modules[]=
+        if $(src.object-mem MODULES)
+            modules=$(src.MODULES)
+            export modules
+        this.MODULES=$(modules)
+        
+        this.PACKAGES[]=
+        this.PREDICATES[]=
+        if $(src.object-mem PACKAGES)
+            this.PACKAGES=$(src.PACKAGES)
+            if $(src.object-mem PREDICATES)
+                this.PREDICATES=$(src.PREDICATES)
+                export
+            export
+        this.OCAMLLEX=$(public.OCAMLLEX)
+        this.OCAMLYACC=$(public.OCAMLYACC)
+        this.OCAMLC=$(public.OCAMLC)
+        this.OCAMLOPT=$(public.OCAMLOPT)
+        this.OCAMLMKLIB=$(public.OCAMLMKLIB)
+        return $(this)
+    
+    ### Configure a compiler object
+    protected.configure-compiler(cc, c, config)=
+        export cc
+        cc.CMIDIR=$(c.STAGE.DIR)/$(config)
+        if $(this.PACKAGES)
+            cc.PACKAGES=$(PACKAGES)
+            if $(this.PREDICATES)
+                cc.PREDICATES=$(this.PREDICATES)
+        foreach(c, $(this.COMPONENTS))
+            cc.SEARCH+=$(c.STAGE.DIR)/$(config)
+        match $(config)
+        case $"debug"
+            cc.OPTIONS+=-g -warn-error A
+            cc.CFLAGS+=-g -Werror
+        case $"release"
+            cc.CFLAGS+=-O3
+            if $(cc.instanceof OCaml_native_compiler)
+                cc.OPTIONS+=-inline 9 -noassert -unsafe
+        return $(cc)
+    
+    ### Protected composer method
+    protected.precompose(c)=
+        ckdeps=
+        export ckdeps
+        foreach(c0, $(this.COMPONENTS))
+            ckdeps+=$(c0.ck libraries)
+        this.COMPONENTS+=$c
+        this.OCAMLLEX.DEPEND+=$(ckdeps)
+        this.OCAMLYACC.DEPEND+=$(ckdeps)
+        this.OCAMLC.DEPEND+=$(ckdeps)
+        this.OCAMLOPT.DEPEND+=$(ckdeps)
+        return $(this)
+    
+    ### Compile all the interfaces
+    protected.compile-interfaces(dst)=
+        cmi=
+        export cmi
+        foreach(m, $(this.MODULES))
+            mli=$(file $(addsuffix .mli, $m))
+            if $(test -f $(mli))
+                cmi+=$(this.OCAMLC.cmi-file $(mli), $(dst))
+            else
+                mly=$(file $(addsuffix .mly, $m))
+                if $(test -f $(mly))
+                    ml=$(this.OCAMLYACC.generate $(mly), $(dst))
+                    mli=$(replacesuffixes .ml, .mli, $(ml))
+                    cmi+=$(this.OCAMLC.cmi-file $(mli), $(dst))
+        return $(cmi)
+    
+    ### Compile all the modules into bytecode
+    protected.compile-bytecode(dst)=
+        cmo=
+        export cmo
+        foreach(m, $(this.MODULES))
+            ml=$(file $(addsuffix .ml, $m))
+            if $(test -f $(ml))
+                cmo+=$(this.OCAMLC.cmo-file $(ml), $(dst))
+            else
+                mll=$(file $(addsuffix .mll, $m))
+                if $(test -f $(mll))
+                    ml=$(this.OCAMLLEX.generate $(mll), $(dst))
+                    cmo+=$(this.OCAMLC.cmo-file $(ml), $(dst))
+                else
+                    mly=$(file $(addsuffix .mly, $m))
+                    if $(test -f $(mly))
+                        prefix=$(this.OCAMLYACC.prefix $(mly), $(dst))
+                        ml=$(file $(addsuffix .ml, $(prefix)))
+                        cmo+=$(this.OCAMLC.cmo-file $(ml), $(dst))
+                    else
+                        eprintln(*** No source file for module $m)
+                        exit(-1)
+        return $(cmo)
+    
+    ### Compile all the modules into native
+    protected.compile-native(dst)=
+        cmx=
+        export cmx
+        foreach(m, $(this.MODULES))
+            ml=$(file $(addsuffix .ml, $m))
+            if $(test -f $(ml))
+                cmx+=$(this.OCAMLOPT.cmx-file $(ml), $(dst))
+            else
+                mll=$(file $(addsuffix .mll, $m))
+                if $(test -f $(mll))
+                    ml=$(this.OCAMLLEX.generate $(mll), $(dst))
+                    cmx+=$(this.OCAMLOPT.cmx-file $(ml), $(dst))
+                else
+                    mly=$(file $(addsuffix .mly, $m))
+                    if $(test -f $(mly))
+                        prefix=$(this.OCAMLYACC.prefix $(mly), $(dst))
+                        ml=$(file $(addsuffix .ml, $(prefix)))
+                        cmx+=$(this.OCAMLOPT.cmx-file $(ml), $(dst))
+                    else
+                        eprintln(*** No source file for module $m)
+                        exit(-1)
+        return $(cmx)
+    
+    ### Configuration visitor
+    protected.visit-configurations(c)=
+        private.outputs=
+        export outputs
+        foreach(config, $(this.CONFIGURATIONS))
+            this.OCAMLC=$(configure-compiler $(this.OCAMLC), $c, $(config))
+            this.OCAMLOPT=$(configure-compiler $(this.OCAMLOPT), $c, $(config))
+            dst=$(dir $(c.STAGE.DIR)/$(config))
+            cmi=$(this.compile-interfaces $(dst))
+            this.OCAMLC.DEPEND+=$(cmi)
+            this.OCAMLOPT.DEPEND+=$(cmi)
+            cmo=$(this.compile-bytecode $(dst))
+            cmx=$(this.compile-native $(dst))
+            outputs+=$(this.compose-aux $(config), $(cmo), $(cmx), $(dst))
+        return $(outputs)
+    
+    ### Final configuration
+    protected.final-configuration()=
+        if $(mem release, $(CONFIGURATIONS))
+            return release
+        else
+            return $(nth 0, $(CONFIGURATIONS))
+    
+    ### Construct a new composer
+    protected.new(name, src, context)=
+        src.NAME=$(name)
+        this=$(source $(src), $(context))
+        return $(this)
+
+### OCaml library composition units
+OCaml_library.=
+    class OCaml_library
+    extends $(OCaml_unit)
+    
+    ### Normalize the source description
+    protected.source(src, context)=
+        this=$(OCaml_unit::source $(src), $(context))
+        this.CFILES[]=
+        if $(src.object-mem CFILES)
+            this.CFILES=$(src.CFILES)
+            export
+        return $(this)
+    
+    ### Auxillary composition method
+    protected.compose-aux(config, cmo, cmx, dst)=
+        private.cc=$(this.OCAMLC)
+        private.ccopt=$(this.OCAMLOPT)
+        private.outputs=
+        if $(this.CFILES)
+            private.mklib=$(this.OCAMLMKLIB)
+            private.libs=
+            private.po=$(ccopt.c-primitives $(this.CFILES), $(dst))
+            private.pa=$(mklib.c-library $(this.NAME), $(po), $(dst))
+            outputs+=$(pa)
+            libs=$(mklib.bytecode-library $(this.NAME), $(cmo), $(dst))
+            $(libs): $(pa)
+            outputs+=$(libs)
+            libs=$(mklib.native-library $(this.NAME), $(cmx), $(dst))
+            $(libs): $(pa)
+            outputs+=$(libs)
+            export outputs
+        else
+            outputs+=$(cc.bytecode-library $(this.NAME), $(cmo), $(dst))
+            outputs+=$(ccopt.native-library $(this.NAME), $(cmx), $(dst))
+            export outputs
+        return $(outputs)
+    
+    ### Construct a new composer
+    new(name, src)=
+        return $(OCaml_unit::new $(name), $(src), OCaml_library.new)
+    
+    ### Compose
+    compose(c)=
+        c=$(OCaml_component.assert $c, $"OCaml_library $(NAME)")
+        this=$(precompose $c)
+        private.libs=$(visit-configurations $c)
+        
+        $(c.ck libraries): $(libs)
+        
+        return $(libs)
+    
+    ### Package files
+    package-files(c)=
+        c=$(OCaml_component.assert $c, $"OCaml_library $(NAME)")
+        cdir=$(dir $(c.STAGE.DIR)/$(final-configuration))
+        mli=$(module-file-by-extension .mli, $(this.MODULES))
+        mll=$(module-file-by-extension .mll, $(this.MODULES))
+        mly=$(module-file-by-extension .mly, $(this.MODULES))
+        cmi=$(module-file-by-extension .cmi, $(this.MODULES))
+        cmi=$(file $(addprefix $(cdir)/, $(cmi)))
+        cmx=$(module-file-by-extension .cmx, $(this.MODULES))
+        cmx=$(file $(addprefix $(cdir)/, $(cmx)))
+        libs=
+        export libs
+        if $(this.CFILES)
+            libs+=dll$(this.NAME).so lib$(this.NAME).a
+        libs=$(file $(addprefix $(cdir)/, $(libs)))
+        return $(mli) $(mll) $(mly) $(cmi) $(cmx) $(libs)
+    
+    ### Package archive specifiers
+    package-archives()=
+        private.byte=$(this.NAME).cma
+        private.native=$(this.NAME).cmxa
+        s.=
+            extends $(Map)
+            $|byte|=$(byte)
+            $|native|=$(native)
+        return $s
+
+### OCaml library composition units
+OCaml_program.=
+    class OCaml_program
+    extends $(OCaml_unit)
+    
+    ### Normalize the source description
+    protected.source(src, context)=
+        this=$(OCaml_unit::source $(src), $(context))
+        this.LIBREFS[]=
+        this.SUPPORT[]=
+        if $(src.object-mem LIBREFS)
+            this.LIBREFS=$(src.LIBREFS)
+            export
+        if $(src.object-mem SUPPORT)
+            this.SUPPORT=$(src.SUPPORT)
+            export
+        return $(this)
+    
+    ### Return the dynamic library search path
+    protected.support-load-paths(config)=
+        search=
+        export search
+        foreach(r, $(this.LIBREFS))
+            if $(r.MIXED)
+                search+=$(dir $(r.DIR)/$(config))
+        return $(TOOLSDIR)/usr/lib/ocaml $(search)
+    
+    ### Configure a compiler object
+    protected.configure-compiler(cc, c, config)=
+        cc=$(OCaml_unit::configure-compiler $(cc), $c, $(config))
+        cc.DEPEND+=$(c.ck libraries)
+        return $(cc)
+    
+    ### Auxillary composition method
+    protected.compose-aux(config, cmo, cmx, dst)=
+        cma=
+        cmxa=
+        archive=
+        export cma cmxa archive
+        foreach(r, $(this.LIBREFS))
+            cma+=$(r.cma $(config))
+            cmxa+=$(r.cmxa $(config))
+            archive+=$(r.archive $(config))
+        private.programs=
+        export programs
+        section
+            private.cc=$(this.OCAMLC)
+            cc.OPTIONS+=$(cc.verbose-flag)
+            cc.SUPPORT+=$(this.SUPPORT)
+            objs=$(cma) $(cmo)
+            name=$(this.NAME).run
+            programs+=$(cc.program $(name), $(config), $(objs), $(dst))
+        section
+            private.cc=$(this.OCAMLOPT)
+            cc.OPTIONS+=$(cc.verbose-flag)
+            cc.SUPPORT+=$(this.SUPPORT)
+            cc.DEPEND+=$(archive)
+            objs=$(cmxa) $(cmx)
+            name=$(this.NAME)
+            programs+=$(cc.program $(name), $(config), $(objs), $(dst))
+        return $(programs)
+    
+    ### Construct a new composer
+    new(name, src)=
+        return $(OCaml_unit::new $(name), $(src), OCaml_program.new)
+    
+    ### Compose
+    compose(c)=
+        c=$(OCaml_component.assert $c, $"OCaml_program $(this.NAME)")
+        this=$(precompose $c)
+        private.progs=$(visit-configurations $c)
+        
+        $(c.ck programs): $(progs)
+        
+        return $(progs)
+
+### OCaml program test program composition units
+OCaml_test_program.=
+    class OCaml_test_program
+    extends $(OCaml_program)
+    
+    ### Construct a new composer
+    new(name, src)=
+        return $(OCaml_program::new $(name), $(src))
+    
+    ### Extend the composer to add the <test> ephemeral target
+    compose-aux(config, cmo, cmx, dst)=
+        progs=$(OCaml_program::compose-aux $(config), $(cmo), $(cmx), $(dst))
+        load=$(concat $":", $(support-load-paths $(config)))
+        run=$(nth 0, $(progs))
+        
+        test: $(progs)
+            section
+                setenv(CAML_LD_LIBRARY_PATH, $(load))
+                foreach(p, $(progs))
+                    $p -verbose || echo $p failed!
+        
+        return $(progs)
+
+### OCaml findlib package composition
+OCaml_findlib_subpackage.=
+    class OCaml_findlib_subpackage
+    
+    ### Raise an exception
+    protected.throw(m)=
+        x.=
+            message=$"Ocaml_findlib_subpackage [$m]"
+        raise $x
+    
+    ### Constructor helper
+    protected.subpackage(i)=
+        if $(not $(i.object-mem NAME))
+            throw($"undefined package name")
+        if $(not $(i.object-mem DESCRIPTION))
+            throw($"no description for package $(i.NAME)")
+        o.=
+            NAME=$(i.NAME)
+            DESCRIPTION=$(i.DESCRIPTION)
+            REQUIRES[]=
+            ARCHIVES[]=
+            SUBPKGS[]=
+        export o
+        if $(this.object-mem NAME)
+            o.NAME=$(this.NAME)/$(o.NAME)
+        if $(i.object-mem REQUIRES)
+            o.REQUIRES=$(i.REQUIRES)
+        if $(i.object-mem ARCHIVES)
+            o.ARCHIVES=$(i.ARCHIVES)
+        return $o
+    
+    ### Construction invariant
+    protected.new(src)=
+        private.src=$(subpackage $(src))
+        this.NAME=$(src.NAME)
+        this.DESCRIPTION=$(src.DESCRIPTION)
+        this.REQUIRES=$(src.REQUIRES)
+        this.ARCHIVES=$(src.ARCHIVES)
+        this.SUBPKGS=$(src.SUBPKGS)
+        return $(this)
+    
+    ### Add a subpackage
+    add-subpackage(src)=
+        this.SUBPKGS+=$(this.subpackage $(src))
+        return $(this)
+
+### OCaml findlib package composition
+OCaml_findlib_package.=
+    class OCaml_findlib_package
+    extends $(OCaml_findlib_subpackage)
+    
+    ### Generate the META file text
+    protected.generate-meta()=
+        fp=$(open-out-string)
+        fprint($(fp), $""# META file generated for $(this.NAME) package
+
+name="$(this.NAME)"
+version="$(this.VERSION)"
+description="$(this.DESCRIPTION)"
+"")
+        if $(this.REQUIRES)
+            fprintln($(fp), $""requires="$(this.REQUIRES)" "")
+        foreach(p, $(this.SUBPKGS))
+            fprintln($(fp), $(EMPTY))
+            fprintln($(fp), $""package "$(basename $(p.NAME))" ("")
+            if $(p.REQUIRES)
+                fprintln($(fp), $""  requires="$(p.REQUIRES)" "")
+            foreach(v, $(p.ARCHIVES))
+                private.byte=$(v.find byte)
+                private.native=$(v.find native)
+                fprintln($(fp), $"  archive(byte)=" "$(byte)")
+                fprintln($(fp), $"  archive(native)=" "$(native)")
+            fprintln($(fp), $")")
+        private.text=$(out-contents $(fp))
+        close($(fp))
+        return $(text)
+    
+    ### The META file target
+    protected.meta-target()=
+        private.meta=$(file $(this.STAGE.DIR)/META)
+        private.text=$(generate-meta)
+            
+        $(meta): $(this.STAGE.DIR) $(this.FILES)
+            fprint($@, $(text))
+        return $(meta)
+    
+    ### Constructor
+    new(src)=
+        this=$(OCaml_findlib_subpackage::new $(src))
+        if $(not $(src.object-mem VERSION))
+            throw($"no version for package $(this.NAME)")
+        private.stage=$(Stage)
+        stage.DIR=$(AUXROOT)
+        this.STAGE=$(stage.push $(this.NAME).package)
+        this.VERSION=$(src.VERSION)
+        this.FILES[]=
+        this.DOCSEARCH[]=
+        return $(this)
+    
+    ### Install target
+    install-target()=
+        private.target=$(addprefix install-, $(this.NAME))
+        private.meta=$(meta-target)
+        .PHONY: $(target)
+        $(target): $(meta) $(this.FILES)
+            -ocamlfind install $(this.NAME) $^
+        return $(target)
+    
+    ### Remove target
+    remove-target()=
+        private.target=$(addprefix remove-, $(this.NAME))
+        .PHONY: $(target)
+        $(target):
+            -ocamlfind remove $(this.NAME)
+        return $(target)
+    
+    ### Documents target
+    documents-target()=
+        private.target=$(addprefix documents-, $(this.NAME))
+        private.dstage=$(this.STAGE.push docs)
+        OCAMLDOC.DEPEND+=$(dstage.DIR) $(this.FILES)
+        OCAMLDOC.SEARCH+=$(this.DOCSEARCH)
+        return $(OCAMLDOC.html-documents $(this.FILES), $(dstage.DIR))
+
+# End $File$
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.