Split library rules into more logical steps
Signed-off-by: Rudi Grinberg <rudi.grinberg@gmail.com>
This commit is contained in:
parent
ce0042bbe5
commit
9c7bb2878a
309
src/lib_rules.ml
309
src/lib_rules.ml
|
@ -86,6 +86,39 @@ module Gen (P : Install_rules.Params) = struct
|
||||||
| Native -> [Library.archive lib ~dir ~ext:ctx.ext_lib])
|
| Native -> [Library.archive lib ~dir ~ext:ctx.ext_lib])
|
||||||
]))
|
]))
|
||||||
|
|
||||||
|
(* If the compiler reads the cmi for module alias even with
|
||||||
|
[-w -49 -no-alias-deps], we must sandbox the build of the
|
||||||
|
alias module since the modules it references are built after. *)
|
||||||
|
let alias_module_build_sandbox =
|
||||||
|
Ocaml_version.always_reads_alias_cmi ctx.version
|
||||||
|
|
||||||
|
let build_alias_module (m : Module.t) ~main_module_name ~modules ~cctx
|
||||||
|
~dynlink ~js_of_ocaml =
|
||||||
|
let file =
|
||||||
|
match m.impl with
|
||||||
|
| Some f -> f
|
||||||
|
| None -> Option.value_exn m.intf
|
||||||
|
in
|
||||||
|
SC.add_rule sctx
|
||||||
|
(Build.return
|
||||||
|
(Module.Name.Map.values (Module.Name.Map.remove modules m.name)
|
||||||
|
|> List.map ~f:(fun (m : Module.t) ->
|
||||||
|
sprintf "(** @canonical %s.%s *)\n\
|
||||||
|
module %s = %s\n"
|
||||||
|
(Module.Name.to_string main_module_name)
|
||||||
|
(Module.Name.to_string m.name)
|
||||||
|
(Module.Name.to_string m.name)
|
||||||
|
(Module.Name.to_string (Module.real_unit_name m))
|
||||||
|
)
|
||||||
|
|> String.concat ~sep:"\n")
|
||||||
|
>>> Build.write_file_dyn file.path);
|
||||||
|
let cctx = Compilation_context.for_alias_module cctx in
|
||||||
|
Module_compilation.build_module cctx m
|
||||||
|
~js_of_ocaml
|
||||||
|
~dynlink
|
||||||
|
~sandbox:alias_module_build_sandbox
|
||||||
|
~dep_graphs:(Ocamldep.Dep_graphs.dummy m)
|
||||||
|
|
||||||
let build_c_file (lib : Library.t) ~scope ~dir ~includes (src, dst) =
|
let build_c_file (lib : Library.t) ~scope ~dir ~includes (src, dst) =
|
||||||
SC.add_rule sctx
|
SC.add_rule sctx
|
||||||
(SC.expand_and_eval_set sctx ~scope ~dir lib.c_flags
|
(SC.expand_and_eval_set sctx ~scope ~dir lib.c_flags
|
||||||
|
@ -130,11 +163,124 @@ module Gen (P : Install_rules.Params) = struct
|
||||||
]));
|
]));
|
||||||
dst
|
dst
|
||||||
|
|
||||||
(* If the compiler reads the cmi for module alias even with
|
let ocamlmklib (lib : Library.t) ~dir ~scope ~o_files ~sandbox ~custom
|
||||||
[-w -49 -no-alias-deps], we must sandbox the build of the
|
~targets =
|
||||||
alias module since the modules it references are built after. *)
|
SC.add_rule sctx ~sandbox
|
||||||
let alias_module_build_sandbox =
|
(SC.expand_and_eval_set sctx ~scope ~dir
|
||||||
Ocaml_version.always_reads_alias_cmi ctx.version
|
lib.c_library_flags ~standard:(Build.return [])
|
||||||
|
>>>
|
||||||
|
Build.run ~context:ctx
|
||||||
|
(Ok ctx.ocamlmklib)
|
||||||
|
[ As (Utils.g ())
|
||||||
|
; if custom then A "-custom" else As []
|
||||||
|
; A "-o"
|
||||||
|
; Path (Path.relative dir (sprintf "%s_stubs" lib.name))
|
||||||
|
; Deps o_files
|
||||||
|
; Dyn (fun cclibs ->
|
||||||
|
(* https://github.com/ocaml/dune/issues/119 *)
|
||||||
|
if ctx.ccomp_type = "msvc" then
|
||||||
|
let cclibs = msvc_hack_cclibs cclibs in
|
||||||
|
Arg_spec.quote_args "-ldopt" cclibs
|
||||||
|
else
|
||||||
|
As cclibs
|
||||||
|
)
|
||||||
|
; Hidden_targets targets
|
||||||
|
])
|
||||||
|
|
||||||
|
let build_self_stubs lib ~scope ~dir ~o_files =
|
||||||
|
let static = Library.stubs_archive lib ~dir ~ext_lib:ctx.ext_lib in
|
||||||
|
let dynamic = Library.dll lib ~dir ~ext_dll:ctx.ext_dll in
|
||||||
|
let modes =
|
||||||
|
Mode_conf.Set.eval lib.modes
|
||||||
|
~has_native:(Option.is_some ctx.ocamlopt) in
|
||||||
|
let ocamlmklib = ocamlmklib lib ~scope ~dir ~o_files in
|
||||||
|
if modes.native &&
|
||||||
|
modes.byte &&
|
||||||
|
lib.dynlink
|
||||||
|
then begin
|
||||||
|
(* If we build for both modes and support dynlink, use a
|
||||||
|
single invocation to build both the static and dynamic
|
||||||
|
libraries *)
|
||||||
|
ocamlmklib ~sandbox:false ~custom:false ~targets:[static; dynamic]
|
||||||
|
end else begin
|
||||||
|
ocamlmklib ~sandbox:false ~custom:true ~targets:[static];
|
||||||
|
(* We can't tell ocamlmklib to build only the dll, so we
|
||||||
|
sandbox the action to avoid overriding the static archive *)
|
||||||
|
ocamlmklib ~sandbox:true ~custom:false ~targets:[dynamic]
|
||||||
|
end
|
||||||
|
|
||||||
|
let build_stubs lib ~dir ~scope ~requires ~dir_contents =
|
||||||
|
let all_dirs = Dir_contents.dirs dir_contents in
|
||||||
|
let h_files =
|
||||||
|
List.fold_left all_dirs ~init:[] ~f:(fun acc dc ->
|
||||||
|
String.Set.fold (Dir_contents.text_files dc) ~init:acc
|
||||||
|
~f:(fun fn acc ->
|
||||||
|
if String.is_suffix fn ~suffix:".h" then
|
||||||
|
Path.relative (Dir_contents.dir dc) fn :: acc
|
||||||
|
else
|
||||||
|
acc))
|
||||||
|
in
|
||||||
|
let all_dirs = Path.Set.of_list (List.map all_dirs ~f:Dir_contents.dir) in
|
||||||
|
let resolve_name ~ext (loc, fn) =
|
||||||
|
let p = Path.relative dir (fn ^ ext) in
|
||||||
|
if not (match Path.parent p with
|
||||||
|
| None -> false
|
||||||
|
| Some p -> Path.Set.mem all_dirs p) then
|
||||||
|
Loc.fail loc
|
||||||
|
"File %a is not part of the current directory group. \
|
||||||
|
This is not allowed."
|
||||||
|
Path.pp (Path.drop_optional_build_context p)
|
||||||
|
;
|
||||||
|
(p, Path.relative dir (fn ^ ctx.ext_obj))
|
||||||
|
in
|
||||||
|
let o_files =
|
||||||
|
let includes =
|
||||||
|
Arg_spec.S
|
||||||
|
[ Hidden_deps h_files
|
||||||
|
; Arg_spec.of_result_map requires ~f:(fun libs ->
|
||||||
|
S [ Lib.L.c_include_flags libs ~stdlib_dir:ctx.stdlib_dir
|
||||||
|
; Hidden_deps (SC.Libs.file_deps sctx libs ~ext:".h")
|
||||||
|
])
|
||||||
|
]
|
||||||
|
in
|
||||||
|
List.map lib.c_names ~f:(fun name ->
|
||||||
|
build_c_file lib ~scope ~dir ~includes (resolve_name name ~ext:".c")
|
||||||
|
) @ List.map lib.cxx_names ~f:(fun name ->
|
||||||
|
build_cxx_file lib ~scope ~dir ~includes (resolve_name name ~ext:".cpp")
|
||||||
|
)
|
||||||
|
in
|
||||||
|
match lib.self_build_stubs_archive with
|
||||||
|
| Some _ -> ()
|
||||||
|
| None -> build_self_stubs lib ~dir ~scope ~o_files
|
||||||
|
|
||||||
|
let build_shared lib ~dir ~flags ~(ctx : Context.t) =
|
||||||
|
Option.iter ctx.ocamlopt ~f:(fun ocamlopt ->
|
||||||
|
let src = Library.archive lib ~dir ~ext:(Mode.compiled_lib_ext Native) in
|
||||||
|
let dst = Library.archive lib ~dir ~ext:".cmxs" in
|
||||||
|
let build =
|
||||||
|
Build.dyn_paths (Build.arr (fun () ->
|
||||||
|
[Library.archive lib ~dir ~ext:ctx.ext_lib]))
|
||||||
|
>>>
|
||||||
|
Ocaml_flags.get flags Native
|
||||||
|
>>>
|
||||||
|
Build.run ~context:ctx
|
||||||
|
(Ok ocamlopt)
|
||||||
|
[ Dyn (fun flags -> As flags)
|
||||||
|
; A "-shared"; A "-linkall"
|
||||||
|
; A "-I"; Path dir
|
||||||
|
; A "-o"; Target dst
|
||||||
|
; Dep src
|
||||||
|
]
|
||||||
|
in
|
||||||
|
let build =
|
||||||
|
if Library.has_stubs lib then
|
||||||
|
Build.path (Library.stubs_archive ~dir lib ~ext_lib:ctx.ext_lib)
|
||||||
|
>>>
|
||||||
|
build
|
||||||
|
else
|
||||||
|
build
|
||||||
|
in
|
||||||
|
SC.add_rule sctx build)
|
||||||
|
|
||||||
let library_rules (lib : Library.t) ~dir_contents ~dir ~scope
|
let library_rules (lib : Library.t) ~dir_contents ~dir ~scope
|
||||||
~compile_info ~dir_kind =
|
~compile_info ~dir_kind =
|
||||||
|
@ -194,125 +340,16 @@ module Gen (P : Install_rules.Params) = struct
|
||||||
|
|
||||||
let dep_graphs = Ocamldep.rules cctx in
|
let dep_graphs = Ocamldep.rules cctx in
|
||||||
|
|
||||||
Option.iter alias_module ~f:(fun m ->
|
|
||||||
let file =
|
|
||||||
match m.impl with
|
|
||||||
| Some f -> f
|
|
||||||
| None -> Option.value_exn m.intf
|
|
||||||
in
|
|
||||||
SC.add_rule sctx
|
|
||||||
(Build.return
|
|
||||||
(Module.Name.Map.values (Module.Name.Map.remove modules m.name)
|
|
||||||
|> List.map ~f:(fun (m : Module.t) ->
|
|
||||||
sprintf "(** @canonical %s.%s *)\n\
|
|
||||||
module %s = %s\n"
|
|
||||||
(Module.Name.to_string main_module_name)
|
|
||||||
(Module.Name.to_string m.name)
|
|
||||||
(Module.Name.to_string m.name)
|
|
||||||
(Module.Name.to_string (Module.real_unit_name m))
|
|
||||||
)
|
|
||||||
|> String.concat ~sep:"\n")
|
|
||||||
>>> Build.write_file_dyn file.path));
|
|
||||||
|
|
||||||
|
|
||||||
let dynlink = lib.dynlink in
|
let dynlink = lib.dynlink in
|
||||||
let js_of_ocaml = lib.buildable.js_of_ocaml in
|
let js_of_ocaml = lib.buildable.js_of_ocaml in
|
||||||
Module_compilation.build_modules cctx ~js_of_ocaml ~dynlink ~dep_graphs;
|
Module_compilation.build_modules cctx ~js_of_ocaml ~dynlink ~dep_graphs;
|
||||||
Option.iter alias_module ~f:(fun m ->
|
|
||||||
let cctx = Compilation_context.for_alias_module cctx in
|
|
||||||
Module_compilation.build_module cctx m
|
|
||||||
~js_of_ocaml
|
|
||||||
~dynlink
|
|
||||||
~sandbox:alias_module_build_sandbox
|
|
||||||
~dep_graphs:(Ocamldep.Dep_graphs.dummy m));
|
|
||||||
|
|
||||||
if Library.has_stubs lib then begin
|
Option.iter alias_module
|
||||||
let all_dirs = Dir_contents.dirs dir_contents in
|
~f:(build_alias_module ~main_module_name ~modules ~cctx ~dynlink
|
||||||
let h_files =
|
~js_of_ocaml);
|
||||||
List.fold_left all_dirs ~init:[] ~f:(fun acc dc ->
|
|
||||||
String.Set.fold (Dir_contents.text_files dc) ~init:acc
|
if Library.has_stubs lib then
|
||||||
~f:(fun fn acc ->
|
build_stubs lib ~dir ~scope ~requires ~dir_contents;
|
||||||
if String.is_suffix fn ~suffix:".h" then
|
|
||||||
Path.relative (Dir_contents.dir dc) fn :: acc
|
|
||||||
else
|
|
||||||
acc))
|
|
||||||
in
|
|
||||||
let all_dirs = Path.Set.of_list (List.map all_dirs ~f:Dir_contents.dir) in
|
|
||||||
let resolve_name ~ext (loc, fn) =
|
|
||||||
let p = Path.relative dir (fn ^ ext) in
|
|
||||||
if not (match Path.parent p with
|
|
||||||
| None -> false
|
|
||||||
| Some p -> Path.Set.mem all_dirs p) then
|
|
||||||
Loc.fail loc
|
|
||||||
"File %a is not part of the current directory group. \
|
|
||||||
This is not allowed."
|
|
||||||
Path.pp (Path.drop_optional_build_context p)
|
|
||||||
;
|
|
||||||
(p, Path.relative dir (fn ^ ctx.ext_obj))
|
|
||||||
in
|
|
||||||
let o_files =
|
|
||||||
let includes =
|
|
||||||
Arg_spec.S
|
|
||||||
[ Hidden_deps h_files
|
|
||||||
; Arg_spec.of_result_map requires ~f:(fun libs ->
|
|
||||||
S [ Lib.L.c_include_flags libs ~stdlib_dir:ctx.stdlib_dir
|
|
||||||
; Hidden_deps (SC.Libs.file_deps sctx libs ~ext:".h")
|
|
||||||
])
|
|
||||||
]
|
|
||||||
in
|
|
||||||
List.map lib.c_names ~f:(fun name ->
|
|
||||||
build_c_file lib ~scope ~dir ~includes (resolve_name name ~ext:".c")
|
|
||||||
) @ List.map lib.cxx_names ~f:(fun name ->
|
|
||||||
build_cxx_file lib ~scope ~dir ~includes (resolve_name name ~ext:".cpp")
|
|
||||||
)
|
|
||||||
in
|
|
||||||
match lib.self_build_stubs_archive with
|
|
||||||
| Some _ -> ()
|
|
||||||
| None ->
|
|
||||||
let ocamlmklib ~sandbox ~custom ~targets =
|
|
||||||
SC.add_rule sctx ~sandbox
|
|
||||||
(SC.expand_and_eval_set sctx ~scope ~dir
|
|
||||||
lib.c_library_flags ~standard:(Build.return [])
|
|
||||||
>>>
|
|
||||||
Build.run ~context:ctx
|
|
||||||
(Ok ctx.ocamlmklib)
|
|
||||||
[ As (Utils.g ())
|
|
||||||
; if custom then A "-custom" else As []
|
|
||||||
; A "-o"
|
|
||||||
; Path (Path.relative dir (sprintf "%s_stubs" lib.name))
|
|
||||||
; Deps o_files
|
|
||||||
; Dyn (fun cclibs ->
|
|
||||||
(* https://github.com/ocaml/dune/issues/119 *)
|
|
||||||
if ctx.ccomp_type = "msvc" then
|
|
||||||
let cclibs = msvc_hack_cclibs cclibs in
|
|
||||||
Arg_spec.quote_args "-ldopt" cclibs
|
|
||||||
else
|
|
||||||
As cclibs
|
|
||||||
)
|
|
||||||
; Hidden_targets targets
|
|
||||||
])
|
|
||||||
in
|
|
||||||
let static = Library.stubs_archive lib ~dir ~ext_lib:ctx.ext_lib in
|
|
||||||
let dynamic = Library.dll lib ~dir ~ext_dll:ctx.ext_dll in
|
|
||||||
let modes =
|
|
||||||
Mode_conf.Set.eval lib.modes
|
|
||||||
~has_native:(Option.is_some ctx.ocamlopt)
|
|
||||||
in
|
|
||||||
if modes.native &&
|
|
||||||
modes.byte &&
|
|
||||||
lib.dynlink
|
|
||||||
then begin
|
|
||||||
(* If we build for both modes and support dynlink, use a
|
|
||||||
single invocation to build both the static and dynamic
|
|
||||||
libraries *)
|
|
||||||
ocamlmklib ~sandbox:false ~custom:false ~targets:[static; dynamic]
|
|
||||||
end else begin
|
|
||||||
ocamlmklib ~sandbox:false ~custom:true ~targets:[static];
|
|
||||||
(* We can't tell ocamlmklib to build only the dll, so we
|
|
||||||
sandbox the action to avoid overriding the static archive *)
|
|
||||||
ocamlmklib ~sandbox:true ~custom:false ~targets:[dynamic]
|
|
||||||
end
|
|
||||||
end;
|
|
||||||
|
|
||||||
List.iter Cm_kind.all ~f:(fun cm_kind ->
|
List.iter Cm_kind.all ~f:(fun cm_kind ->
|
||||||
let files =
|
let files =
|
||||||
|
@ -346,38 +383,10 @@ module Gen (P : Install_rules.Params) = struct
|
||||||
SC.add_rules sctx (
|
SC.add_rules sctx (
|
||||||
let src = Library.archive lib ~dir ~ext:(Mode.compiled_lib_ext Mode.Byte) in
|
let src = Library.archive lib ~dir ~ext:(Mode.compiled_lib_ext Mode.Byte) in
|
||||||
let target = Path.extend_basename src ~suffix:".js" in
|
let target = Path.extend_basename src ~suffix:".js" in
|
||||||
Js_of_ocaml_rules.build_cm cctx
|
Js_of_ocaml_rules.build_cm cctx ~js_of_ocaml ~src ~target);
|
||||||
~js_of_ocaml:lib.buildable.js_of_ocaml ~src ~target);
|
|
||||||
|
|
||||||
if ctx.natdynlink_supported then
|
if ctx.natdynlink_supported then
|
||||||
Option.iter ctx.ocamlopt ~f:(fun ocamlopt ->
|
build_shared lib ~dir ~flags ~ctx;
|
||||||
let src = Library.archive lib ~dir ~ext:(Mode.compiled_lib_ext Native) in
|
|
||||||
let dst = Library.archive lib ~dir ~ext:".cmxs" in
|
|
||||||
let build =
|
|
||||||
Build.dyn_paths (Build.arr (fun () ->
|
|
||||||
[Library.archive lib ~dir ~ext:ctx.ext_lib]))
|
|
||||||
>>>
|
|
||||||
Ocaml_flags.get flags Native
|
|
||||||
>>>
|
|
||||||
Build.run ~context:ctx
|
|
||||||
(Ok ocamlopt)
|
|
||||||
[ Dyn (fun flags -> As flags)
|
|
||||||
; A "-shared"; A "-linkall"
|
|
||||||
; A "-I"; Path dir
|
|
||||||
; A "-o"; Target dst
|
|
||||||
; Dep src
|
|
||||||
]
|
|
||||||
in
|
|
||||||
let build =
|
|
||||||
if Library.has_stubs lib then
|
|
||||||
Build.path (Library.stubs_archive ~dir lib ~ext_lib:ctx.ext_lib)
|
|
||||||
>>>
|
|
||||||
build
|
|
||||||
else
|
|
||||||
build
|
|
||||||
in
|
|
||||||
SC.add_rule sctx build
|
|
||||||
);
|
|
||||||
|
|
||||||
Odoc.setup_library_odoc_rules lib ~requires ~modules ~dep_graphs ~scope;
|
Odoc.setup_library_odoc_rules lib ~requires ~modules ~dep_graphs ~scope;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue