Skip to content

Build fails with Unbound module Stdlib when a project uses menhir with package management #15642

Closed
ocaml/opam-repository
#30850

Description

@agarwal

Description

Since dune 3.24, dune pkg lock selects the relocatable compiler by default. In a project that uses package management and contains a (menhir ...) stanza, dune build then fails immediately with:

File "command line", line 1:
Error: Unbound module "Stdlib"

The failing step is menhir's type inference, which runs ocamlc -i over a generated mock module. With --display=short:

      ocamlc parser__mock.mli.inferred (exit 2)

The failure appears with the default repository set and goes away if the relocatable repository is excluded from the solve, which puts the project back on ocaml-base-compiler. Nothing else about the project changes.

Reproduction

I created this minimal example:

$ cat dune
(library
 (name repro))

(menhir
 (modules parser))

$ cat dune-project
(lang dune 3.21)

(using menhir 2.0)

(package
 (name repro)
 (depends
  (ocaml
   (and
    (>= 5.2.0)
    (< 5.3.0)))
  menhir)
 (allow_empty))

$ cat dune-workspace
(lang dune 3.21)

(pkg enabled)

(context default)

$ cat parser.mly
%token <int> INT
%token EOF
%start <int> main

%%

main:
  | i = INT EOF { i + 1 }

Then I ran:

$ dune pkg lock
Solution for dune.lock

Dependencies common to all supported platforms:
- compiler-cloning.enabled
- menhir.20260209
- menhirCST.20260209
- menhirGLR.20260209
- menhirLib.20260209
- menhirSdk.20260209
- ocaml.5.2.2
- ocaml-base-compiler.5.2.2
- ocaml-compiler.5.2.2
- relocatable-compiler.5.2.2.20251109.1

$ dune build
File "command line", line 1:
Error: Unbound module Stdlib

Then, I confirmed I can workaround the issue by updating dune-workspace to exclude the relocatable repository from lock_dir and rebuilding:

$ cat dune-workspace
(lang dune 3.21)

(pkg enabled)

(context default)

(lock_dir
 (repositories
  (:standard \ relocatable)))

$ dune pkg lock
Solution for dune.lock

Dependencies common to all supported platforms:
- menhir.20260209
- menhirCST.20260209
- menhirGLR.20260209
- menhirLib.20260209
- menhirSdk.20260209
- ocaml.5.2.1
- ocaml-base-compiler.5.2.1
- ocaml-config.3

$ dune build
$ echo $?
0

Specifications

$ dune --version
3.24.0

$ dune exec -- ocaml --version
The OCaml toplevel, version 5.2.1  

System: macOS 26.5.2, arm64

Activity

  1. added
    menhirRelated to the internal menhir plugin
    package managementDune's package management — `(pkg)` stanza, lockdirs, `dune pkg` commands
    package management build failuresIssues arising from building a particular opam package under `dune pkg`
    regressionA defect in previously working behavior, generally breaks existing user workflows
    on Aug 2, 2026
  2. added theissue type on Aug 2, 2026
  3. added
    macosIssues that relate to Dune on macOS
    and removed
    regressionA defect in previously working behavior, generally breaks existing user workflows
    on Aug 4, 2026
  4. Alizter commented on Aug 4, 2026

    @Alizter
    Collaborator

    The difference between the relocatable and non-relocatable compiler cases comes down to whether or not the ocamlc binary appears in the workspace or not.

    When dune detects a compiler that is relocatable, it builds it as if it were any other opam package. When it detects a non-relocatable compiler, it builds it in a special external (and sometimes buggy) directory called the "toolchains cache".

    When a rule is sandboxed, dependencies that are resolved inside the workspace are relocated to the sandbox. Typically this means that they will be symlinked inside the sandbox. When dependencies occur outside of the workspace, we don't do this kind of relocation and instead invoke them directly.

    On Linux, when ocamlc resolves itself using something like readlink /proc/self/exe, it does so and observes that it is living inside of _build/_private/default/.pkg/ocaml-compiler-<hash>/bin, from which the relocatable machinary can hop around and find the stdlib. Notably, the fact that ocamlopt itself was run from a symlink inside a sandbox didn't affect it.

    On macos, when ocamlc resolves itself using _NSGetExecutablePath, it does so and observes that it is living at the location of the symlink. It therefore isn't able to hop-around like on linux since there is no sibling lib/ directory to look in.

    This is a classic case of under-specifying your dependencies. The invocation in the menhir rules that does ocamlc -i is relying on the stdlib being present in its usual location relative to the compiler binary. This leads to the error we observe here.

    The fix is to stop invoking ocamlc -i without the relevant stdlib include.

  5. Alizter commented on Aug 4, 2026

    @Alizter
    Collaborator

    Here is a reproduction case and fix: #15679

  6. self-assigned this
    on Aug 18, 2026
  7. shonfeder commented on Sep 11, 2026

    @shonfeder
    Member

    I took the token on this issue from Ali a while back, but have been delayed in advancing my fix due to other responsibilities. I believe I've refined the root cause problem a bit, and have landed on a fix that also addresses the persistent MacOS failure visible on #15679 . It turns out two latent defects are surfacing here: (1) the missing dependency on the stdlib during interface generation and (2) miss-classification of the stdlib path in dune's internal path typing, which can prevent the added stdlib from being installed into the sandbox where the menhir rule is executed. I should have my fix ready for review tomorrow, which builds on and supersedes the draft PR.

  8. shonfeder commented on Sep 25, 2026

    @shonfeder
    Member

    Thanks again for the report @agarwal , and sorry for the somewhat slow turnaround on a fix.

    This is fixed in main now, with #16374 . It will be released in 3.25, but you can try or use it before then with opam pin dune --dev-repo now or tomorrow via the nightly binary build (on MacOS or Linux) once the new daily build is deployed.

  9. added this to the 3.25.0 milestone on Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

macosIssues that relate to Dune on macOSmenhirRelated to the internal menhir pluginpackage management build failuresIssues arising from building a particular opam package under `dune pkg`

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions