Preprocessing Specification¶
Some stanzas including (library)
accept a (preprocessing)
field. The
possible values for its argument are:
pp-spec ::= <pp-module> (per-module <per-module>+) per-module ::= ( <pp-module> <module>+ ) pp-module ::= no_preprocessing (action <action>) (pps <ppx-rewriters-and-flags>) (staged_pps <ppx-rewriters-and-flags>) future_syntax
no_preprocessing¶
When no_preprocessing
is passed, files are given as-is to the compiler.
This is the default behavior.
Preprocessing With Actions¶
In (action <action>)
, <action>
uses the same DSL as described in
User Actions, and for the same reason given in that section, it will be
executed from the root of the current build context. It’s expected to be an
action that reads the file given as a dependency named input-file
and
outputs the preprocessed file on its standard output.
More precisely, (preprocess (action <action>))
acts as if
you had set up a rule for every file of the form:
(rule
(target file.pp.ml)
(deps file.ml)
(action
(with-stdout-to %{target}
(chdir %{workspace_root} <action>))))
The equivalent of a -pp <command>
option passed to the OCaml compiler is
(system "<command> %{input-file}")
.
Using PPX Rewriters¶
If (pps <ppx-rewriters-and-flags>)
is used, the corresponding rewriters are
set up using the “fast pipeline” (using a separate preprocessing step).
If (staged_pps <ppx-rewriters-and-flags>)
is used, they are set up using
the “classic pipeline” (using the -ppx
command-line argument).
The distinction between these pipelines is explained in How Preprocessing Works.
PPX rewriters need to be compiled as a driver to be used by Dune. To run PPXs that do not support this (usually old ones), it is possible to use the ppxfind tool.
Arguments to PPX Rewriters¶
In (pps <ppx-rewriters-and-flags>)
and (staged_pps
<ppx-rewriters-and-flags>)
, <ppx-rewriters-and-flags>
is a sequence where
each element is either a command line flag if it starts with a -
or the name
of a library.
If you want to pass command line flags that don’t start with a -
, you can
separate library names from flags using --
. So for instance from the
following preprocess
field:
(preprocess (pps ppx1 -foo ppx2 -- -bar 42))
The list of libraries will be ppx1
and ppx2
, and the command line
arguments will be: -foo -bar 42
.
Future Syntax¶
The future_syntax
specification is a special value that brings some of the
newer OCaml syntaxes to older compilers.
It is equivalent to no_preprocessing
when using one of the most recent
versions of the compiler. When using an older one, it is a shim preprocessor
that backports some of the newer syntax elements. This allows you to use some
of the new OCaml features while keeping compatibility with older compilers.
One example of supported syntax is the custom let-syntax
that was
introduced in 4.08, allowing the user to define custom let
operators.
Note that this feature is implemented by the third-party ocaml-syntax-shims project, so if you use this feature, you must also declare a dependency on this package.
Per-Module Preprocessing Specification¶
By default, a preprocessing specification applies to all modules in the
library/set of executables. It’s possible to select the preprocessing on a
module-by-module basis by using the (per-module ...)
syntax. For instance:
(preprocess
(per_module
((action (run ./pp.sh X=1 %{input-file})) foo bar)
((action (run ./pp.sh X=2 %{input-file})) baz)))
The modules Foo
and Bar
will be preprocessed with pp.sh X=1
, and
Baz
will be preprocessed with pp.sh X=2
.
Preprocessor Dependencies¶
If your preprocessor needs extra dependencies, you should use the
preprocessor_deps
field available in the library
, executable
, and
executables
stanzas. It uses the Dependency Specification to
declare what the preprocessor needs.