This example demonstrates how to do conditional compilation in Dune based on compilation modes (bytes, native, js) without using virtual libraries.
The select form allows you to choose different implementations based on available libraries:
(library
(name mylib)
(libraries
(select platform.ml from
(js_of_ocaml -> platform.js.ml)
(-> platform.native.ml))))This will:
- Use
platform.js.mlwhenjs_of_ocamlis available - Fall back to
platform.native.mlotherwise
You can use rules with enabled_if to generate different files based on conditions:
(rule
(target config.ml)
(enabled_if (= %{profile} release))
(action (copy config.release.ml %{target})))
(rule
(target config.ml)
(enabled_if (<> %{profile} release))
(action (copy config.dev.ml %{target})))For different compilation modes, you can create separate source files:
src/
├── common.ml # Shared code
├── backend_native.ml
├── backend_bytecode.ml
└── backend_js.ml
Then use select or rules to pick the right implementation.
For more complex scenarios, especially with Melange/JS compilation:
; In dune-workspace
(context
(default))
(context
(default
(name js)))Then in your library:
(library
(name mylib)
(enabled_if (= %{context_name} default)))
(library
(name mylib)
(modes melange)
(enabled_if (= %{context_name} js)))For native:
dune buildFor JavaScript (with js_of_ocaml):
dune build @install --profile jsFor specific contexts:
dune build --context jsUnlike virtual libraries, these approaches have no runtime performance penalty since the selection happens at build time.