test: observational baseline for over-rebuilds under implicit_transitive_deps=false#14350
Merged
Alizter merged 5 commits intoApr 29, 2026
Merged
Conversation
5c1c3c2 to
6d37749
Compare
There was a problem hiding this comment.
Pull request overview
Adds a blackbox regression test to ensure that with (implicit_transitive_deps false), a transitive link-only library change does not trigger recompilation of a consumer that cannot see that transitive library via -I/-H.
Changes:
- Introduces a new per-module dependency blackbox test case covering the “link-only transitive dep” scenario under
implicit_transitive_deps=false. - Asserts that editing the transitive library does not cause rebuilds of the consumer module.
6d37749 to
0cd3bb1
Compare
ba90ae7 to
08b85f5
Compare
08b85f5 to
49d37ca
Compare
…ps=false Records that under [(implicit_transitive_deps false)], a transitive link-only library does NOT trigger a consumer rebuild when its source changes — the consumer cannot see it through [-I] or [-H], so the compile rule must not depend on its objdir. Trunk satisfies this property today: the compile-rule deps are restricted to libs in [direct_requires + hidden_requires], so a purely-link-only transitive lib doesn't enter the deps. The test asserts count = 0 and passes on [main]. Pre-emptive guard against changes that would expand a consumer's compile-rule deps via [Lib.closure] (or a similar transitive walk) without re-restricting to the cctx's compile scope. Reported by @nojb in ocaml#14116 (comment) where an early version of ocaml#14116 violated this property. Signed-off-by: Robin Bate Boerop <me@robinbb.com>
…-false] Caught while diagnosing ocaml#14116 (comment): the prior version of this test edited [link_only_module.ml] from [let x = 42] to [let x = 43]. Both produce the same [.cmi] (the exported signature [val x : int] is unchanged), so dune's content-hash invalidation didn't fire any glob over the lib's objdir — even when the consumer's compile-rule deps incorrectly included such a glob. The test passed on a binary that was actually broken, masking the bug. Switched to [echo > link_only_module.ml] which empties the file, removing the [val x] binding from the exported signature so the [.cmi] content actually changes. Combined with reframing the assertion as an observational baseline (count = 2 on trunk, the two [Main.cmi]/[Main.cmo] rebuilds the cctx-wide glob causes), the test now empirically reflects trunk's current behaviour and gives ocaml#14116 something to flip when its per-module filter narrows the deps. Audit of the other [robinbb-test-*] branches confirmed no other test relies on the same weak-edit pattern: every other [count = 0] / [[]] assertion either edits a [.mli] (signature- changing) or a [.ml] of a module without [.mli] while adding a new top-level binding. Signed-off-by: Robin Bate Boerop <me@robinbb.com>
…itive-deps-false]
[| length] hides which targets actually re-ran — a future change
that swaps one expected target for a different one (e.g. the
[.cmo]/[.cmt] rule skipped, replaced by [.cmx]/[.o]) would still
pass [length = 2]. Inspecting the array of [{ target_files }]
records each rule's exact outputs, so any divergence from the
documented post-build state shows up as a cram diff.
This pattern is consistent with other tests in this cluster that
already match against the full target list (e.g. [alias-reexport.t]
asserting [[]] for the no-rebuild case rather than [length 0]).
Signed-off-by: Robin Bate Boerop <me@robinbb.com>
49d37ca to
e800109
Compare
@check's deps are gated on [Context.merlin] (see all three [add_*] functions in [src/dune_rules/check_rules.ml]). Under any workspace configuration that disables merlin, [dune build @check] is a no-op and the post-edit trace assertion would pass vacuously — the over-rebuild this test exists to record would go silent. Switching to [./main.exe] forces compilation regardless of the merlin gating. The expected [target_files] arrays change from [.cmo]/[.cmt] (bytecode, fired via @check) to [.cmx]/[.o] (native, fired via the explicit native exe target). Reported in review. Signed-off-by: Robin Bate Boerop <me@robinbb.com>
Alizter
reviewed
Apr 29, 2026
Alizter
approved these changes
Apr 29, 2026
The [-H]-glob path this test exercises is reached only when [(implicit_transitive_deps false)] resolves to mode [Disabled_with_hidden_includes] — which requires dune lang [3.17+] plus OCaml [5.2+] hidden-includes support (gated in [src/dune_lang/dune_project.ml]'s [Implicit_transitive_deps.mode]). Older dune lang versions fall back to mode [Disabled] without [-H] and don't exhibit the over-rebuild recorded here. Spell that out in the prose so a reader doesn't wonder whether the test should also run under the older behaviour. Addresses Alizter's review feedback: ocaml#14350 (comment) Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb
added a commit
to robinbb/dune
that referenced
this pull request
Apr 29, 2026
Three cluster tests landed on main as observational baselines (via PRs ocaml#14308, ocaml#14331, ocaml#14350) recording the trunk-today rebuild list. With this PR's per-module filter applied, the [.cmi]/[.cmti] byte rule no longer globs over a dep lib's objdir for unreferenced sibling modules, so: - [single-module-unreferenced-lib.t]: [spurious_rebuild]'s rebuild count drops from 1 to 0. - [opaque-mli-change.t]: only the [.cmx]/[.o] native rule re-runs (release and dev profile both); the byte rule's deps no longer include the changed dep lib's [.cmi]. - [implicit-transitive-deps-false.t]: same — the [.cmx]/[.o] native rule re-runs, the byte rule does not. Promote the asserted [target_files] arrays accordingly. No behavioural surprise here — all three drops match the design of the per-module filter; the upstream baselines exist specifically to be flipped by this PR. Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb
added a commit
to robinbb/dune
that referenced
this pull request
Apr 29, 2026
Cluster tests landed on main as observational baselines (via PRs ocaml#14308, ocaml#14331, ocaml#14350, and the transitive-unreferenced-module follow-up) recording the trunk rebuild list. With this PR's per-module filter applied, the [.cmi]/[.cmti] byte rule no longer globs over a dep lib's objdir for unreferenced sibling modules, so: - [single-module-unreferenced-lib.t]: [spurious_rebuild]'s rebuild count drops from 1 to 0. - [opaque-mli-change.t]: only the [.cmx]/[.o] native rule re-runs (release and dev profile both); the byte rule's deps no longer include the changed dep lib's [.cmi]. - [implicit-transitive-deps-false.t]: same — the [.cmx]/[.o] native rule re-runs, the byte rule does not. - [transitive-unreferenced-module.t]: the consumer doesn't even directly reference the transitive lib, so the filter drops it entirely; both rules are skipped, [target_files] becomes [[]]. Promote the asserted [target_files] arrays accordingly. No behavioural surprise here — all four drops match the design of the per-module filter; the upstream baselines exist specifically to be flipped by this PR. Signed-off-by: Robin Bate Boerop <me@robinbb.com>
robinbb
added a commit
to robinbb/dune
that referenced
this pull request
Apr 29, 2026
Cluster tests landed on main as observational baselines (via PRs ocaml#14308, ocaml#14331, ocaml#14350, and the transitive-unreferenced-module follow-up) recording the trunk rebuild list. With this PR's per-module filter applied, the [.cmi]/[.cmti] byte rule no longer globs over a dep lib's objdir for unreferenced sibling modules, so: - [single-module-unreferenced-lib.t]: [spurious_rebuild]'s rebuild count drops from 1 to 0. - [opaque-mli-change.t]: only the [.cmx]/[.o] native rule re-runs (release and dev profile both); the byte rule's deps no longer include the changed dep lib's [.cmi]. - [implicit-transitive-deps-false.t]: same — the [.cmx]/[.o] native rule re-runs, the byte rule does not. - [transitive-unreferenced-module.t]: the consumer doesn't even directly reference the transitive lib, so the filter drops it entirely; both rules are skipped, [target_files] becomes [[]]. Promote the asserted [target_files] arrays accordingly. No behavioural surprise here — all four drops match the design of the per-module filter; the upstream baselines exist specifically to be flipped by this PR. Signed-off-by: Robin Bate Boerop <me@robinbb.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Observational baseline. Under
(implicit_transitive_deps false), atransitive link-only library should not trigger a consumer rebuild
when its source changes — the consumer cannot see it through
-Ior
-H, so the compile rule should not depend on its objdir.Trunk does not yet satisfy this property: the cctx-wide glob
over
link_only_lib's objdir invalidates Main on any.cmicontent change in the link-only library. This test records the
current rebuild targets for Main as a baseline that a future
per-module dep filter (#14116) can promote to
[].The earlier draft of this PR asserted
count = 0and was reportedto pass on
main; commit9948ed896("strengthen the.cmiperturbation") replaced the weak edit (
let x = 42→let x = 43,which produces an identical
.cmi) withecho > link_only_module.ml(which empties the binding). Under the strengthened perturbation
the property fails on trunk, and the test was reframed as an
observational baseline rather than a regression guard.
Reported by @nojb in
#14116 (comment),
where an early version of #14116 violated this property and was
later fixed.