Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/changes/11866.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- Introduce option `(implicit_transitive_deps
false-if-hidden-includes-supported)` that is equivalent to
`(implicit_transitive_deps false)` when `-H` is supported by the compiler
(OCaml >= 5.2) and equivalent to `(implicit_transitive_deps true)` otherwise.
(#11866, fixes #11212, @nojb)
27 changes: 20 additions & 7 deletions doc/reference/dune-project/implicit_transitive_deps.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
implicit_transitive_deps
------------------------

.. describe:: (implicit_transitive_deps ...)
.. describe:: (implicit_transitive_deps <setting>)

Control whether transitive dependencies are made implicitly visible.
Control whether transitive dependencies are made implicitly visible during
compilation.

By default, Dune allows transitive dependencies of dependencies used when
compiling OCaml. However, this can be disabled by specifying:
``<setting>`` is one of:

- ``true`` makes transitive dependencies implicitly visible. This is the
default.

- ``false`` only listed dependencies are visible. If the ``-H`` flag is
supported by the compiler (OCaml version >= 5.2) and Dune language version
is >= 1.17, Dune will pass the flag to the compiler, which avoids some
corner cases (see below).

- ``false-if-hidden-includes-supported`` only listed dependencies are visible
if the compiler supports the ``-H`` flag. Otherwise (OCaml version < 5.2),
the setting is ignored and all transitive dependencies are made visible.
Introduced in Dune 3.20.

.. code:: dune

Expand All @@ -17,9 +30,9 @@ implicit_transitive_deps

We recommend users experiment with this mode and report any problems.

Note that you must use ``threads.posix`` instead of ``threads`` when using
this mode. This isn't an important limitation, as ``threads.vm`` is
deprecated anyway.
Note that if ``-H`` flag is not being used, you must use ``threads.posix``
instead of ``threads`` when using this mode. This isn't an important
limitation, as ``threads.vm`` is deprecated anyway.

In some situations, it can be desirable to selectively preserve the behavior
of transitive dependencies' availability a library's users. For example, if
Expand Down
98 changes: 87 additions & 11 deletions src/dune_lang/dune_project.ml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,68 @@ module Versioned_file = Dune_sexp.Versioned_file
module Execution_parameters = Dune_engine.Execution_parameters
module Compound_user_error = Dune_engine.Compound_user_error

module Implicit_transitive_deps = struct
type t =
| Enabled
| Disabled
| Disabled_with_hidden_includes

let to_bool = function
| Enabled -> true
| Disabled | Disabled_with_hidden_includes -> false
;;

module Stanza = struct
type mode = t

type t =
| Enabled
| Disabled
| Disabled_if_hidden_includes_supported

let default ~lang:_ = Enabled

let to_dyn = function
| Enabled -> Dyn.variant "Enabled" []
| Disabled -> Dyn.variant "Disabled" []
| Disabled_if_hidden_includes_supported ->
Dyn.variant "Disabled_if_hidden_includes_supported" []
;;

let equal = Poly.equal

let encode = function
| Enabled -> Encoder.bool true
| Disabled -> Encoder.bool false
| Disabled_if_hidden_includes_supported ->
Encoder.string "false-if-hidden-includes-supported"
;;

let decode =
let check ver = Syntax.since Stanza.syntax ver in
enum'
[ "true", check (1, 7) >>> return Enabled
; "false", check (1, 7) >>> return Disabled
; ( "false-if-hidden-includes-supported"
, check (3, 20) >>> return Disabled_if_hidden_includes_supported )
]
;;

let mode t ~ocaml_version ~dune_version : mode =
match t with
| Enabled -> Enabled
| Disabled ->
if Ocaml.Version.supports_hidden_includes ocaml_version && dune_version >= (3, 17)
then Disabled_with_hidden_includes
else Disabled
| Disabled_if_hidden_includes_supported ->
if Ocaml.Version.supports_hidden_includes ocaml_version
then Disabled_with_hidden_includes
else Enabled
;;
end
end

type t =
{ name : Dune_project_name.t
; root : Path.Source.t
Expand All @@ -15,7 +77,7 @@ type t =
; project_file : Path.Source.t option
; extension_args : Univ_map.t
; parsing_context : Univ_map.t
; implicit_transitive_deps : bool
; implicit_transitive_deps : Implicit_transitive_deps.Stanza.t
; wrapped_executables : bool
; map_workspace_root : bool
; executables_implicit_empty_intf : bool
Expand Down Expand Up @@ -54,7 +116,14 @@ let version t = t.version
let root t = t.root
let stanza_parser t = Decoder.set key t t.stanza_parser
let file t = t.project_file
let implicit_transitive_deps t = t.implicit_transitive_deps

let implicit_transitive_deps t ocaml_version =
Implicit_transitive_deps.Stanza.mode
t.implicit_transitive_deps
~ocaml_version
~dune_version:t.dune_version
;;

let generate_opam_files t = t.generate_opam_files
let warnings t = t.warnings
let set_generate_opam_files generate_opam_files t = { t with generate_opam_files }
Expand Down Expand Up @@ -106,7 +175,8 @@ let to_dyn
; ( "packages"
, (list (pair Package.Name.to_dyn Package.to_dyn))
(Package.Name.Map.to_list packages) )
; "implicit_transitive_deps", bool implicit_transitive_deps
; ( "implicit_transitive_deps"
, Implicit_transitive_deps.Stanza.to_dyn implicit_transitive_deps )
; "wrapped_executables", bool wrapped_executables
; "map_workspace_root", bool map_workspace_root
; "executables_implicit_empty_intf", bool executables_implicit_empty_intf
Expand Down Expand Up @@ -333,7 +403,6 @@ let interpret_lang_and_extensions ~(lang : Lang.Instance.t) ~explicit_extensions

let filename = "dune-project"
let opam_file_location_default ~lang:_ = `Relative_to_project
let implicit_transitive_deps_default ~lang:_ = true
let wrapped_executables_default ~(lang : Lang.Instance.t) = lang.version >= (2, 0)
let map_workspace_root_default ~(lang : Lang.Instance.t) = lang.version >= (3, 0)

Expand Down Expand Up @@ -396,7 +465,7 @@ let infer ~dir info packages =
let parsing_context, stanza_parser, extension_args =
interpret_lang_and_extensions ~lang ~explicit_extensions:String.Map.empty
in
let implicit_transitive_deps = implicit_transitive_deps_default ~lang in
let implicit_transitive_deps = Implicit_transitive_deps.Stanza.default ~lang in
let wrapped_executables = wrapped_executables_default ~lang in
let map_workspace_root = map_workspace_root_default ~lang in
let executables_implicit_empty_intf = executables_implicit_empty_intf_default ~lang in
Expand Down Expand Up @@ -493,10 +562,17 @@ let encode : t -> Dune_sexp.t list =
List.filter_opt
[ flag "generate_opam_files" generate_opam_files (fun ~lang:_ ->
not generate_opam_files)
; flag
"implicit_transitive_deps"
implicit_transitive_deps
implicit_transitive_deps_default
; (if
Implicit_transitive_deps.Stanza.equal
implicit_transitive_deps
(Implicit_transitive_deps.Stanza.default ~lang)
then None
else
Some
(constr
"implicit_transitive_deps"
Implicit_transitive_deps.Stanza.encode
implicit_transitive_deps))
; flag "wrapped_executables" wrapped_executables wrapped_executables_default
; flag "map_workspace_root" map_workspace_root map_workspace_root_default
; flag
Expand Down Expand Up @@ -762,7 +838,7 @@ let parse ~dir ~(lang : Lang.Instance.t) ~file =
version of extensions before parsing them. *)
Extension.instantiate ~dune_lang_ver:lang.version ~loc ~parse_args name ver)
and+ implicit_transitive_deps =
field_o_b "implicit_transitive_deps" ~check:(Syntax.since Stanza.syntax (1, 7))
field_o "implicit_transitive_deps" Implicit_transitive_deps.Stanza.decode
and+ wrapped_executables =
field_o_b "wrapped_executables" ~check:(Syntax.since Stanza.syntax (1, 11))
and+ map_workspace_root =
Expand Down Expand Up @@ -843,7 +919,7 @@ let parse ~dir ~(lang : Lang.Instance.t) ~file =
let implicit_transitive_deps =
Option.value
implicit_transitive_deps
~default:(implicit_transitive_deps_default ~lang)
~default:(Implicit_transitive_deps.Stanza.default ~lang)
in
let wrapped_executables =
Option.value wrapped_executables ~default:(wrapped_executables_default ~lang)
Expand Down
11 changes: 10 additions & 1 deletion src/dune_lang/dune_project.mli
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ open Dune_config
module Pin_stanza := Pin_stanza
module Execution_parameters := Dune_engine.Execution_parameters

module Implicit_transitive_deps : sig
type t =
| Enabled
| Disabled
| Disabled_with_hidden_includes

val to_bool : t -> bool
end

type t

val to_dyn : t -> Dyn.t
Expand Down Expand Up @@ -95,7 +104,7 @@ val find_extension_args : t -> 'a Extension.t -> 'a option

val is_extension_set : t -> 'a Extension.t -> bool
val set_parsing_context : t -> 'a Decoder.t -> 'a Decoder.t
val implicit_transitive_deps : t -> bool
val implicit_transitive_deps : t -> Ocaml.Version.t -> Implicit_transitive_deps.t
val dune_version : t -> Syntax.Version.t
val wrapped_executables : t -> bool
val map_workspace_root : t -> bool
Expand Down
13 changes: 5 additions & 8 deletions src/dune_rules/compilation_context.ml
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,10 @@ let create
let context = Super_context.context super_context in
let* ocaml = Context.ocaml context in
let direct_requires, hidden_requires =
if Dune_project.implicit_transitive_deps project
then Memo.Lazy.force requires_link, Resolve.Memo.return []
else if
Version.supports_hidden_includes ocaml.version
&& Dune_project.dune_version project >= (3, 17)
then (
match Dune_project.implicit_transitive_deps project ocaml.version with
| Enabled -> Memo.Lazy.force requires_link, Resolve.Memo.return []
| Disabled -> requires_compile, Resolve.Memo.return []
| Disabled_with_hidden_includes ->
let requires_hidden =
let open Resolve.Memo.O in
let+ requires_compile = requires_compile
Expand All @@ -166,8 +164,7 @@ let create
List.iter ~f:(fun lib -> Table.set requires_table lib ()) requires_compile;
List.filter requires_link ~f:(fun l -> not (Table.mem requires_table l))
in
requires_compile, requires_hidden)
else requires_compile, Resolve.Memo.return []
requires_compile, requires_hidden
in
let sandbox = Sandbox_config.no_special_requirements in
let modes =
Expand Down
8 changes: 6 additions & 2 deletions src/dune_rules/merlin/merlin.ml
Original file line number Diff line number Diff line change
Expand Up @@ -687,8 +687,12 @@ module Unprocessed = struct
>>= function
| Some lib ->
let+ libs =
let linking =
Dune_project.implicit_transitive_deps (Scope.project scope)
let* linking =
let+ ocaml = Context.ocaml (Super_context.context sctx) in
Dune_project.Implicit_transitive_deps.to_bool
(Dune_project.implicit_transitive_deps
(Scope.project scope)
ocaml.version)
in
Lib.closure [ lib ] ~linking
|> Resolve.Memo.peek
Expand Down
12 changes: 8 additions & 4 deletions test/blackbox-tests/test-cases/hidden-deps-supported.t/run.t
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,13 @@ implicit_transitive_deps is set to false.
-I .run.eobjs/byte
-I .run.eobjs/native

In the following two tests we use "false-if-hidden-includes-supported" for
testing purposes, but since this test is guarded by OCaml version >= 5.2, this
should be equivalent to "false".

$ cat >dune-project <<EOF
> (lang dune 3.17)
> (implicit_transitive_deps false)
> (lang dune 3.20)
> (implicit_transitive_deps false-if-hidden-includes-supported)
> EOF

$ getincludes
Expand All @@ -40,8 +44,8 @@ implicit_transitive_deps is set to false.
Test transitive deps can not be directly accessed, both for compiler versions supporting -H or not:

$ cat >dune-project <<EOF
> (lang dune 3.17)
> (implicit_transitive_deps false)
> (lang dune 3.20)
> (implicit_transitive_deps false-if-hidden-includes-supported)
> EOF

$ dune build ./runf.exe 2>&1 | grep -v ocamlc
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ the new -H feature added.

$ cat >dune-project <<EOF
> (lang dune 3.17)
> (implicit_transitive_deps false)
> (implicit_transitive_deps false-if-hidden-includes-supported)
> EOF

$ dune build

$ cat >dune-project <<EOF
> (lang dune 3.20)
> (implicit_transitive_deps false-if-hidden-includes-supported)
> EOF

$ getincludes
Expand Down
Loading