--- name: dune-migration description: Migrating OCaml projects from ocamlbuild/topkg to dune. Use when discussing _tags files, .mllib files, pkg/pkg.ml, topkg, or build system migration. --- # OCaml Build System Migration ## When to Use This Skill Invoke this skill when: - Converting a project from ocamlbuild to dune - Discussing _tags, .mllib, or pkg.ml files - Migrating from topkg to dune - Understanding ocamlbuild artifacts ## Process Overview ### 1. Analyze the Existing Build Read these files to understand the project: - `_tags` - ocamlbuild compilation flags and package dependencies - `pkg/pkg.ml` - topkg package description - `pkg/META` - findlib metadata - `*.mllib` files - module lists for libraries - `opam` - package dependencies ### 2. Create dune-project ```dune (lang dune 3.20) (name ) (generate_opam_files true) ``` ### 3. Create Library dune Files For each library (from `.mllib` files): ```dune (library (name ) (public_name ) (libraries )) ``` For optional libraries (from `pkg/pkg.ml`): ```dune (library (name ) (public_name ) (optional) (libraries )) ``` ### 4. Handle Toplevel Init Files Files like `*_top_init.ml` shouldn't be compiled as modules: ```dune (library (name lib_name) (modules lib_module) ; Explicitly list modules (libraries deps)) (install (package pkg) (section lib) (files lib_top_init.ml)) ``` ### 5. Handle Warnings If the original code triggers warnings: ```dune (library (name lib) (flags (:standard -w -27))) ``` Common warnings to suppress in vendored code: - `-w -27` - unused variable ### 6. Create Test dune File ```dune (test (name test_name) (libraries lib_name alcotest)) ``` For optional tests: ```dune (executable (name test_optional) (modules test_optional) (optional) (libraries lib some_optional_lib)) ``` ### 7. Update opam File 1. Rename `opam` to `.opam` 2. Remove ocamlbuild/topkg dependencies 3. Add dune: ``` depends: [ "ocaml" {>= "4.14.0"} "dune" {>= "3.0"} ] ``` 4. Update build commands: ``` build: [ ["dune" "subst"] {dev} ["dune" "build" "-p" name "-j" jobs] ["dune" "runtest" "-p" name "-j" jobs] {with-test} ["dune" "build" "@doc" "-p" name "-j" jobs] {with-doc} ] ``` ### 8. Documentation dune File If there's a `doc/` directory: ```dune (documentation (package )) ``` ### 9. Remove ocamlbuild Files Files to delete: - `_tags` - `.merlin` - `pkg/pkg.ml` - `pkg/META` - `*.mllib` files - `*.itarget` files - The `pkg/` directory ## Mapping Reference | ocamlbuild | dune | |------------|------| | `_tags: package(foo)` | `(libraries foo)` | | `_tags: thread` | `(libraries threads)` | | `foo.mllib` with `Foo` | `(library (name foo) (modules foo))` | | `pkg/pkg.ml: Pkg.mllib ~cond:x` | `(library ... (optional))` | | `pkg/META` | Auto-generated by dune | | `opam` | `.opam` | ## Common Issues ### "Library not found" for optional deps Use `(optional)` on the library stanza. ### Unused variable warnings Add `(flags (:standard -w -27))`. ### Module in wrong library Use `(modules ...)` to explicitly list modules. ### Toplevel init files Exclude from library with `(modules ...)` and use `(install ...)`. ## Verification After migration: ```bash dune build @check # Verify syntax dune build # Build project dune runtest # Run tests dune build @doc # Build docs ```