Skip to content

Instantly share code, notes, and snippets.

@samoht
Last active January 14, 2026 20:29
Show Gist options
  • Select an option

  • Save samoht/d3378c7a2a45af0650627fa27e826405 to your computer and use it in GitHub Desktop.

Select an option

Save samoht/d3378c7a2a45af0650627fa27e826405 to your computer and use it in GitHub Desktop.
RFC: Toolchains

RFC: Toolchains

Mental Model

Toolchain = compiler + tools that must match the project's OCaml version.

Dune manages toolchains transparently: download, build, cache, and select the right compiler for each build context.

Toolchain Sources

Source Description Use Case
System OCaml from PATH Quick builds, system-managed compiler
Locked From dune.lock Reproducible builds, pinned compiler version
Workspace Built from workspace sources Compiler development, custom patches

Selection Priority

  1. Explicit (toolchain ...) in dune-project
  2. Locked compiler in dune.lock
  3. System compiler from PATH

Configuration

Using a Locked Toolchain

; dune-project
(lang dune 3.18)

(package
 (name my-project)
 (depends
  (ocaml (>= 5.2))))

After dune pkg lock, the compiler is locked like any other package.

Using a Workspace Toolchain

For compiler development or custom patches:

; dune-project
(lang dune 3.18)

(toolchain
 (source workspace)
 (package ocaml))

This builds the compiler from workspace sources (e.g., vendored or local).

Using the System Toolchain

; dune-project
(lang dune 3.18)

(toolchain
 (source system))

Uses whatever ocaml is in PATH. No version management.

Relocatable Compilers

Locked toolchains are built as relocatable: they work from any installation path.

~/.cache/dune/
├── db/files/v5/<hash>/     # Content-addressed compiler
└── index/
    └── ocaml.5.2.0-a1b2c3d4 -> ../db/files/v5/<hash>

Benefits:

  • Share compiled toolchains across projects
  • No recompilation when moving projects
  • Works with dune's content-addressed cache

How Relocatability Works

Dune patches the compiler during build:

  1. Relative paths for stdlib lookup
  2. OCAMLLIB environment variable support
  3. Wrapper scripts that set up the environment

Cross-Compilation

For targeting multiple platforms from one host:

; dune-project
(lang dune 3.18)

(toolchain
 (name native))

(toolchain
 (name windows)
 (target x86_64-w64-mingw32))

Build Contexts

; dune-workspace
(context
 (default
  (targets native windows)))

This creates two build contexts:

  • _build/default/ - native compilation
  • _build/default.windows/ - cross-compiled for Windows

Toolchain Selection

For each context, dune selects the appropriate toolchain:

Context Toolchain OCAMLFIND_TOOLCHAIN
default native (not set)
default.windows windows windows

Directory Structure

_build/
├── .toolchains/
│   ├── native/           # Native compiler install
│   └── windows/          # Cross-compiler install
├── default/              # Native build output
└── default.windows/      # Cross-compiled output

Toolchain Packages

Packages that provide toolchain components use the (toolchain) field:

; duniverse/dune
(vendor ocaml.5.2.0
 (toolchain native))

(vendor ocaml-windows.5.2.0
 (toolchain windows))

Dune builds toolchain packages first, before any other packages.

Commands

dune toolchain list           # Show available toolchains
dune toolchain which          # Show active toolchain for context
dune toolchain exec -- ocaml  # Run command with toolchain in PATH

Open Questions

Toolchain lock files

Should toolchains have separate lock files from project dependencies?

dune.lock           # Project dependencies
dune.toolchain.lock # Compiler and build tools

This would allow updating project deps without re-locking the compiler.

Toolchain sharing across workspaces

With relocatable compilers cached globally, multiple workspaces can share the same compiled toolchain. Should dune expose this explicitly?

dune toolchain install ocaml.5.2.0   # Pre-install for sharing

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment