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

Fix native code generation of empty libraries on MSVC #2829

Merged
merged 2 commits into from
Nov 5, 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
21 changes: 3 additions & 18 deletions src/dune/context.ml
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,6 @@ module Env_nodes = struct
(Dune_env.Stanza.find env_nodes.workspace ~profile).env_vars
end

module Ccomp_type = struct
type t =
| Msvc
| Other of string

let to_dyn =
let open Dyn.Encoder in
function
| Msvc -> constr "Msvc" []
| Other s -> constr "Other" [ string s ]

let of_string = function
| "msvc" -> Msvc
| s -> Other s
end

type t =
{ name : Context_name.t
; kind : Kind.t
Expand Down Expand Up @@ -79,7 +63,7 @@ type t =
; version_string : string
; version : Ocaml_version.t
; stdlib_dir : Path.t
; ccomp_type : Ccomp_type.t
; ccomp_type : Lib_config.Ccomp_type.t
; c_compiler : string
; ocamlc_cflags : string list
; ocamlopt_cflags : string list
Expand Down Expand Up @@ -474,6 +458,7 @@ let create ~(kind : Kind.t) ~path ~env ~env_nodes ~name ~merlin ~targets
let version = Ocaml_version.of_ocaml_config ocfg in
let arch_sixtyfour = Ocaml_config.word_size ocfg = 64 in
let ocamlopt = get_ocaml_tool "ocamlopt" in
let ccomp_type = Lib_config.Ccomp_type.of_config ocfg in
let lib_config =
{ Lib_config.has_native = Option.is_some ocamlopt
; ext_obj = Ocaml_config.ext_obj ocfg
Expand All @@ -486,11 +471,11 @@ let create ~(kind : Kind.t) ~path ~env ~env_nodes ~name ~merlin ~targets
; natdynlink_supported =
Dynlink_supported.By_the_os.of_bool natdynlink_supported
; stdlib_dir
; ccomp_type
}
in
if Option.is_some fdo_target_exe then
check_fdo_support lib_config.has_native ocfg ~name;
let ccomp_type = Ccomp_type.of_string (Ocaml_config.ccomp_type ocfg) in
let t =
{ name
; implicit
Expand Down
10 changes: 1 addition & 9 deletions src/dune/context.mli
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,6 @@ module Env_nodes : sig
}
end

module Ccomp_type : sig
type t =
| Msvc
| Other of string

val to_dyn : t -> Dyn.t
end

type t =
{ name : Context_name.t
; kind : Kind.t
Expand Down Expand Up @@ -89,7 +81,7 @@ type t =
; version_string : string
; version : Ocaml_version.t
; stdlib_dir : Path.t
; ccomp_type : Ccomp_type.t
; ccomp_type : Lib_config.Ccomp_type.t
; c_compiler : string
; ocamlc_cflags : string list
; ocamlopt_cflags : string list
Expand Down
21 changes: 15 additions & 6 deletions src/dune/lib.ml
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,10 @@ type db =
and resolve_result =
| Not_found
| Found of Lib_info.external_
| Hidden of Lib_info.external_ * string
| Hidden of
{ info : Lib_info.external_
; reason : string
}
| Redirect of db option * (Loc.t * Lib_name.t)

type lib = t
Expand Down Expand Up @@ -1134,7 +1137,7 @@ end = struct
in
Table.add_exn db.table name res;
res
| Hidden (info, hidden) -> (
| Hidden { info; reason = hidden } -> (
match
match db.parent with
| None -> St_not_found
Expand Down Expand Up @@ -1539,16 +1542,19 @@ module DB = struct
type t = resolve_result =
| Not_found
| Found of Lib_info.external_
| Hidden of Lib_info.external_ * string
| Hidden of
{ info : Lib_info.external_
; reason : string
}
| Redirect of db option * (Loc.t * Lib_name.t)

let to_dyn x =
let open Dyn.Encoder in
match x with
| Not_found -> constr "Not_found" []
| Found lib -> constr "Found" [ Lib_info.to_dyn Path.to_dyn lib ]
| Hidden (lib, s) ->
constr "Hidden" [ Lib_info.to_dyn Path.to_dyn lib; string s ]
| Hidden { info = lib; reason } ->
constr "Hidden" [ Lib_info.to_dyn Path.to_dyn lib; string reason ]
| Redirect (_, (_, name)) -> constr "Redirect" [ Lib_name.to_dyn name ]
end

Expand Down Expand Up @@ -1752,7 +1758,10 @@ module DB = struct
else
Not_found
| Hidden pkg ->
Hidden (Dune_package.Lib.info pkg, "unsatisfied 'exist_if'") ))
Hidden
{ info = Dune_package.Lib.info pkg
; reason = "unsatisfied 'exist_if'"
} ))
~all:(fun () ->
Findlib.all_packages findlib |> List.map ~f:Dune_package.Entry.name)

Expand Down
5 changes: 4 additions & 1 deletion src/dune/lib.mli
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,10 @@ module DB : sig
type nonrec t =
| Not_found
| Found of Lib_info.external_
| Hidden of Lib_info.external_ * string
| Hidden of
{ info : Lib_info.external_
; reason : string
}
| Redirect of t option * (Loc.t * Lib_name.t)

val to_dyn : t Dyn.Encoder.t
Expand Down
18 changes: 15 additions & 3 deletions src/dune/lib_archives.ml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@ let lib_files t = t.lib_files

let dll_files t = t.dll_files

let has_native_archive lib config contents =
Lib_config.linker_can_create_empty_archives config
||
let name = Dune_file.Library.best_name lib in
let modules = Dir_contents.modules_of_library contents ~name in
not (Modules.is_empty modules)

module Library = Dune_file.Library

let make ~(ctx : Context.t) ~dir ~dir_contents (lib : Library.t) =
Expand Down Expand Up @@ -41,9 +48,14 @@ let make ~(ctx : Context.t) ~dir ~dir_contents (lib : Library.t) =
; if_
(native && not virtual_library)
(let files =
[ Library.archive ~dir lib ~ext:(Mode.compiled_lib_ext Native)
; Library.archive ~dir lib ~ext:ext_lib
]
if has_native_archive lib ctx.lib_config dir_contents then
[ Library.archive ~dir lib ~ext:ext_lib ]
else
[]
in
let files =
Library.archive ~dir lib ~ext:(Mode.compiled_lib_ext Native)
:: files
in
if
Dynlink_supported.get lib.dynlink
Expand Down
3 changes: 3 additions & 0 deletions src/dune/lib_archives.mli
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ open Stdune

type t

val has_native_archive :
Dune_file.Library.t -> Lib_config.t -> Dir_contents.t -> bool

val make :
ctx:Context.t
-> dir:Path.Build.t
Expand Down
24 changes: 24 additions & 0 deletions src/dune/lib_config.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
open! Stdune

module Ccomp_type = struct
type t =
| Msvc
| Other of string

let to_dyn =
let open Dyn.Encoder in
function
| Msvc -> constr "Msvc" []
| Other s -> constr "Other" [ string s ]

let of_string = function
| "msvc" -> Msvc
| s -> Other s

let of_config ocfg = of_string (Ocaml_config.ccomp_type ocfg)
end

type t =
{ has_native : bool
; ext_lib : string
Expand All @@ -11,6 +29,7 @@ type t =
; natdynlink_supported : Dynlink_supported.By_the_os.t
; ext_dll : string
; stdlib_dir : Path.t
; ccomp_type : Ccomp_type.t
}

let var_map =
Expand All @@ -28,3 +47,8 @@ let get_for_enabled_if t ~var =
| None ->
Code_error.raise "Lib_config.get_for_enabled_if: var not allowed"
[ ("var", Dyn.Encoder.string var) ]

let linker_can_create_empty_archives t =
match t.ccomp_type with
| Msvc -> false
| Other _ -> true
13 changes: 13 additions & 0 deletions src/dune/lib_config.mli
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
open Stdune

module Ccomp_type : sig
type t =
| Msvc
| Other of string

val to_dyn : t -> Dyn.t

val of_config : Ocaml_config.t -> t
end

type t =
{ has_native : bool
; ext_lib : string
Expand All @@ -11,8 +21,11 @@ type t =
; natdynlink_supported : Dynlink_supported.By_the_os.t
; ext_dll : string
; stdlib_dir : Path.t
; ccomp_type : Ccomp_type.t
}

val allowed_in_enabled_if : string list

val get_for_enabled_if : t -> var:string -> string

val linker_can_create_empty_archives : t -> bool
30 changes: 22 additions & 8 deletions src/dune/lib_rules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ let msvc_hack_cclibs =
Option.value ~default:lib (String.drop_prefix ~prefix:"-l" lib))

(* Build an OCaml library. *)
let build_lib (lib : Library.t) ~sctx ~expander ~flags ~dir ~mode ~cm_files =
let build_lib (lib : Library.t) ~sctx ~dir_contents ~expander ~flags ~dir ~mode
~cm_files =
let ctx = Super_context.context sctx in
let { Lib_config.ext_lib; _ } = ctx.lib_config in
Option.iter (Context.compiler ctx mode) ~f:(fun compiler ->
Expand Down Expand Up @@ -74,7 +75,14 @@ let build_lib (lib : Library.t) ~sctx ~expander ~flags ~dir ~mode ~cm_files =
; Hidden_targets
( match mode with
| Byte -> []
| Native -> [ Library.archive lib ~dir ~ext:ext_lib ] )
| Native ->
if
Lib_archives.has_native_archive lib ctx.lib_config
dir_contents
then
[ Library.archive lib ~dir ~ext:ext_lib ]
else
[] )
] ))

let gen_wrapped_compat_modules (lib : Library.t) cctx =
Expand Down Expand Up @@ -211,7 +219,7 @@ let build_stubs lib ~cctx ~dir ~expander ~requires ~dir_contents
ocamlmklib ~archive_name ~loc:lib.buildable.loc ~sctx ~expander ~dir
~o_files ~c_library_flags:lib.c_library_flags ~build_targets_together

let build_shared lib ~sctx ~dir ~flags =
let build_shared lib ~dir_contents ~sctx ~dir ~flags =
let ctx = Super_context.context sctx in
Option.iter ctx.ocamlopt ~f:(fun ocamlopt ->
let ext_lib = ctx.lib_config.ext_lib in
Expand All @@ -226,7 +234,6 @@ let build_shared lib ~sctx ~dir ~flags =
let build =
Build.paths
(Library.foreign_archives lib ~dir ~ext_lib |> List.map ~f:Path.build)
>>> Build.path (Path.build (Library.archive lib ~dir ~ext:ext_lib))
>>> Command.run ~dir:(Path.build ctx.build_dir) (Ok ocamlopt)
[ Command.Args.dyn (Ocaml_flags.get flags Native)
; A "-shared"
Expand All @@ -238,9 +245,16 @@ let build_shared lib ~sctx ~dir ~flags =
; Dep src
]
in
let build =
if Lib_archives.has_native_archive lib ctx.lib_config dir_contents then
Build.path (Path.build (Library.archive lib ~dir ~ext:ext_lib))
>>> build
else
build
in
Super_context.add_rule sctx build ~dir)

let setup_build_archives (lib : Dune_file.Library.t) ~cctx
let setup_build_archives (lib : Dune_file.Library.t) ~dir_contents ~cctx
~(dep_graphs : Dep_graph.Ml_kind.t) ~expander =
let dir = Compilation_context.dir cctx in
let obj_dir = Compilation_context.obj_dir cctx in
Expand Down Expand Up @@ -273,7 +287,7 @@ let setup_build_archives (lib : Dune_file.Library.t) ~cctx
Cm_files.make ~obj_dir ~ext_obj ~modules ~top_sorted_modules
in
Mode.Dict.Set.iter modes ~f:(fun mode ->
build_lib lib ~sctx ~expander ~flags ~dir ~mode ~cm_files));
build_lib lib ~dir_contents ~sctx ~expander ~flags ~dir ~mode ~cm_files));
(* Build *.cma.js *)
if modes.byte then
Super_context.add_rules sctx ~dir
Expand All @@ -287,7 +301,7 @@ let setup_build_archives (lib : Dune_file.Library.t) ~cctx
in
Js_of_ocaml_rules.build_cm cctx ~js_of_ocaml ~src ~target);
if Dynlink_supported.By_the_os.get natdynlink_supported && modes.native then
build_shared ~sctx lib ~dir ~flags
build_shared ~dir_contents ~sctx lib ~dir ~flags

let cctx (lib : Library.t) ~sctx ~source_modules ~dir ~expander ~scope
~compile_info =
Expand Down Expand Up @@ -351,7 +365,7 @@ let library_rules (lib : Library.t) ~cctx ~source_modules ~dir_contents
Module_compilation.build_all cctx ~dep_graphs;
let expander = Super_context.expander sctx ~dir in
if not (Library.is_virtual lib) then
setup_build_archives lib ~cctx ~dep_graphs ~expander;
setup_build_archives lib ~dir_contents ~cctx ~dep_graphs ~expander;
let () =
let vlib_stubs_o_files = Vimpl.vlib_stubs_o_files vimpl in
if Library.has_foreign lib || List.is_non_empty vlib_stubs_o_files then
Expand Down
10 changes: 10 additions & 0 deletions src/dune/modules.ml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ module Wrapped = struct
; wrapped : Mode.t
}

let empty t = Module_name.Map.is_empty t.modules

let encode
{ modules; wrapped_compat; alias_module; main_module_name; wrapped } =
let open Dune_lang.Encoder in
Expand Down Expand Up @@ -752,3 +754,11 @@ let relocate_alias_module t ~src_dir =
match t with
| Wrapped t -> Wrapped (Wrapped.relocate_alias_module t ~src_dir)
| s -> s

let is_empty = function
| Stdlib _
| Impl _
| Singleton _ ->
false
| Unwrapped w -> Module_name.Map.is_empty w
| Wrapped w -> Wrapped.empty w
2 changes: 2 additions & 0 deletions src/dune/modules.mli
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,5 @@ val exit_module : t -> Module.t option
(** [relcoate_alias_module t ~src_dir] sets the source directory of the alias
module to [src_dir]. Only works if [t] is wrapped. *)
val relocate_alias_module : t -> src_dir:Path.t -> t

val is_empty : t -> bool