% OASIS User Manual
% author Sylvain Le Gall and others

Introduction
============

OASIS is a tool to help OCaml developers to integrate configure, build and
install systems in their projects. It should help to create standard entry
points in the source code build system, allowing external tools to analyse
projects easily.

This tool is freely inspired by [Cabal][] which is the same kind of tool for
[Haskell][].

  [Cabal]: http://www.haskell.org/cabal
  [Haskell]: http://www.haskell.org

Everything starts with a single text file, named `_oasis`, at the root of the
project source directory. It contains semi-colon separated fields and sections
that describe what is contained in the project and what to do with it.

This file is used to generate a skeleton for build, configure and install
systems. Generation can be customized through extra fields or directly inside
generated files.

The main entry point is an OCaml script `setup.ml`. It is self contained. Once
generated there is no additional dependencies (just like an autoconf
`configure` script).

OASIS has been created with [OCamlbuild][] in mind. So there is probably some
features/bugs that are oriented toward this build system.

  [OCamlbuild]: https://ocaml.org/learn/tutorials/ocamlbuild/

Features:

 * OCamlbuild support ([see here](#plugin-ocamlbuild))
 * Standard files auto-generation (see here [1](#plugin-devfiles),
   [2](#plugin-meta), [3](#plugin-stdfiles))
 * Generic support for all step ([see here](#plugin-custom))
 * Internal configure/install ([see here](#plugin-internal))

Planned features:

 * [OCaml autoconf](http://ocaml-autoconf.forge.ocamlcore.org)
 * [OCamlMakefile](http://www.ocaml.info/software.html#build_tools)
 * [OMake](http://omake.metaprl.org/index.html)

Writing `_oasis` file
=====================

Syntax
------

The `_oasis` must be a valid UTF-8 text file. This file identify the toplevel
directory of the project.

Identifiers are just like variable names in OCaml, it cannot contains "-" or
numbers at the beginning. Strings follow OCaml convention. For extra
information on the parser/lexer see [Genlex][].

 [Genlex]: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Genlex.html

A line beginning by `#` is a comment and is ignored. Blank line are ignored.

The file contains semi-colon fields and sections.

### Fields

Fields are defined as `field_name: field_value`:

 * Field name is an identifier, it contains only alphanumeric chars.
 * Field name is case insensitive.
 * Field value follow OCaml string convention, expect you don't need '"'
   around it.
 * Leading and trailing blanks of field value are removed.
 * A field value can continue on several lines, in this case the content of
   the value must be indented one level more then the field name. In the body of
   the value a blank line is represented by `.`.
 * If two fields have the same `field_name`, only the latter sets the value.

The separator ':' can be replaced by '+:' which appends the `field_value` to
the previous value of the value (rather than erasing it). Beware that appending
is value dependent, some fields can concatenate, some cannot.

The ':' can also be replaced by '\$:', see
[Conditional value](#conditional-value).

### Sections

Sections can be an identifier or a string:

    Library foo

or

    Library "foo".

Section name can be : `Library`, `Executable`, `Document`, `Test` and
`SourceRepository`. Content of a section is indented relative to the section
begin.

Example:
    # Toplevel fields
    OASISFormat:  1.0
    
    Library "foo"
      # Library fields
      Path: src/
    
    # Back to toplevel fields
    Synopsis: bar

### Conditional value

It is possible to define some fields conditionally. Not all fields can be
specified this way, only fields that have no good default values and that must
be evaluated at runtime is defined.

For example:

 * Toplevel fields `Name` and `Version` cannot be conditional.
 * Library fields `Build` and `Install` can be conditional.

A condition is defined using a `if ... else ...` construct.

Example:

    Library bar
      if os_type(Win32)
        Build: true
      else
        Build: false

Available tests are :

$ListOASISTests

The values from these tests are extracted from theoutput of `ocamlc -config`.


An additional `flag` test is available which check that the a Flag is defined. See
the chapter on the [Flag section](#flag).

Tests and flags can be combined using standard boolean operation:

* `(expr)`
* `! expr`: negation of `expr`.
* `expr1 && expr2`: boolean and.
* `expr1 || expr2`: boolean or.
* `true` and `false`.


For boolean fields, you can replace the `if ... else ...` construct by `\$:`.

For example:

    Library bar
      if os_type(Win32)
        Build: true
      else
        Build: false

is equivalent to:


        Build\$: os_type(Win32)

### Features

OASIS allows to experiment with non-official, experimental features. These
features are included in the code but are not activated by default. In order to
activate them. You need to list them in `AlphaFeatures` or `BetaFeatures` of
your `_oasis`.

Alpha features are under development and may only be used for testing. They are
not yet well defined, they are evolving quickly and may be removed in future
release of OASIS.

Beta features are features almost ready to be shipped, they mostly need to be
polished before release. You may use them as they will probably be ready for
the next version of OASIS.

Once you have activated a features, you get access to more fields and some
parts of the code maybe be activated as well.

Features allow the OASIS development team to release experiment early and
should avoid long delay between release.

Available features:

$ListAllFeatures

Package
-------

Package fields are defined outside sections. They apply to the whole project.

Fields:

$ListOASISPackageFields

`BuildDepends` and `BuildTools` are appended to all sections and not used
directly in the package.

Sections
--------

There are 6 possible sections:

 * `Flag`: a command line flag.
 * `Library`: an OCaml library.
 * `Object`: a .cmo/.cmx object (__require BetaFeatures: section\_object__).
 * `Executable`: an OCaml executable.
 * `Document`: a document.
 * `Test`: a test.
 * `SourceRepository`: version control system information.

None of these sections are mandatory. `Library`, `Executable`, `Document` and
`Test` can be dependent on each other. This not a problem as long as there is no
cycle inside the dependency graph. Dependencies can be expressed through
`BuildDepends` and `BuildTools` fields.

### Flag

A flag section defines a configure command line option. It will be translated to
to `--enable-XXX` and `--disable-XXX` for the command line. It can be used
inside conditional fields.

Fields:

$ListOASISFlagFields

### Common fields

These fields are used inside `Library` and `Executable`.

Fields:

$ListOASISBuildFields

All files defined in the section are relative to `Path`.

### Library

Define an OCaml library. OCaml API is generated using `ocamldoc` applied to
`Modules` with `BuildDepends` required flags.

Fields:

$ListOASISLibraryFields
 * Include all common fields.

### Object

__require BetaFeatures: section\_object__

Define an OCaml object file. It is very close to a library except that an
object when linked will evaluate all its toplevel statement. This may be ideal
if you want to call for example an initialisation function.

Fields:

$ListOASISObjectFields
 * Include all common fields.

### Executable

Define an OCaml executable. If the executable is a bytecode that use internal
library, a helper script can be generated to set library path.

Fields:

$ListOASISExecutableFields
 * Include all common fields.

### Document

Define a generated document.

Fields:

$ListOASISDocumentFields

### Test

Define a test to run.

Fields:

$ListOASISTestFields

### SourceRepository

Define VCS information. There are two special identified repositories:

 * head: identify the main development repository.
 * this: identify the repository at the state of the current version.

Fields:

$ListOASISSourceRepositoryFields

Supported VCS types are: darcs, git, svn, cvs, hg, bzr, arch, monotone.

License
-------

We have adopted a [DEP-5][] license style description.

 [DEP-5]: http://dep.debian.net/deps/dep5/#license-specification

The reason of this format is to have machine-readable license description.
Using this former work, we hope to be compatible with future standards of
Debian.

We have limited the number of license to:

$ListShortLicenses
 * or an URL describing the license

And license exception to:

$ListLicenseExceptions
 * or an URL describing the license exception

You can specify a license version using a dash and only digits or dashes at the
end of the license short name.

Examples :

 * `LGPL-2.1 with OCaml linking exception`: LGPL v2.1 with OCaml linking exception
 * `GPL-2+`: GPL v2 or later

Data files
----------

`DataFiles` fields help to install extra data inside `\$datadir/\$pkg_name`. This
field is a comma separated list of file, with optional value inside parenthesis.
You can override target directory using `fn (\$datadir/other_location)`.

You can use wildcard `*` but only for a filename and followed by a single dot
extension: `dir/*.html` is valid but `dir/*` and `dir/*.tar.gz` are not valid.

Substitution inside text
------------------------

Substitution is performed using [Buffer.add\_substitute][].

 [Buffer.add\_substitute]: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Buffer.html#VALadd_substitute

Variable are evaluated using environment. This is a mix of various data coming
from `_oasis` file, `ocamlc -config` output and configure tests. So environment
variables depends of each project. You can have a precise idea of what variables
is available looking at the file `setup.data`.

Here is a list of standard variables:

$ListStandardVariables

Other variables are defined depending on your `_oasis` file:

 * Variables from BuildDepends:  `pkg_`  and the name of the findlib package.
   It points to the directory containing the package.
   If there is a version constraint, it is also translated to a variable. It
   contains a boolean value to know if the version is ok or not.
   Internal findlib packages don't create variables.
   Example: `BuildDepends: oUnit (>= 1.0.3)` becomes two variables
   `pkg_oUnit = /usr/lib/ocaml/ounit` and `pkg_oUnit_ge_1_0_3 = true`.
 * Variables from external BuildTools: the variable is the name given
   in the field and its value the filename of the executable.
   Example: `BuildTools: make` becomes `make = /usr/bin/make`.
 * Dynamic variables from internal BuildTools: the variable is the name
   of the Executable section and its value the filename of the executable.
   Example: `Executable ocamlmod` becomes `ocamlmod =
   _build/src/tools/ocamlmod`. These variables are set through `setup.log`
   rather than `setup.data`. They are set only when the corresponding files
   is built.


It is also possible to apply transformation through functions. This is useful
when you need to use properties that need to be determined at runtime:

 * `utoh`: convert an Unix filename into a host filename (e.g. UNIX -> Win32
    conversion).
 * `ocaml_escaped`: call to `String.escaped`.

For example `\$(utoh src/test.ml)` will be replaced by `src\test.ml` on Windows.

Customization of generated files
--------------------------------

When OASIS generates file, it always replace only lines between
`OASIS_START` and `OASIS_STOP`. These keywords are commented and
followed by data to check that content is unchanged.

If the file doesn't exist, OASIS will create the whole file using default
header and footer.

If OASIS detects a change inside the section being replaced, it will create a
backup of the file and issue a warning.

Customization of setup.ml
-------------------------

`setup.ml` as any generated files can be customized in its header and footer.
Moreover it can be customized through hook in the code directly.

TODO: explains hook.

Using OASIS during software development
---------------------------------------

Since `_oasis` becomes a central place of information about the building
process, it can be quite cumbersome to run again and again `oasis`. You can
avoid it using the `-dev` flags when calling `oasis` for the first time. This
way it will rebuilt very dependents build files each time you call `ocaml
setup.ml`. A `setup.ml` built this way, should not be distributed. This intended
for development purpose only.

Plugins
-------

OASIS is basically built around plugins. They are used to define
specific behavior for generating files and including their own code in `setup.ml`.

There are 6 categories of plugin:

 * __Conf__: apply to configure step, used in the field `ConfType`
 * __Build__: apply to build stepi, used in the field `BuildType`
 * __Test__: apply to test sections, used in the field `Type` of a test
 * __Doc__: apply to documentation sections, used in the field `Type` of a document
 * __Install__: apply to install and uninstall steps, used in the field `DocType`
 * __Extra__: everything else, used in the field `Plugins`

$ListOASISPlugins

Building and installing
=======================

The file `setup.ml` is the base system to run every targets. It contains a
self contained OCaml script, that only depends on OCaml standard installation
that doesn't require using stublibs (no Str or Unix). This constraint is
required to be fully portable even on system that doesn't support dynamic
loading.

The file `setup.data` is the result of the configure step and contains data that
can be used for other step. It is removed only in `distclean` target. The format
of this file is on variable and values per line: `var="value"`. The value is an
OCaml string. The file in this form can be read by `make` and `sh`. Once
generated this file should not be modified.

The file `setup.log` contains a list of action done and is used and updated by
action done and cancel (e.g. action `install` log files installed which action
`uninstall` remove).

ocaml setup.ml -configure
-------------------------

This is the first step to perform. It is mandatory. It runs various test of the
build environment to check that everything required is installed.


ocaml setup.ml -build
---------------------

This step is mandatory. Build libraries and executables.

ocaml setup.ml -test
--------------------

This step is optional. Run defined test. Need the build step before.

ocaml setup.ml -doc
-------------------

This step is optional. It builds API documentation for library and extra
documentation as defined in `Document`.

ocaml setup.ml -install
-----------------------

This step is mandatory. Install what has been built in build and doc step. Also
install data files as defined in `DataFiles` fields.

ocaml setup.ml -uninstall
-------------------------

This step is optional. Remove files and libraries installed.

ocaml setup.ml -reinstall
-------------------------

This step is optional. Perform an uninstall and then an install step.

ocaml setup.ml -clean
---------------------

This step is optional. Clean generated files during build and doc steps.

ocaml setup.ml -distclean
-------------------------

This step is optional. Try to go back to pristine source state.

ocaml setup.ml -all
-------------------

This step is optional. Run configure, build, test and doc step in one run.

OASIS usage
===================

Command line
------------

$OASISCommandLineHelp

