dune/src/module_compilation.ml

119 lines
4.4 KiB
OCaml

open Import
open Build.O
open! No_io
module SC = Super_context
let build_cm sctx ?sandbox ~dynlink ~flags ~cm_kind ~(dep_graph:Ocamldep.dep_graph)
~requires ~(modules : Module.t String_map.t) ~dir ~alias_module (m : Module.t) =
let ctx = SC.context sctx in
Option.iter (Mode.of_cm_kind cm_kind |> Context.compiler ctx) ~f:(fun compiler ->
Option.iter (Module.cm_source ~dir m cm_kind) ~f:(fun src ->
let ml_kind = Cm_kind.source cm_kind in
let dst = Module.cm_file m ~dir cm_kind in
let extra_args, extra_deps, extra_targets =
match cm_kind, m.intf with
(* If there is no mli, [ocamlY -c file.ml] produces both the
.cmY and .cmi. We choose to use ocamlc to produce the cmi
and to produce the cmx we have to wait to avoid race
conditions. *)
| Cmo, None -> [], [], [Module.cm_file m ~dir Cmi]
| Cmx, None ->
(* Change [-intf-suffix] so that the compiler thinks the
cmi exists and reads it instead of re-creating it, which
could create a race condition. *)
([ "-intf-suffix"
; Filename.extension m.impl.name
],
[Module.cm_file m ~dir Cmi], [])
| Cmi, None -> assert false
| Cmi, Some _ -> [], [], []
(* We need the .cmi to build either the .cmo or .cmx *)
| (Cmo | Cmx), Some _ -> [], [Module.cm_file m ~dir Cmi], []
in
let extra_targets =
match cm_kind with
| Cmx -> Path.relative dir (m.obj_name ^ ctx.ext_obj) :: extra_targets
| Cmi | Cmo -> extra_targets
in
let dep_graph = Ml_kind.Dict.get dep_graph ml_kind in
let other_cm_files =
Build.dyn_paths
(dep_graph >>^ (fun dep_graph ->
let deps =
List.map (Utils.find_deps ~dir dep_graph m.name)
~f:(Utils.find_module ~dir modules)
in
List.concat_map
deps
~f:(fun m ->
match cm_kind with
| Cmi | Cmo -> [Module.cm_file m ~dir Cmi]
| Cmx -> [Module.cm_file m ~dir Cmi; Module.cm_file m ~dir Cmx])))
in
let extra_targets, cmt_args =
match cm_kind with
| Cmx -> (extra_targets, Arg_spec.S [])
| Cmi | Cmo ->
let fn = Option.value_exn (Module.cmt_file m ~dir ml_kind) in
(fn :: extra_targets, A "-bin-annot")
in
SC.add_rule sctx ?sandbox
(Build.paths extra_deps >>>
other_cm_files >>>
requires &&&
Ocaml_flags.get_for_cm flags ~cm_kind >>>
Build.run ~context:ctx (Ok compiler)
~extra_targets
[ Dyn (fun (_, ocaml_flags) -> As ocaml_flags)
; cmt_args
; Dyn (fun (libs, _) -> Lib.include_flags libs)
; As extra_args
; if dynlink || cm_kind <> Cmx then As [] else A "-nodynlink"
; A "-no-alias-deps"
; A "-I"; Path dir
; (match alias_module with
| None -> S []
| Some (m : Module.t) -> As ["-open"; m.name])
; A "-o"; Target dst
; A "-c"; Ml_kind.flag ml_kind; Dep src
])))
let build_module sctx ?sandbox ~dynlink ~js_of_ocaml ~flags m ~scope ~dir ~dep_graph
~modules ~requires ~alias_module =
List.iter Cm_kind.all ~f:(fun cm_kind ->
let requires = Cm_kind.Dict.get requires cm_kind in
build_cm sctx ?sandbox ~dynlink ~flags ~dir ~dep_graph ~modules m ~cm_kind
~requires ~alias_module);
(* Build *.cmo.js *)
let src = Module.cm_file m ~dir Cm_kind.Cmo in
SC.add_rules sctx (Js_of_ocaml_rules.build_cm sctx ~scope ~dir ~js_of_ocaml ~src)
let build_modules sctx ~dynlink ~js_of_ocaml ~flags ~scope ~dir ~dep_graph ~modules ~requires
~alias_module =
let cmi_requires =
Build.memoize "cmi library dependencies"
(requires
>>>
SC.Libs.file_deps sctx ~ext:".cmi")
in
let cmi_and_cmx_requires =
Build.memoize "cmi and cmx library dependencies"
(requires
>>>
SC.Libs.file_deps sctx ~ext:".cmi-and-.cmx")
in
let requires : _ Cm_kind.Dict.t =
{ cmi = cmi_requires
; cmo = cmi_requires
; cmx = cmi_and_cmx_requires
}
in
String_map.iter
(match alias_module with
| None -> modules
| Some (m : Module.t) -> String_map.remove m.name modules)
~f:(fun ~key:_ ~data:m ->
build_module sctx m ~dynlink ~js_of_ocaml ~flags ~scope ~dir ~dep_graph ~modules ~requires
~alias_module)