Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add flag [disable_dynamically_linked_foreign_archives] to the workspace file #2864

Merged
merged 5 commits into from
Nov 7, 2019
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
13 changes: 10 additions & 3 deletions doc/dune-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ project:

(implicit_transitive_deps <bool>)

When set to ``false``, all dependencies that are directly used by a library
When set to ``false``, all dependencies that are directly used by a library
or an executable must be directly added in the ``libraries`` field. We
recommend users to experiment with this mode and report any problems.

Starting from dune 2.0, dune disables implicit discovery of transitive
dependencies by default. However, users can still opt in to the old
Starting from dune 2.0, dune disables implicit discovery of transitive
dependencies by default. However, users can still opt in to the old
behavior using ``(implicit_transitive_deps true)``.

Note that you must use ``threads.posix`` instead of ``threads`` when using this
Expand Down Expand Up @@ -1686,6 +1686,13 @@ context or can be the description of an opam switch, as follows:
feature is **experimental** and no backwards compatibility is
implied.

- By default Dune builds and installs dynamically linked foreign
archives (usually named ``dll*.so``). It is possible to disable
this by setting
``(disable_dynamically_linked_foreign_archives true)`` in the
workspace file, in which case bytecode executables will be built
with all foreign archives statically linked into the runtime system.


Both ``(default ...)`` and ``(opam ...)`` accept a ``targets`` field in order to
setup cross compilation. See :ref:`cross-compilation` for more
Expand Down
17 changes: 14 additions & 3 deletions src/dune/context.ml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type t =
; profile : Profile.t
; merlin : bool
; fdo_target_exe : Path.t option
; disable_dynamically_linked_foreign_archives : bool
; for_host : t option
; implicit : bool
; build_dir : Path.Build.t
Expand Down Expand Up @@ -222,7 +223,8 @@ let check_fdo_support has_native ocfg ~name =
]

let create ~(kind : Kind.t) ~path ~env ~env_nodes ~name ~merlin ~targets
~host_context ~host_toolchain ~profile ~fdo_target_exe =
~host_context ~host_toolchain ~profile ~fdo_target_exe
~disable_dynamically_linked_foreign_archives =
let opam_var_cache = Table.create (module String) 128 in
( match kind with
| Opam { root = Some root; _ } -> Table.set opam_var_cache "root" root
Expand Down Expand Up @@ -455,6 +457,7 @@ let create ~(kind : Kind.t) ~path ~env ~env_nodes ~name ~merlin ~targets
; profile
; merlin
; fdo_target_exe
; disable_dynamically_linked_foreign_archives
; env_nodes
; for_host = host
; build_dir
Expand Down Expand Up @@ -541,9 +544,11 @@ let extend_paths t ~env =
let opam_config_var t var =
opam_config_var ~env:t.env ~cache:t.opam_var_cache var

let default ~merlin ~env_nodes ~env ~targets ~fdo_target_exe =
let default ~merlin ~env_nodes ~env ~targets ~fdo_target_exe
~disable_dynamically_linked_foreign_archives =
let path = Env.path env in
create ~kind:Default ~path ~env ~env_nodes ~merlin ~targets ~fdo_target_exe
~disable_dynamically_linked_foreign_archives

let opam_version =
let res = ref None in
Expand All @@ -569,7 +574,8 @@ let opam_version =
Fiber.Future.wait future

let create_for_opam ~root ~env ~env_nodes ~targets ~profile ~switch ~name
~merlin ~host_context ~host_toolchain ~fdo_target_exe =
~merlin ~host_context ~host_toolchain ~fdo_target_exe
~disable_dynamically_linked_foreign_archives =
let opam =
match Lazy.force opam with
| None -> Utils.program_not_found "opam" ~loc:None
Expand Down Expand Up @@ -620,6 +626,7 @@ let create_for_opam ~root ~env ~env_nodes ~targets ~profile ~switch ~name
~kind:(Opam { root; switch })
~profile ~targets ~path ~env ~env_nodes ~name ~merlin ~host_context
~host_toolchain ~fdo_target_exe
~disable_dynamically_linked_foreign_archives

let instantiate_context env (workspace : Workspace.t)
~(context : Workspace.Context.t) ~host_context =
Expand All @@ -638,6 +645,7 @@ let instantiate_context env (workspace : Workspace.t)
; paths
; loc = _
; fdo_target_exe
; disable_dynamically_linked_foreign_archives
} ->
let merlin =
workspace.merlin_context = Some (Workspace.Context.name context)
Expand All @@ -653,6 +661,7 @@ let instantiate_context env (workspace : Workspace.t)
let env = extend_paths ~env paths in
default ~env ~env_nodes ~profile ~targets ~name ~merlin ~host_context
~host_toolchain ~fdo_target_exe
~disable_dynamically_linked_foreign_archives
| Opam
{ base =
{ targets
Expand All @@ -664,6 +673,7 @@ let instantiate_context env (workspace : Workspace.t)
; paths
; loc = _
; fdo_target_exe
; disable_dynamically_linked_foreign_archives
}
; switch
; root
Expand All @@ -672,6 +682,7 @@ let instantiate_context env (workspace : Workspace.t)
let env = extend_paths ~env paths in
create_for_opam ~root ~env_nodes ~env ~profile ~switch ~name ~merlin
~targets ~host_context ~host_toolchain:toolchain ~fdo_target_exe
~disable_dynamically_linked_foreign_archives

let create ~env (workspace : Workspace.t) =
let rec contexts : t list Fiber.Once.t Context_name.Map.t Lazy.t =
Expand Down
6 changes: 6 additions & 0 deletions src/dune/context.mli
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ type t =
(** [Some path/to/foo.exe] if this contexts is for feedback-directed
optimization of target path/to/foo.exe *)
; fdo_target_exe : Path.t option
(* By default Dune builds and installs dynamically linked foreign
archives (usually named [dll*.so]). It is possible to disable this
by adding (disable_dynamically_linked_foreign_archives true) to the
workspace file, in which case bytecode executables will be built
with all foreign archives statically linked into the runtime system. *)
; disable_dynamically_linked_foreign_archives : bool
(** If this context is a cross-compilation context, you need another
context for building tools used for the compilation that run on the
host. *)
Expand Down
2 changes: 1 addition & 1 deletion src/dune/dune_file.mli
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ module Library : sig
val foreign_archives :
t -> dir:Path.Build.t -> ext_lib:string -> Path.Build.t list

(** The [dll*.a] files of all foreign archives, including foreign stubs.
(** The [dll*.so] files of all foreign archives, including foreign stubs.
[dir] is the directory the library is declared in. *)
val foreign_dll_files :
t -> dir:Path.Build.t -> ext_dll:string -> Path.Build.t list
Expand Down
9 changes: 8 additions & 1 deletion src/dune/exe.ml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ module Linkage = struct
=
let link_mode : Link_mode.t =
match m.mode with
| Byte -> Byte
| Byte ->
if ctx.disable_dynamically_linked_foreign_archives then
(* When [disable_dynamically_linked_foreign_archives] is set to
[true] in the workspace, we link in all stub archives statically
into the runtime system. *)
Byte_with_stubs_statically_linked_in
else
Byte
| Native -> Native
| Best ->
if Option.is_some ctx.ocamlopt then
Expand Down
4 changes: 3 additions & 1 deletion src/dune/lib_archives.ml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ let make ~(ctx : Context.t) ~dir ~dir_contents (lib : Library.t) =
in
let dll_files =
if_
(byte && Dynlink_supported.get lib.dynlink ctx.supports_shared_libraries)
( byte
&& Dynlink_supported.get lib.dynlink ctx.supports_shared_libraries
&& not ctx.disable_dynamically_linked_foreign_archives )
(Library.foreign_dll_files lib ~dir ~ext_dll)
in
{ lib_files; dll_files }
13 changes: 9 additions & 4 deletions src/dune/lib_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,13 @@ let ocamlmklib ~loc ~c_library_flags ~sctx ~dir ~expander ~o_files
])
in
if build_targets_together then
(* Build both the static and dynamic targets in one ocamlmklib invocation. *)
(* Build both the static and dynamic targets in one [ocamlmklib]
invocation, unless dynamically linked foreign archives are disabled. *)
build ~sandbox:Sandbox_config.no_special_requirements ~custom:false
[ static_target; dynamic_target ]
( if ctx.disable_dynamically_linked_foreign_archives then
[ static_target ]
else
[ static_target; dynamic_target ] )
else (
(* Build the static target only by passing the [-custom] flag. *)
build ~sandbox:Sandbox_config.no_special_requirements ~custom:true
Expand All @@ -169,8 +173,9 @@ let ocamlmklib ~loc ~c_library_flags ~sctx ~dir ~expander ~o_files
"optional targets", allowing us to run [ocamlmklib] with the [-failsafe]
flag, which always produces the static target and sometimes produces the
dynamic target too. *)
build ~sandbox:Sandbox_config.needs_sandboxing ~custom:false
[ dynamic_target ]
if not ctx.disable_dynamically_linked_foreign_archives then
build ~sandbox:Sandbox_config.needs_sandboxing ~custom:false
[ dynamic_target ]
)

(* Build a static and a dynamic archive for a foreign library. Note that the
Expand Down
6 changes: 6 additions & 0 deletions src/dune/workspace.ml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module Context = struct
; host_context : Context_name.t option
; paths : (string * Ordered_set_lang.t) list
; fdo_target_exe : Path.t option
; disable_dynamically_linked_foreign_archives : bool
}

let fdo_suffix t =
Expand All @@ -61,6 +62,9 @@ module Context = struct
and+ toolchain =
field_o "toolchain"
(Dune_lang.Syntax.since syntax (1, 5) >>> Context_name.decode)
and+ disable_dynamically_linked_foreign_archives =
field ~default:false "disable_dynamically_linked_foreign_archives"
(Dune_lang.Syntax.since syntax (2, 0) >>> bool)
and+ fdo_target_exe =
let f file =
let ext = Filename.extension file in
Expand Down Expand Up @@ -112,6 +116,7 @@ module Context = struct
; toolchain
; paths
; fdo_target_exe
; disable_dynamically_linked_foreign_archives
}
end

Expand Down Expand Up @@ -209,6 +214,7 @@ module Context = struct
; toolchain = None
; paths = []
; fdo_target_exe = None
; disable_dynamically_linked_foreign_archives = false
}
end

Expand Down
7 changes: 7 additions & 0 deletions src/dune/workspace.mli
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ module Context : sig
; host_context : Context_name.t option
; paths : (string * Ordered_set_lang.t) list
; fdo_target_exe : Path.t option
(* By default Dune builds and installs dynamically linked foreign
archives (usually named [dll*.so]). It is possible to disable
this by setting [disable_dynamically_linked_foreign_archives] to
[true] in the workspace file, in which case bytecode executables
will be built with all foreign archives statically linked into
the runtime system. *)
; disable_dynamically_linked_foreign_archives : bool
}
end

Expand Down
122 changes: 122 additions & 0 deletions test/blackbox-tests/test-cases/foreign-stubs/run.t
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,125 @@ Testsuite for the (foreign_stubs ...) field.

$ ./sdune clean
$ ./sdune build

----------------------------------------------------------------------------------
* Fails to build a pure bytecode executable with a foreign archive

$ cat >dune <<EOF
> (executable
> (modes byte)
> (name main)
> (modules main)
> (foreign_archives time))
> (foreign_library
> (archive_name time)
> (language c)
> (names time))
> EOF

$ cat >time.c <<EOF
> #include <caml/mlvalues.h>
> value current_time(value unit) { return Val_int(1345); }
> EOF

$ cat >main.ml <<EOF
> external current_time : unit -> int = "current_time"
> let () = Printf.printf "clock = %d" (current_time ())
> EOF

$ ./sdune clean
$ ./sdune exec ./main.bc
File "dune", line 1, characters 0-80:
1 | (executable
2 | (modes byte)
3 | (name main)
4 | (modules main)
5 | (foreign_archives time))
Error: Pure bytecode executables cannot contain foreign archives.
Hint: If you only need to build a native executable use "(modes exe)".
[1]

----------------------------------------------------------------------------------
* Build a bytecode executable by statically linking in a foreign archive when the
setting [disable_dynamically_linked_foreign_archives] is [true] in the workspace

$ cat >dune-workspace <<EOF
> (lang dune 2.0)
> (context
> (default (disable_dynamically_linked_foreign_archives true)))
> EOF

$ ./sdune clean
$ ./sdune exec ./main.bc
clock = 1345

----------------------------------------------------------------------------------
* Make sure no rules are generated for foreign dynamically linked archives

$ ./sdune build _build/default/dlltime.so
Error: Don't know how to build _build/default/dlltime$ext_dll
[1]

----------------------------------------------------------------------------------
* Fails to install a library with foreign stubs when a [dll*.so] rule is missing

$ cat >dune-project <<EOF
> (lang dune 1.11)
> (package
> (name foo))
> EOF

$ cat >dune-workspace <<EOF
> (lang dune 2.0)
> (context
> (default (disable_dynamically_linked_foreign_archives false)))
> EOF

$ cat >dune <<EOF
> (library
> (public_name foo.clock)
> (name clock)
> (modules clock)
> (self_build_stubs_archive (time)))
> (rule
> (targets time%{ext_obj})
> (deps time.c)
> (action (run %{ocaml-config:c_compiler} -c -I %{ocaml-config:standard_library} -o %{targets} %{deps})))
> (rule
> (targets libtime_stubs.a)
> (deps time%{ext_obj})
> (action (run ar rcs %{targets} %{deps})))
> EOF

$ cat >clock.ml <<EOF
> external current_time : unit -> int = "current_time"
> let clock = current_time ()
> EOF

$ cat >clock.mli <<EOF
> val clock : int
> EOF

$ ./sdune clean
$ ./sdune build @install
File "dune", line 1, characters 0-100:
1 | (library
2 | (public_name foo.clock)
3 | (name clock)
4 | (modules clock)
5 | (self_build_stubs_archive (time)))
Error: No rule found for dlltime_stubs$ext_dll
[1]

----------------------------------------------------------------------------------
* Succeeds to install a library with foreign stubs when a [dll*.so] rule is missing
but the setting [disable_dynamically_linked_foreign_archives] is [true] in the workspace

$ cat >dune-workspace <<EOF
> (lang dune 2.0)
> (context
> (default (disable_dynamically_linked_foreign_archives true)))
> EOF

$ ./sdune clean
$ ./sdune build @install