Skip to content

Commit fa3d4c3

Browse files
committed
fix: run ocamldep for single-module stanzas (#4572)
Dune previously skipped ocamldep for singleton stanzas as an optimization (no intra-stanza deps to compute). This prevented per-module library dependency filtering from working, since it relies on ocamldep output to determine which libraries a module references. Remove the singleton shortcut from dep_rules.ml so ocamldep runs for all stanzas. The cost is negligible (one extra ocamldep invocation per single-module stanza) and enables the filtering optimization for all cases. Signed-off-by: Robin Bate Boerop <me@robinbb.com>
1 parent 7fd7b21 commit fa3d4c3

5 files changed

Lines changed: 23 additions & 40 deletions

File tree

src/dune_rules/dep_rules.ml

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,6 @@ let deps_of_vlib_module ~obj_dir ~vimpl ~dir ~sctx ~ml_kind ~for_ sourced_module
131131
Ocamldep.read_deps_of ~obj_dir:vlib_obj_dir ~modules ~ml_kind ~for_ m
132132
;;
133133

134-
(** Tests whether a set of modules is a singleton *)
135-
let has_single_file modules = Option.is_some @@ Modules.With_vlib.as_singleton modules
136-
137134
let rec deps_of
138135
~obj_dir
139136
~modules
@@ -153,7 +150,7 @@ let rec deps_of
153150
| Root | Alias _ -> true
154151
| _ -> false)
155152
in
156-
if is_alias_or_root || has_single_file modules
153+
if is_alias_or_root
157154
then Memo.return (Action_builder.return [])
158155
else (
159156
let skip_if_source_absent f sourced_module =
@@ -195,18 +192,15 @@ let read_deps_of_module ~modules ~obj_dir dep ~for_ =
195192
in
196193
List.singleton interface_module |> Action_builder.return
197194
| _ ->
198-
if has_single_file modules
199-
then Action_builder.return []
200-
else (
201-
match dep with
202-
| Immediate (unit, ml_kind) ->
203-
Ocamldep.read_immediate_deps_of ~obj_dir ~modules ~ml_kind ~for_ unit
204-
| Transitive (unit, ml_kind) ->
205-
let open Action_builder.O in
206-
let+ deps = Ocamldep.read_deps_of ~obj_dir ~modules ~ml_kind ~for_ unit in
207-
(match Modules.With_vlib.alias_for modules unit with
208-
| [] -> deps
209-
| aliases -> aliases @ deps))
195+
(match dep with
196+
| Immediate (unit, ml_kind) ->
197+
Ocamldep.read_immediate_deps_of ~obj_dir ~modules ~ml_kind ~for_ unit
198+
| Transitive (unit, ml_kind) ->
199+
let open Action_builder.O in
200+
let+ deps = Ocamldep.read_deps_of ~obj_dir ~modules ~ml_kind ~for_ unit in
201+
(match Modules.With_vlib.alias_for modules unit with
202+
| [] -> deps
203+
| aliases -> aliases @ deps))
210204
;;
211205

212206
let read_immediate_deps_of ~obj_dir ~modules ~ml_kind ~for_ m =
@@ -231,15 +225,12 @@ let for_module ~obj_dir ~modules ~sandbox ~impl ~dir ~sctx ~for_ module_ =
231225
;;
232226

233227
let rules ~obj_dir ~modules ~sandbox ~impl ~sctx ~dir ~for_ =
234-
match Modules.With_vlib.as_singleton modules with
235-
| Some m -> Memo.return (Dep_graph.Ml_kind.dummy m)
236-
| None ->
237-
dict_of_func_concurrently (fun ~ml_kind ->
238-
let+ per_module =
239-
Modules.With_vlib.obj_map modules
240-
|> Parallel_map.parallel_map ~f:(fun _obj_name m ->
241-
deps_of ~obj_dir ~modules ~sandbox ~impl ~sctx ~dir ~ml_kind ~for_ m)
242-
in
243-
Dep_graph.make ~dir ~per_module)
244-
|> Memo.map ~f:(Dep_graph.Ml_kind.for_module_compilation ~modules)
228+
dict_of_func_concurrently (fun ~ml_kind ->
229+
let+ per_module =
230+
Modules.With_vlib.obj_map modules
231+
|> Parallel_map.parallel_map ~f:(fun _obj_name m ->
232+
deps_of ~obj_dir ~modules ~sandbox ~impl ~sctx ~dir ~ml_kind ~for_ m)
233+
in
234+
Dep_graph.make ~dir ~per_module)
235+
|> Memo.map ~f:(Dep_graph.Ml_kind.for_module_compilation ~modules)
245236
;;

test/blackbox-tests/test-cases/per-module-lib-deps/single-module-lib.t

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Per-module filtering does not help single-module library consumers.
1+
Per-module filtering works for single-module library consumers.
22

33
When a consumer library has only one module, dune skips ocamldep for that
44
stanza. Without ocamldep data, the per-module filtering has nothing to work
@@ -59,8 +59,8 @@ Modify only the unused module:
5959
> let new_fn () = "new"
6060
> EOF
6161

62-
uses_alpha is recompiled even though it only references Alpha, not Unused:
62+
uses_alpha is no longer recompiled because it only references Alpha, not Unused:
6363

6464
$ dune build ./main.exe
6565
$ dune trace cat | jq -s 'include "dune"; [.[] | targetsMatchingFilter(test("uses_alpha"))] | length'
66-
2
66+
0

test/blackbox-tests/test-cases/virtual-libraries/github2896.t

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ where vlib is a virtual library, and impl implements this library.
2323
Error: Library "vlib" was pulled in.
2424
-> required by library "lib" in _build/default/lib
2525
-> required by library "impl" in _build/default/impl
26-
-> required by _build/default/impl/.impl.objs/byte/vlib.cmo
27-
-> required by _build/default/impl/impl.cma
26+
-> required by _build/default/impl/.impl.objs/native/vlib.cmx
27+
-> required by _build/default/impl/impl.a
2828
-> required by alias impl/all
2929
[1]
3030

@@ -37,6 +37,5 @@ The implementation impl was built, but it's not usable:
3737
-> required by library "lib" in _build/default/lib
3838
-> required by library "impl" in _build/default/impl
3939
-> required by executable foo in dune:1
40-
-> required by _build/default/.foo.eobjs/native/dune__exe__Foo.cmx
4140
-> required by _build/default/foo.exe
4241
[1]

test/blackbox-tests/test-cases/virtual-libraries/virtual-modules-excluded-by-modules-field.t

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ X is warned about:
4040
1 | module type F = X
4141
^
4242
Error: Unbound module type X
43-
File "src/impl/dune", lines 1-3, characters 0-40:
44-
1 | (library
45-
2 | (name impl)
46-
3 | (implements foo))
47-
Error: No rule found for src/.foo.objs/y.impl.all-deps
4843
[1]
4944

5045
In 3.11 onwards this warning becomes an error
@@ -76,6 +71,5 @@ This should be ignored if we are in vendored_dirs
7671
Error: No implementation found for virtual library "foo" in
7772
_build/default/src.
7873
-> required by executable bar in dune:3
79-
-> required by _build/default/.bar.eobjs/native/dune__exe__Bar.cmx
8074
-> required by _build/default/bar.exe
8175
[1]

test/blackbox-tests/test-cases/virtual-libraries/vlib-wrong-default-impl.t/run.t

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ library is not actually an implementation of the virtual library.
44
$ dune build @default
55
Error: "not_an_implem" is not an implementation of "vlibfoo".
66
-> required by executable exe in exe/dune:2
7-
-> required by _build/default/exe/.exe.eobjs/native/dune__exe__Exe.cmx
87
-> required by _build/default/exe/exe.exe
98
-> required by alias exe/default in exe/dune:5
109
[1]

0 commit comments

Comments
 (0)