Skip to content

test: cross-library .cmi regression baselines (4 fixtures)#14584

Merged
Alizter merged 1 commit into
mainfrom
robinbb-test-cross-lib-soundness-barriers
May 27, 2026
Merged

test: cross-library .cmi regression baselines (4 fixtures)#14584
Alizter merged 1 commit into
mainfrom
robinbb-test-cross-lib-soundness-barriers

Conversation

@robinbb

@robinbb robinbb commented May 18, 2026

Copy link
Copy Markdown
Collaborator

Four fixtures pinning the consumer-compile cmi-dep behaviour today, when the cctx-wide cmi glob over a dep lib's objdir covers the consumer's transitive .cmi needs regardless of whether ocamldep can see the chain syntactically. Each fixture hides the leaf's name from ocamldep through a different mechanism:

  • cross-lib-preprocess-barrier.t(preprocess (action ...))
  • cross-lib-pps-runtime-no-ocamldep-barrier.t(preprocess (pps X)) + ppx_runtime_libraries
  • cross-lib-instrumentation-barrier.t(instrumentation (backend X))
  • cross-lib-open-flag-barrier.t(flags (-open M))

Three of the four assert build success under --sandbox=copy. The instrumentation case additionally pins today's wide cmi glob over middle's objdir in dune rules output.

The forthcoming per-module narrowing work (#14492) will validate that each construct continues to work soundly under tighter per-module dep tracking, and will flip the instrumentation case's jq expected output from "glob present" to "glob absent".

@robinbb robinbb force-pushed the robinbb-test-cross-lib-soundness-barriers branch 2 times, most recently from 7e57b43 to 1b7d59d Compare May 18, 2026 18:02
@robinbb robinbb self-assigned this May 18, 2026
@robinbb robinbb force-pushed the robinbb-test-cross-lib-soundness-barriers branch from 1b7d59d to 3c4514f Compare May 18, 2026 20:31
@robinbb robinbb requested a review from Copilot May 18, 2026 20:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds blackbox regression fixtures under per-module-lib-deps/ to pin today’s “wide .cmi glob” behavior for cross-library compilation dependencies in cases where ocamldep can’t see the full transitive .cmi chain (preprocess/action, ppx runtime deps, instrumentation backend, and -open flags). These baselines are intended to guard upcoming per-module dependency narrowing work (#14492).

Changes:

  • Add a preprocess (action ...) fixture ensuring a consumer build succeeds under --sandbox=copy when only transitive .cmi loads make the leaf needed.
  • Add a ppx runtime-libraries fixture ensuring the consumer build succeeds under --sandbox=copy even when the runtime library is never named in consumer source.
  • Add an instrumentation-backend fixture that snapshots the current .cmi glob present in dune rules JSON output.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/blackbox-tests/test-cases/per-module-lib-deps/cross-lib-preprocess-barrier.t New blackbox test for .cmi dep tracking across an action-preprocessed library under sandbox copy.
test/blackbox-tests/test-cases/per-module-lib-deps/cross-lib-pps-runtime-no-ocamldep-barrier.t/run.t New blackbox test exercising ppx_runtime_libraries-induced compile-time .cmi needs under sandbox copy.
test/blackbox-tests/test-cases/per-module-lib-deps/cross-lib-instrumentation-barrier.t/run.t New blackbox test pinning current instrumentation-disabled behavior and .cmi glob presence in dune rules output.
test/blackbox-tests/test-cases/per-module-lib-deps/cross-lib-instrumentation-barrier.t/ppx/hello.ml Support library for the instrumentation backend fixture.
test/blackbox-tests/test-cases/per-module-lib-deps/cross-lib-instrumentation-barrier.t/ppx/hello_ppx.ml Support ppx rewriter for the instrumentation backend fixture.
test/blackbox-tests/test-cases/per-module-lib-deps/cross-lib-instrumentation-barrier.t/ppx/dune-project Defines the nested hello package for the instrumentation backend fixture.
test/blackbox-tests/test-cases/per-module-lib-deps/cross-lib-instrumentation-barrier.t/ppx/dune Declares the instrumentation backend and its ppx/runtime library.
test/blackbox-tests/test-cases/per-module-lib-deps/cross-lib-open-flag-barrier.t New blackbox test intended to cover -open-hidden transitive .cmi needs under sandbox copy.

@robinbb robinbb force-pushed the robinbb-test-cross-lib-soundness-barriers branch from 3c4514f to 3fb5e95 Compare May 18, 2026 20:57
@robinbb robinbb marked this pull request as ready for review May 18, 2026 22:11
@robinbb robinbb requested a review from Alizter May 18, 2026 22:11
@robinbb

robinbb commented May 18, 2026

Copy link
Copy Markdown
Collaborator Author

@Alizter This is more code that I have factored out of the 9-layer PR 14492.

@robinbb robinbb force-pushed the robinbb-test-cross-lib-soundness-barriers branch from 3fb5e95 to 6b999b2 Compare May 18, 2026 23:17
@robinbb robinbb requested a review from Alizter May 18, 2026 23:18
Four fixtures pinning the consumer-compile cmi-dep behaviour today, when the cctx-wide cmi glob over a dep lib's objdir covers the consumer's transitive `.cmi` needs regardless of whether `ocamldep` can see the chain syntactically. Each fixture hides the leaf's name from `ocamldep` through a different mechanism:

- `cross-lib-preprocess-barrier.t` — `(preprocess (action ...))`
- `cross-lib-pps-runtime-no-ocamldep-barrier.t` — `(preprocess (pps X))` + `ppx_runtime_libraries`
- `cross-lib-instrumentation-barrier.t` — `(instrumentation (backend X))`
- `cross-lib-open-flag-barrier.t` — `(flags (-open M))`

Three of the four assert build success under `--sandbox=copy`. The instrumentation case additionally pins today's wide cmi glob over `middle`'s objdir in `dune rules` output.

The forthcoming per-module narrowing work (#14492) will validate that each construct continues to work soundly under tighter per-module dep tracking, and will flip the instrumentation case's `jq` expected output from "glob present" to "glob absent".

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
@robinbb robinbb force-pushed the robinbb-test-cross-lib-soundness-barriers branch from 6b999b2 to 7e326e9 Compare May 20, 2026 20:33
@Alizter Alizter merged commit 4e6677b into main May 27, 2026
31 checks passed
@Alizter Alizter deleted the robinbb-test-cross-lib-soundness-barriers branch May 27, 2026 19:39
robinbb added a commit to robinbb/dune that referenced this pull request May 29, 2026
Closes a soundness gap in the per-module narrowing pipeline missed
by the wrapped / ppx-runtime / virtual-impl recoveries: when a
dependency library's effective flags inject [-open M], its source
can reference [M]'s identifiers without naming [M], and ocamldep
emits no token to drive the cross-library walker. Both the
library stanza's own [(flags ...)] and any [(env ...)] stanza that
contributes default flags to the dep lib's directory can inject
[-open] entries.

Reported by RyanJamesStewart on ocaml#14517 with this fixture: an
unwrapped [middle] depending on unwrapped [prelude] with
[(flags (:standard -open Prelude))], exposing
[val pick : unit -> color] (where [color] resolves through the open
to [Prelude.color]). The consumer pattern-matches the result
against bare constructors. The compile genuinely needs [prelude.cmi]
to resolve the constructors; the BFS over [ocamldep -modules]
cannot reach [prelude] (no syntactic [Prelude] token on either
side); the three existing recoveries do not catch it ([prelude] is
not wrapped, not a ppx-runtime lib, not a virtual-impl).

[Module_compilation.cross_lib_tight_set]:
- Add [~mode] (the consumer's compile mode) so we can expand a dep
  lib's effective flags via [Ocaml_flags.get].
- Extend [read_entry_deps] to compute [read_lib_opens] for the
  visited lib and union the result into the BFS frontier. Localised
  in the BFS rather than the initial-frontier computation so the
  reachability rule reads as: a module is reachable iff the consumer
  references it, or some reached module's ocamldep names it, or some
  reached module's owning lib's effective flags open it.
- [read_lib_opens] short-circuits to empty for non-local libs; their
  [src_dir] is not a build path, and env stanzas cannot inject flags
  into already-compiled artifacts. For local libs we evaluate
  [Ocaml_flags_db.ocaml_flags] which folds env-stanza flags under the
  library stanza's spec, so both injection paths are captured even
  when the library stanza is [:standard].

[Lib_info]:
- Add [stanza_flags : Dune_lang.Ocaml_flags.Spec.t] field plus
  accessor. Local libs carry their stanza's [conf.buildable.flags];
  external libs ([findlib], [dune_package]) carry [Spec.standard].

Regression tests on `main` that this patch makes pass under the
per-module narrowing stack:
- [cross-lib-open-flag-barrier.t] (added by ocaml#14584) pins the
  stanza-flag injection path. Fails on L4 and L5 head before this
  patch (Unbound constructor Green under [--sandbox=copy]); passes
  after.
- [cross-lib-env-open-flag-barrier.t] (added by ocaml#14776) pins the
  env-stanza injection path: same shape, but [-open Prelude] is
  supplied by an [(env ...)] stanza while the library stanza uses
  [:standard]. Fails on the pre-ocaml#14517 [:standard]-short-circuit
  variant of this patch (same Unbound constructor error); passes
  after.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
Alizter pushed a commit that referenced this pull request May 30, 2026
Fifth fixture in the cross-lib `.cmi` regression baseline family
(#14584): pins consumer-compile cmi-dep behaviour when `-open M`
is injected by an `(env ...)` stanza rather than the intermediate
library's own `(flags ...)` field. The intermediate's library
stanza uses `:standard`. Asserts build success under
`--sandbox=copy`.

The forthcoming per-module narrowing work (#14492) will validate
that this construct continues to work soundly under tighter
per-module dep tracking.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
Alizter added a commit that referenced this pull request May 30, 2026
…14776)

## Summary

Fifth fixture in the cross-lib `.cmi` regression baseline family started
by #14584. Pins consumer-compile `.cmi` dep behaviour when `-open M` is
injected by an `(env ...)` stanza rather than the intermediate library's
own `(flags ...)` field. The intermediate's library stanza uses
`:standard`. Asserts build success under `--sandbox=copy`.

Pairs with the stanza-flag variant `cross-lib-open-flag-barrier.t`
already on `main` from #14584, covering the second of the two `-open`
injection paths.

The forthcoming per-module narrowing work (#14492) will validate that
this construct continues to work soundly under tighter per-module dep
tracking.
robinbb added a commit that referenced this pull request Jun 8, 2026
Closes a soundness gap in the per-module narrowing pipeline missed
by the wrapped / ppx-runtime / virtual-impl recoveries: when a
dependency library's effective flags inject [-open M], its source
can reference [M]'s identifiers without naming [M], and ocamldep
emits no token to drive the cross-library walker. Both the
library stanza's own [(flags ...)] and any [(env ...)] stanza that
contributes default flags to the dep lib's directory can inject
[-open] entries.

Reported by RyanJamesStewart on #14517 with this fixture: an
unwrapped [middle] depending on unwrapped [prelude] with
[(flags (:standard -open Prelude))], exposing
[val pick : unit -> color] (where [color] resolves through the open
to [Prelude.color]). The consumer pattern-matches the result
against bare constructors. The compile genuinely needs [prelude.cmi]
to resolve the constructors; the BFS over [ocamldep -modules]
cannot reach [prelude] (no syntactic [Prelude] token on either
side); the three existing recoveries do not catch it ([prelude] is
not wrapped, not a ppx-runtime lib, not a virtual-impl).

[Module_compilation.cross_lib_tight_set]:
- Add [~mode] (the consumer's compile mode) so we can expand a dep
  lib's effective flags via [Ocaml_flags.get].
- Extend [read_entry_deps] to compute [read_lib_opens] for the
  visited lib and union the result into the BFS frontier. Localised
  in the BFS rather than the initial-frontier computation so the
  reachability rule reads as: a module is reachable iff the consumer
  references it, or some reached module's ocamldep names it, or some
  reached module's owning lib's effective flags open it.
- [read_lib_opens] short-circuits to empty for non-local libs; their
  [src_dir] is not a build path, and env stanzas cannot inject flags
  into already-compiled artifacts. For local libs we evaluate
  [Ocaml_flags_db.ocaml_flags] which folds env-stanza flags under the
  library stanza's spec, so both injection paths are captured even
  when the library stanza is [:standard].

[Lib_info]:
- Add [stanza_flags : Dune_lang.Ocaml_flags.Spec.t] field plus
  accessor. Local libs carry their stanza's [conf.buildable.flags];
  external libs ([findlib], [dune_package]) carry [Spec.standard].

Regression tests on `main` that this patch makes pass under the
per-module narrowing stack:
- [cross-lib-open-flag-barrier.t] (added by #14584) pins the
  stanza-flag injection path. Fails on L4 and L5 head before this
  patch (Unbound constructor Green under [--sandbox=copy]); passes
  after.
- [cross-lib-env-open-flag-barrier.t] (added by #14776) pins the
  env-stanza injection path: same shape, but [-open Prelude] is
  supplied by an [(env ...)] stanza while the library stanza uses
  [:standard]. Fails on the pre-#14517 [:standard]-short-circuit
  variant of this patch (same Unbound constructor error); passes
  after.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb added a commit that referenced this pull request Jun 8, 2026
Closes a soundness gap in the per-module narrowing pipeline missed
by the wrapped / ppx-runtime / virtual-impl recoveries: when a
dependency library's effective flags inject [-open M], its source
can reference [M]'s identifiers without naming [M], and ocamldep
emits no token to drive the cross-library walker. Both the
library stanza's own [(flags ...)] and any [(env ...)] stanza that
contributes default flags to the dep lib's directory can inject
[-open] entries.

Reported by RyanJamesStewart on #14517 with this fixture: an
unwrapped [middle] depending on unwrapped [prelude] with
[(flags (:standard -open Prelude))], exposing
[val pick : unit -> color] (where [color] resolves through the open
to [Prelude.color]). The consumer pattern-matches the result
against bare constructors. The compile genuinely needs [prelude.cmi]
to resolve the constructors; the BFS over [ocamldep -modules]
cannot reach [prelude] (no syntactic [Prelude] token on either
side); the three existing recoveries do not catch it ([prelude] is
not wrapped, not a ppx-runtime lib, not a virtual-impl).

[Module_compilation.cross_lib_tight_set]:
- Add [~mode] (the consumer's compile mode) so we can expand a dep
  lib's effective flags via [Ocaml_flags.get].
- Extend [read_entry_deps] to compute [read_lib_opens] for the
  visited lib and union the result into the BFS frontier. Localised
  in the BFS rather than the initial-frontier computation so the
  reachability rule reads as: a module is reachable iff the consumer
  references it, or some reached module's ocamldep names it, or some
  reached module's owning lib's effective flags open it.
- [read_lib_opens] short-circuits to empty for non-local libs; their
  [src_dir] is not a build path, and env stanzas cannot inject flags
  into already-compiled artifacts. For local libs we evaluate
  [Ocaml_flags_db.ocaml_flags] which folds env-stanza flags under the
  library stanza's spec, so both injection paths are captured even
  when the library stanza is [:standard].

[Lib_info]:
- Add [stanza_flags : Dune_lang.Ocaml_flags.Spec.t] field plus
  accessor. Local libs carry their stanza's [conf.buildable.flags];
  external libs ([findlib], [dune_package]) carry [Spec.standard].

Regression tests on `main` that this patch makes pass under the
per-module narrowing stack:
- [cross-lib-open-flag-barrier.t] (added by #14584) pins the
  stanza-flag injection path. Fails on L4 and L5 head before this
  patch (Unbound constructor Green under [--sandbox=copy]); passes
  after.
- [cross-lib-env-open-flag-barrier.t] (added by #14776) pins the
  env-stanza injection path: same shape, but [-open Prelude] is
  supplied by an [(env ...)] stanza while the library stanza uses
  [:standard]. Fails on the pre-#14517 [:standard]-short-circuit
  variant of this patch (same Unbound constructor error); passes
  after.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb added a commit to robinbb/dune that referenced this pull request Jun 8, 2026
A fifth sibling to the cross-library `.cmi` regression baselines (ocaml#14584), covering `(flags (-open Prelude.Color))` where the intermediate library opens a *dotted* module path naming a submodule of a wrapped dependency, rather than a bare top-level module.

As in `cross-lib-open-flag-barrier.t`, the intermediate's source never names `Prelude` (the open hides it) and the consumer never names it either, so `ocamldep` sees no syntactic chain to `prelude`. The fixture asserts build success under `--sandbox=copy`, pinning that the consumer's compile tracks `prelude`'s `.cmi`s.

The forthcoming per-module narrowing work (ocaml#14492) must key its effective-`-open` detection on the head component of the path (`Prelude` from `Prelude.Color`), since only top-level module names map to libraries; without that, the dotted open would be dropped from the cross-library frontier and the sandboxed build would regress.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb added a commit that referenced this pull request Jun 8, 2026
A fifth sibling to the cross-library `.cmi` regression baselines (#14584), covering `(flags (-open Prelude.Color))` where the intermediate library opens a *dotted* module path naming a submodule of a wrapped dependency, rather than a bare top-level module.

As in `cross-lib-open-flag-barrier.t`, the intermediate's source never names `Prelude` (the open hides it) and the consumer never names it either, so `ocamldep` sees no syntactic chain to `prelude`. The fixture asserts build success under `--sandbox=copy`, pinning that the consumer's compile tracks `prelude`'s `.cmi`s.

The forthcoming per-module narrowing work (#14492) must key its effective-`-open` detection on the head component of the path (`Prelude` from `Prelude.Color`), since only top-level module names map to libraries; without that, the dotted open would be dropped from the cross-library frontier and the sandboxed build would regress.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb added a commit that referenced this pull request Jun 8, 2026
Closes a soundness gap in the per-module narrowing pipeline missed
by the wrapped / ppx-runtime / virtual-impl recoveries: when a
dependency library's effective flags inject [-open M], its source
can reference [M]'s identifiers without naming [M], and ocamldep
emits no token to drive the cross-library walker. Both the
library stanza's own [(flags ...)] and any [(env ...)] stanza that
contributes default flags to the dep lib's directory can inject
[-open] entries.

Reported by RyanJamesStewart on #14517 with this fixture: an
unwrapped [middle] depending on unwrapped [prelude] with
[(flags (:standard -open Prelude))], exposing
[val pick : unit -> color] (where [color] resolves through the open
to [Prelude.color]). The consumer pattern-matches the result
against bare constructors. The compile genuinely needs [prelude.cmi]
to resolve the constructors; the BFS over [ocamldep -modules]
cannot reach [prelude] (no syntactic [Prelude] token on either
side); the three existing recoveries do not catch it ([prelude] is
not wrapped, not a ppx-runtime lib, not a virtual-impl).

[Module_compilation.cross_lib_tight_set]:
- Add [~mode] (the consumer's compile mode) so we can expand a dep
  lib's effective flags via [Ocaml_flags.get].
- Extend [read_entry_deps] to compute [read_lib_opens] for the
  visited lib and union the result into the BFS frontier. Localised
  in the BFS rather than the initial-frontier computation so the
  reachability rule reads as: a module is reachable iff the consumer
  references it, or some reached module's ocamldep names it, or some
  reached module's owning lib's effective flags open it.
- [read_lib_opens] short-circuits to empty for non-local libs; their
  [src_dir] is not a build path, and env stanzas cannot inject flags
  into already-compiled artifacts. For local libs we evaluate
  [Ocaml_flags_db.ocaml_flags] which folds env-stanza flags under the
  library stanza's spec, so both injection paths are captured even
  when the library stanza is [:standard].

[Lib_info]:
- Add [stanza_flags : Dune_lang.Ocaml_flags.Spec.t] field plus
  accessor. Local libs carry their stanza's [conf.buildable.flags];
  external libs ([findlib], [dune_package]) carry [Spec.standard].

Regression tests on `main` that this patch makes pass under the
per-module narrowing stack:
- [cross-lib-open-flag-barrier.t] (added by #14584) pins the
  stanza-flag injection path. Fails on L4 and L5 head before this
  patch (Unbound constructor Green under [--sandbox=copy]); passes
  after.
- [cross-lib-env-open-flag-barrier.t] (added by #14776) pins the
  env-stanza injection path: same shape, but [-open Prelude] is
  supplied by an [(env ...)] stanza while the library stanza uses
  [:standard]. Fails on the pre-#14517 [:standard]-short-circuit
  variant of this patch (same Unbound constructor error); passes
  after.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb added a commit to robinbb/dune that referenced this pull request Jun 8, 2026
A sibling to the cross-library `.cmi` regression baselines (ocaml#14584), covering two chained opens `(flags (-open Prelude -open Color))` where the second argument resolves through the first: `Color` is the `Color` submodule of the wrapped dependency `prelude`, brought into scope by `-open Prelude`, not a top-level module.

As in `cross-lib-open-flag-barrier.t`, the intermediate's source names neither `Prelude` nor `Color`, so `ocamldep` sees no syntactic chain to `prelude`. The fixture asserts build success under `--sandbox=copy`, pinning that the consumer's compile tracks `prelude`'s `.cmi`s.

Per-module narrowing (ocaml#14492) must stay sound when an `-open` argument is not a compilation unit: here `-open Prelude` already reaches `prelude`, covering `Color`'s contents.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb added a commit that referenced this pull request Jun 8, 2026
A sibling to the cross-library `.cmi` regression baselines (#14584), covering two chained opens `(flags (-open Prelude -open Color))` where the second argument resolves through the first: `Color` is the `Color` submodule of the wrapped dependency `prelude`, brought into scope by `-open Prelude`, not a top-level module.

As in `cross-lib-open-flag-barrier.t`, the intermediate's source names neither `Prelude` nor `Color`, so `ocamldep` sees no syntactic chain to `prelude`. The fixture asserts build success under `--sandbox=copy`, pinning that the consumer's compile tracks `prelude`'s `.cmi`s.

Per-module narrowing (#14492) must stay sound when an `-open` argument is not a compilation unit: here `-open Prelude` already reaches `prelude`, covering `Color`'s contents.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb added a commit that referenced this pull request Jun 8, 2026
Closes a soundness gap in the per-module narrowing pipeline missed
by the wrapped / ppx-runtime / virtual-impl recoveries: when a
dependency library's effective flags inject [-open M], its source
can reference [M]'s identifiers without naming [M], and ocamldep
emits no token to drive the cross-library walker. Both the
library stanza's own [(flags ...)] and any [(env ...)] stanza that
contributes default flags to the dep lib's directory can inject
[-open] entries.

Reported by RyanJamesStewart on #14517 with this fixture: an
unwrapped [middle] depending on unwrapped [prelude] with
[(flags (:standard -open Prelude))], exposing
[val pick : unit -> color] (where [color] resolves through the open
to [Prelude.color]). The consumer pattern-matches the result
against bare constructors. The compile genuinely needs [prelude.cmi]
to resolve the constructors; the BFS over [ocamldep -modules]
cannot reach [prelude] (no syntactic [Prelude] token on either
side); the three existing recoveries do not catch it ([prelude] is
not wrapped, not a ppx-runtime lib, not a virtual-impl).

[Module_compilation.cross_lib_tight_set]:
- Add [~mode] (the consumer's compile mode) so we can expand a dep
  lib's effective flags via [Ocaml_flags.get].
- Extend [read_entry_deps] to compute [read_lib_opens] for the
  visited lib and union the result into the BFS frontier. Localised
  in the BFS rather than the initial-frontier computation so the
  reachability rule reads as: a module is reachable iff the consumer
  references it, or some reached module's ocamldep names it, or some
  reached module's owning lib's effective flags open it.
- [read_lib_opens] short-circuits to empty for non-local libs; their
  [src_dir] is not a build path, and env stanzas cannot inject flags
  into already-compiled artifacts. For local libs we evaluate
  [Ocaml_flags_db.ocaml_flags] which folds env-stanza flags under the
  library stanza's spec, so both injection paths are captured even
  when the library stanza is [:standard].

[Lib_info]:
- Add [stanza_flags : Dune_lang.Ocaml_flags.Spec.t] field plus
  accessor. Local libs carry their stanza's [conf.buildable.flags];
  external libs ([findlib], [dune_package]) carry [Spec.standard].

Regression tests on `main` that this patch makes pass under the
per-module narrowing stack:
- [cross-lib-open-flag-barrier.t] (added by #14584) pins the
  stanza-flag injection path. Fails on L4 and L5 head before this
  patch (Unbound constructor Green under [--sandbox=copy]); passes
  after.
- [cross-lib-env-open-flag-barrier.t] (added by #14776) pins the
  env-stanza injection path: same shape, but [-open Prelude] is
  supplied by an [(env ...)] stanza while the library stanza uses
  [:standard]. Fails on the pre-#14517 [:standard]-short-circuit
  variant of this patch (same Unbound constructor error); passes
  after.

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb added a commit that referenced this pull request Jun 9, 2026
## Summary

A fifth sibling to the cross-library `.cmi` regression baselines from
#14584, covering an intermediate library compiled with `(flags (-open
Prelude.Color))` — a *dotted* module path naming a submodule of a
wrapped dependency, rather than a bare top-level module.

The fixture asserts build success under `--sandbox=copy`. It builds on
`main` today (no per-module narrowing) and pins behaviour that the
per-module narrowing work in #14492 must preserve: the effective-`-open`
detection has to key on the head component of the path (`Prelude` from
`Prelude.Color`), since only top-level module names map to libraries.
Without that, the dotted open is dropped from the cross-library frontier
and the sandboxed build regresses.

Test-only; no changelog.

---------

Signed-off-by: Robin Bate Boerop <me@robinbb.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants