Skip to content

Commit d35fc98

Browse files
authored
Add support for -H compiler flag (#10644)
* Add support for -H Signed-off-by: HasanA <[email protected]> Signed-off-by: Nicolás Ojeda Bär <[email protected]>
1 parent aac3d84 commit d35fc98

File tree

23 files changed

+245
-34
lines changed

23 files changed

+245
-34
lines changed

doc/changes/10644.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- Add support for the -H flag (introduced in OCaml compiler 5.2) in dune
2+
(requires lang versions 3.17). This adaptation gives
3+
the correct semantics for `(implicit_transitive_deps false)`.
4+
(#10644, fixes #9333, ocsigen/tyxml#274, #2733, #4963, @MA0100)

src/dune_rules/compilation_context.ml

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,42 @@ open Import
33
module Includes = struct
44
type t = Command.Args.without_targets Command.Args.t Lib_mode.Cm_kind.Map.t
55

6-
let make ~project ~opaque ~requires : _ Lib_mode.Cm_kind.Map.t =
6+
let make ~project ~opaque ~direct_requires ~hidden_requires : _ Lib_mode.Cm_kind.Map.t =
77
(* TODO : some of the requires can filtered out using [ocamldep] info *)
88
let open Resolve.Memo.O in
9-
let iflags libs mode = Lib_flags.L.include_flags ~project libs mode in
9+
let iflags direct_libs hidden_libs mode =
10+
Lib_flags.L.include_flags ~project ~direct_libs ~hidden_libs mode
11+
in
1012
let make_includes_args ~mode groups =
1113
Command.Args.memo
1214
(Resolve.Memo.args
13-
(let+ libs = requires in
15+
(let+ direct_libs = direct_requires
16+
and+ hidden_libs = hidden_requires in
1417
Command.Args.S
15-
[ iflags libs mode; Hidden_deps (Lib_file_deps.deps libs ~groups) ]))
18+
[ iflags direct_libs hidden_libs mode
19+
; Hidden_deps (Lib_file_deps.deps (direct_libs @ hidden_libs) ~groups)
20+
]))
1621
in
1722
let cmi_includes = make_includes_args ~mode:(Ocaml Byte) [ Ocaml Cmi ] in
1823
let cmx_includes =
1924
Command.Args.memo
2025
(Resolve.Memo.args
21-
(let+ libs = requires in
26+
(let+ direct_libs = direct_requires
27+
and+ hidden_libs = hidden_requires in
2228
Command.Args.S
23-
[ iflags libs (Ocaml Native)
29+
[ iflags direct_libs hidden_libs (Ocaml Native)
2430
; Hidden_deps
2531
(if opaque
2632
then
27-
List.map libs ~f:(fun lib ->
33+
List.map (direct_libs @ hidden_libs) ~f:(fun lib ->
2834
( lib
2935
, if Lib.is_local lib
3036
then [ Lib_file_deps.Group.Ocaml Cmi ]
3137
else [ Ocaml Cmi; Ocaml Cmx ] ))
3238
|> Lib_file_deps.deps_with_exts
3339
else
3440
Lib_file_deps.deps
35-
libs
41+
(direct_libs @ hidden_libs)
3642
~groups:[ Lib_file_deps.Group.Ocaml Cmi; Ocaml Cmx ])
3743
]))
3844
in
@@ -74,6 +80,7 @@ type t =
7480
; modules : modules
7581
; flags : Ocaml_flags.t
7682
; requires_compile : Lib.t list Resolve.Memo.t
83+
; requires_hidden : Lib.t list Resolve.Memo.t
7784
; requires_link : Lib.t list Resolve.t Memo.Lazy.t
7885
; includes : Includes.t
7986
; preprocessing : Pp_spec.t
@@ -99,6 +106,7 @@ let obj_dir t = t.obj_dir
99106
let modules t = t.modules.modules
100107
let flags t = t.flags
101108
let requires_compile t = t.requires_compile
109+
let requires_hidden t = t.requires_hidden
102110
let requires_link t = Memo.Lazy.force t.requires_link
103111
let includes t = t.includes
104112
let preprocessing t = t.preprocessing
@@ -139,10 +147,24 @@ let create
139147
=
140148
let open Memo.O in
141149
let project = Scope.project scope in
142-
let requires_compile =
150+
let context = Super_context.context super_context in
151+
let* ocaml = Context.ocaml context in
152+
let direct_requires, hidden_requires =
143153
if Dune_project.implicit_transitive_deps project
144-
then Memo.Lazy.force requires_link
145-
else requires_compile
154+
then Memo.Lazy.force requires_link, Resolve.Memo.return []
155+
else if Version.supports_hidden_includes ocaml.version
156+
&& Dune_project.dune_version project >= (3, 17)
157+
then (
158+
let requires_hidden =
159+
let open Resolve.Memo.O in
160+
let+ requires_compile = requires_compile
161+
and+ requires_link = Memo.Lazy.force requires_link in
162+
let requires_table = Table.create (module Lib) 5 in
163+
List.iter ~f:(fun lib -> Table.set requires_table lib ()) requires_compile;
164+
List.filter requires_link ~f:(fun l -> not (Table.mem requires_table l))
165+
in
166+
requires_compile, requires_hidden)
167+
else requires_compile, Resolve.Memo.return []
146168
in
147169
let sandbox = Sandbox_config.no_special_requirements in
148170
let modes =
@@ -153,8 +175,6 @@ let create
153175
in
154176
Option.value ~default modes |> Lib_mode.Map.map ~f:Option.is_some
155177
in
156-
let context = Super_context.context super_context in
157-
let* ocaml = Context.ocaml context in
158178
let opaque =
159179
let profile = Context.profile context in
160180
eval_opaque ocaml profile opaque
@@ -180,9 +200,10 @@ let create
180200
; obj_dir
181201
; modules = { modules; dep_graphs }
182202
; flags
183-
; requires_compile
203+
; requires_compile = direct_requires
204+
; requires_hidden = hidden_requires
184205
; requires_link
185-
; includes = Includes.make ~project ~opaque ~requires:requires_compile
206+
; includes = Includes.make ~project ~opaque ~direct_requires ~hidden_requires
186207
; preprocessing
187208
; opaque
188209
; stdlib
@@ -263,8 +284,16 @@ let for_module_generated_at_link_time cctx ~requires ~module_ =
263284
their implementation must also be compiled with -opaque *)
264285
Ocaml.Version.supports_opaque_for_mli cctx.ocaml.version
265286
in
287+
let direct_requires = requires in
288+
let hidden_requires = Resolve.Memo.return [] in
266289
let modules = singleton_modules module_ in
267-
let includes = Includes.make ~project:(Scope.project cctx.scope) ~opaque ~requires in
290+
let includes =
291+
Includes.make
292+
~project:(Scope.project cctx.scope)
293+
~opaque
294+
~direct_requires
295+
~hidden_requires
296+
in
268297
{ cctx with
269298
opaque
270299
; flags = Ocaml_flags.empty

src/dune_rules/compilation_context.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ val obj_dir : t -> Path.Build.t Obj_dir.t
5555
val modules : t -> Modules.With_vlib.t
5656
val flags : t -> Ocaml_flags.t
5757
val requires_link : t -> Lib.t list Resolve.Memo.t
58+
val requires_hidden : t -> Lib.t list Resolve.Memo.t
5859
val requires_compile : t -> Lib.t list Resolve.Memo.t
5960
val includes : t -> Command.Args.without_targets Command.Args.t Lib_mode.Cm_kind.Map.t
6061
val preprocessing : t -> Pp_spec.t

src/dune_rules/lib_flags.ml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,16 @@ let link_deps sctx t mode =
8585
module L = struct
8686
type nonrec t = Lib.t list
8787

88-
let to_iflags dirs =
88+
let to_flags flag dirs =
8989
Command.Args.S
9090
(Path.Set.fold dirs ~init:[] ~f:(fun dir acc ->
91-
Command.Args.Path dir :: A "-I" :: acc)
91+
Command.Args.Path dir :: A flag :: acc)
9292
|> List.rev)
9393
;;
9494

95+
let to_iflags dir = to_flags "-I" dir
96+
let to_hflags dir = to_flags "-H" dir
97+
9598
let remove_stdlib dirs libs =
9699
match libs with
97100
| [] -> dirs
@@ -155,8 +158,13 @@ module L = struct
155158
remove_stdlib dirs ts
156159
;;
157160

158-
let include_flags ?project ts mode =
159-
to_iflags (include_paths ?project ts { lib_mode = mode; melange_emit = false })
161+
let include_flags ?project ~direct_libs ~hidden_libs mode =
162+
let include_paths ts =
163+
include_paths ?project ts { lib_mode = mode; melange_emit = false }
164+
in
165+
let hidden_includes = to_hflags (include_paths hidden_libs) in
166+
let direct_includes = to_iflags (include_paths direct_libs) in
167+
Command.Args.S [ direct_includes; hidden_includes ]
160168
;;
161169

162170
let melange_emission_include_flags ?project ts =

src/dune_rules/lib_flags.mli

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,14 @@ module L : sig
2424

2525
val to_iflags : Path.Set.t -> _ Command.Args.t
2626
val include_paths : ?project:Dune_project.t -> t -> Lib_mode.t -> Path.Set.t
27-
val include_flags : ?project:Dune_project.t -> t -> Lib_mode.t -> _ Command.Args.t
27+
28+
val include_flags
29+
: ?project:Dune_project.t
30+
-> direct_libs:t
31+
-> hidden_libs:t
32+
-> Lib_mode.t
33+
-> _ Command.Args.t
34+
2835
val melange_emission_include_flags : ?project:Dune_project.t -> t -> _ Command.Args.t
2936
val c_include_flags : t -> Super_context.t -> _ Command.Args.t
3037
val toplevel_ld_paths : t -> Path.Set.t

src/dune_rules/merlin/ocaml_index.ml

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,22 @@ let cctx_rules cctx =
2424
let obj_dir = Compilation_context.obj_dir cctx in
2525
let fn = index_path_in_obj_dir obj_dir in
2626
let additional_libs =
27-
let open Resolve.Memo.O in
28-
let+ non_compile_libs =
29-
(* The indexer relies on the load_path of cmt files. When
30-
[implicit_transitive_deps] is set to [false] some necessary paths will
31-
be missing.These are passed to the indexer with the `-I` flag.
32-
33-
The implicit transitive libs correspond to the set:
34-
(requires_link \ req_compile) *)
35-
let* req_link = Compilation_context.requires_link cctx in
36-
let+ req_compile = Compilation_context.requires_compile cctx in
37-
List.filter req_link ~f:(fun l -> not (List.exists req_compile ~f:(Lib.equal l)))
38-
in
39-
Lib_flags.L.include_flags non_compile_libs (Lib_mode.Ocaml Byte)
27+
let scope = Compilation_context.scope cctx in
28+
(* Dune language >= 3.17 correctly passes the `-H` flag to the compiler. *)
29+
if Dune_project.dune_version (Scope.project scope) < (3, 17)
30+
then
31+
let open Resolve.Memo.O in
32+
let+ non_compile_libs =
33+
let* req_link = Compilation_context.requires_link cctx in
34+
let+ req_compile = Compilation_context.requires_compile cctx in
35+
List.filter req_link ~f:(fun l ->
36+
not (List.exists req_compile ~f:(Lib.equal l)))
37+
in
38+
Lib_flags.L.include_flags
39+
~direct_libs:non_compile_libs
40+
~hidden_libs:[]
41+
(Lib_mode.Ocaml Byte)
42+
else Resolve.Memo.return Command.Args.empty
4043
in
4144
(* Indexing depends (recursively) on [required_compile] libs:
4245
- These libs's cmt files should be built before indexing starts

src/ocaml/version.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ let supports_alerts version = version >= (4, 8, 0)
2929
let has_sandboxed_otherlibs version = version >= (5, 0, 0)
3030
let has_META_files version = version >= (5, 0, 0)
3131
let supports_bin_annot_occurrences version = version >= (5, 2, 0)
32+
let supports_hidden_includes version = version >= (5, 2, 0)

src/ocaml/version.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,6 @@ val has_META_files : t -> bool
7676

7777
(** Whether the compiler supports occurrences indexation *)
7878
val supports_bin_annot_occurrences : t -> bool
79+
80+
(** Whether the compiler supports the -H flag *)
81+
val supports_hidden_includes : t -> bool

test/blackbox-tests/test-cases/dune

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,3 +164,13 @@
164164
(cram
165165
(applies_to sandboxing-stale-directory-target)
166166
(deps %{bin:bash}))
167+
168+
(cram
169+
(applies_to hidden-deps-supported)
170+
(enabled_if
171+
(>= %{ocaml_version} 5.2.0)))
172+
173+
(cram
174+
(applies_to hidden-deps-unsupported)
175+
(enabled_if
176+
(< %{ocaml_version} 5.2.0)))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
let x = 5
2+
let y = Foo.v

0 commit comments

Comments
 (0)