From 5649795e6e0d22c9c8071d4cd1ff1781cd5ee1b2 Mon Sep 17 00:00:00 2001 From: Antonio Nuno Monteiro Date: Sun, 28 Jun 2026 22:38:09 -0700 Subject: [PATCH] fix(melange): stage wrapped root deps for JS emission in the sandbox Signed-off-by: Antonio Nuno Monteiro --- src/dune_rules/melange/melange_rules.ml | 19 ++++++++++++++----- .../melange/cross-module-opt-deps.t | 6 ++---- .../emit-local-transitive-private-module.t | 1 + 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/dune_rules/melange/melange_rules.ml b/src/dune_rules/melange/melange_rules.ml index 12552581d5b..4cc918235b8 100644 --- a/src/dune_rules/melange/melange_rules.ml +++ b/src/dune_rules/melange/melange_rules.ml @@ -246,6 +246,14 @@ let make_same_lib_emission_deps = |> Action_builder.map ~f:melange_cross_module_opt_enabled in let dep_graph = impl_dep_graph ~sctx ~obj_dir ~modules in + let lib_interface_deps = + (* The Melange emitter loads the library interface/root artifact when + emitting wrapped units such as [Stdlib__Char], even if the source + dependency graph does not mention [Stdlib] explicitly. *) + Modules.With_vlib.lib_interface modules + |> Option.map ~f:(fun m -> deps_of_xopt_closure ~obj_dir [ m ]) + |> Option.value ~default:Dep.Set.empty + in fun module_ -> let open Action_builder.O in xopt_enabled @@ -264,11 +272,11 @@ let make_same_lib_emission_deps = module_ in (* Cross-module optimization follows implementation artifacts, but the - initial reachability also comes from the emitted module's interface - dependencies. Seed the implementation graph with that interface - closure so wrappers such as [Stdlib] stay visible to the emitter. *) + initial reachability also comes from the emitted module's interface + dependencies. *) Dep_graph.top_closed_implementations dep_graph (module_ :: intf_deps) - |> Action_builder.map ~f:(deps_of_xopt_closure ~obj_dir) + |> Action_builder.map ~f:(fun deps -> + Dep.Set.union lib_interface_deps (deps_of_xopt_closure ~obj_dir deps)) | false -> (* Emission reads same-library implementation artifacts recursively. Compilation dependencies collapse transitive edges through interfaces @@ -276,7 +284,8 @@ let make_same_lib_emission_deps = emission. Follow the implementation dependency graph directly instead. *) Dep_graph.top_closed_implementations dep_graph [ module_ ] - |> Action_builder.map ~f:(deps_of_closure ~obj_dir ~kind:Cmj) + |> Action_builder.map ~f:(fun deps -> + Dep.Set.union lib_interface_deps (deps_of_closure ~obj_dir ~kind:Cmj deps)) ;; let make_external_lib_emission_deps = diff --git a/test/blackbox-tests/test-cases/melange/cross-module-opt-deps.t b/test/blackbox-tests/test-cases/melange/cross-module-opt-deps.t index 8b248694191..91d459f5202 100644 --- a/test/blackbox-tests/test-cases/melange/cross-module-opt-deps.t +++ b/test/blackbox-tests/test-cases/melange/cross-module-opt-deps.t @@ -76,10 +76,8 @@ repeat the library's `--mel-cross-module-opt` compile flag. $ dune describe rules --display=quiet --profile=release dist-default-flags/node_modules/foo/char.js > char-default-rules.sexp $ grep -c 'stdlib/.stdlib.objs/melange/stdlib.cmi' char-default-rules.sexp - 0 - [1] + 1 $ grep -c 'stdlib/.stdlib.objs/melange/stdlib.cmj' char-default-rules.sexp - 0 - [1] + 1 $ dune build dist-default-flags/node_modules/foo/char.js diff --git a/test/blackbox-tests/test-cases/melange/emit-local-transitive-private-module.t b/test/blackbox-tests/test-cases/melange/emit-local-transitive-private-module.t index 3cb920e9a53..682d398190b 100644 --- a/test/blackbox-tests/test-cases/melange/emit-local-transitive-private-module.t +++ b/test/blackbox-tests/test-cases/melange/emit-local-transitive-private-module.t @@ -15,6 +15,7 @@ transitive implementation closure, even across `.mli` boundaries. $ dune rules --root . --format=json --deps app/dist/node_modules/repro.foo/foo_map.js | > jq_dune -r '.[] | depsFilePaths | select(test("lib/\\.foo\\.objs/melange/.*\\.cmj$")) | sub("^_build/default/"; "")' + lib/.foo.objs/melange/foo.cmj lib/.foo.objs/melange/foo__Foo_internalAVLtree.cmj lib/.foo.objs/melange/foo__Foo_internalMapInt.cmj lib/.foo.objs/melange/foo__Foo_map.cmj