package ppx_optcomp

  1. Overview
  2. Docs
Optional compilation for OCaml


Dune Dependency






Part of the Jane Street's PPX rewriters collection.

Published: 15 Dec 2017


ppx_optcomp - 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
let y = 2

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


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


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.


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.


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.

Dependencies (3)

  1. jbuilder >= "1.0+beta12"
  2. ppx_core >= "v0.10" & < "v0.11"
  3. ocaml >= "4.04.1"

Dev Dependencies


Used by (10)

  1. caqti-dynload < "0.10.2"
  2. conduit >= "0.12.0" & < "1.0.0"
  3. eliom >= "10.1.0"
  4. kqueue >= "0.2.0"
  5. pgocaml_ppx >= "4.2"
  6. poll
  7. ppx_bap < "v0.14.0"
  8. ppx_driver >= "v0.10.0" & < "v0.11.0"
  9. vscoq-language-server >= "2.1.0+coq8.19"
  10. yices2_bindings