Optional compilation for OCaml
OCaml Other
Latest commit dc608ed Feb 21, 2017 @trefis trefis 114.33+05
Permalink
Failed to load latest commit information.
bin 114.29+19 Jan 24, 2017
src 114.29+19 Jan 24, 2017
test 113.33.00 Mar 9, 2016
.gitignore 114.20+69 Dec 15, 2016
CHANGES.md 113.43+70 May 20, 2016
LICENSE.txt 113.09.00 Sep 25, 2015
Makefile 114.20+69 Dec 15, 2016
README.md 113.43+70 May 20, 2016
ppx_optcomp.opam 114.33+05 Feb 21, 2017

README.md

Optional compilation for OCaml

ppx_optcomp stands for Optional Compilation. It is a tool used to handle optional compilations of pieces of code depending of the word size, the version of the compiler, ...

ppx_optcomp can be used a a standalone pre-processor, but is also integrated in the ppx_driver.

The syntax is quite similar to cpp:

#if ocaml_version < (4, 02, 0)
let x = 1
#else
let y = 2
#endif

Note that ppx_optcomp does not support macros like cpp, we only use it for optional compilations.

Syntax

ppx_optcomp runs after the OCaml lexer and before the OCaml parser. This means that parts of the file that are dropped by ppx_optcomp needs to be lexically correct but not grammatically correct.

ppx_optcomp will interpret all lines that start with a #. # has to be the first character, if there are spaces before ppx_optcomp will not try to interpret the line and will pass it as-is to the OCaml parser. The syntax is:

#identifier directive-argument

The argument is everything up to the end of the line. You can use \ at the end of lines to span the argument over multiple line. Optcomp will also automatically fetch arguments past the end of line if a set of parentheses is not properly closed.

So for instance one can write:

#if ocaml_version < (  4
                    , 02
                    ,  0
                    )

Note that since ppx_optcomp runs after the lexer it won't interpret lines starting with # if they are inside another token. So for instance these won't work:

  • #-directive inside a string:

    let x = "
    #if foo
    "
  • #-directive inside a comment:

    (*
    #if foo
    *)

Directives

Defining variables

  • #let pattern = expression
  • #define identifier expression

We also allow: #define identifier. This will define identifier to ().

You can also undefine a variable using #undef identifier.

Conditionals

The following directives are available for conditional compilations:

  • #if expression
  • #elif expression
  • #else
  • #endif

In all cases expression must be an expression that evaluates to a boolean value. Ppx_optcomp will fail if it is not the case.

For people used to cpp, we also allow these:

  • #ifdef identifier
  • #ifndef identifier
  • #elifdef identifier
  • #elifndef identifier

Which will test if a variable is defined. Note that ppx_optcomp will only accept to test if a variable is defined if it has seen it before, in one of #let, #define or #undef. This allows ppx_opcompt to check for typos.

We do however allow this special case:

#ifndef VAR
#define VAR

Warnings and errors

#warning expression will cause the pre-processor to print a message on stderr.

#error expression will cause the pre-processor to fail with the following error message.

Note that in both cases expression can be an arbitrary expression.

Imports

Ppx_optcomp allows one to import another file using:

#import filename

where filename is a string constant. Filenames to import are resolved as follow:

  • if filename is relative, i.e. doesn't start with /, it is considered as relative to the directory of the file being parsed
  • if filename is absolute, i.e. starts with /, it is used as it

To keep things simple ppx_optcomp only allows for #-directives in imported files. The intended use is having this at the beginning of a file:

#import "config.mlh"

Expressions and patterns

ppx_optcomp supports a subset of OCaml expressions and patterns:

  • literals: integers, characters and strings
  • tuples
  • true and false
  • let-bindings
  • pattern matching

And it provides the following functions:

  • comparison operators: =, <, ...
  • boolean operators: ||, &&, not, ...
  • arithmetic operators: +, -, *, /
  • min and max
  • fst and snd
  • conversion functions: to_int, to_string, to_char, to_bool
  • show: pretty-print a value

It also provides defined which is a special function to test if a variable is defined. But the same remark as for #ifdef applies to defined.