-
Notifications
You must be signed in to change notification settings - Fork 415
/
Copy pathvirtual_rules.ml
132 lines (130 loc) · 5.18 KB
/
virtual_rules.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
open Import
open Memo.O
let setup_copy_rules_for_impl ~sctx ~dir vimpl =
let ctx = Super_context.context sctx in
let vlib = Vimpl.vlib vimpl in
let impl = Vimpl.impl vimpl in
let impl_obj_dir = Library.obj_dir ~dir impl in
let vlib_obj_dir = Lib.info vlib |> Lib_info.obj_dir in
let add_rule = Super_context.add_rule sctx ~dir in
let copy_to_obj_dir ~src ~dst =
add_rule ~loc:(Loc.of_pos __POS__) (Action_builder.symlink ~src ~dst)
in
let* { Lib_config.has_native; ext_obj; _ } =
let+ ocaml = Context.ocaml ctx in
ocaml.lib_config
in
let { Lib_mode.Map.ocaml = { byte; native }; melange } =
Mode_conf.Lib.Set.eval impl.modes ~has_native
in
let copy_obj_file m kind =
let src = Obj_dir.Module.cm_file_exn vlib_obj_dir m ~kind in
let dst = Obj_dir.Module.cm_file_exn impl_obj_dir m ~kind in
copy_to_obj_dir ~src ~dst
in
let copy_ocamldep_file m =
match Obj_dir.to_local vlib_obj_dir with
| None -> Memo.return ()
| Some vlib_obj_dir ->
let src = Obj_dir.Module.dep vlib_obj_dir (Immediate (m, Impl)) |> Path.build in
let dst = Obj_dir.Module.dep impl_obj_dir (Immediate (m, Impl)) in
copy_to_obj_dir ~src ~dst
in
let copy_interface_to_impl ~src kind () =
let dst = Obj_dir.Module.cm_public_file_exn impl_obj_dir src ~kind in
let src = Obj_dir.Module.cm_public_file_exn vlib_obj_dir src ~kind in
copy_to_obj_dir ~src ~dst
in
let copy_objs src =
Memo.when_ (byte || native) (fun () -> copy_obj_file src (Ocaml Cmi))
>>> Memo.when_ melange (fun () -> copy_obj_file src (Melange Cmi))
>>> Memo.when_
(Module.visibility src = Public
&& Obj_dir.need_dedicated_public_dir impl_obj_dir)
(fun () ->
Memo.when_ (byte || native) (copy_interface_to_impl ~src (Ocaml Cmi))
>>> Memo.when_ melange (copy_interface_to_impl ~src (Melange Cmi)))
>>> Memo.when_ (Module.has src ~ml_kind:Impl) (fun () ->
Memo.when_ byte (fun () -> copy_obj_file src (Ocaml Cmo))
>>> Memo.when_ melange (fun () ->
copy_obj_file src (Melange Cmj) >>> copy_ocamldep_file src)
>>> Memo.when_ native (fun () ->
copy_obj_file src (Ocaml Cmx)
>>>
let object_file dir = Obj_dir.Module.o_file_exn dir src ~ext_obj in
copy_to_obj_dir ~src:(object_file vlib_obj_dir) ~dst:(object_file impl_obj_dir)))
in
let vlib_modules = Vimpl.vlib_modules vimpl in
Modules.fold vlib_modules ~init:(Memo.return ()) ~f:(fun m acc -> acc >>> copy_objs m)
;;
let impl sctx ~(lib : Library.t) ~scope =
match lib.implements with
| None -> Memo.return None
| Some (loc, implements) ->
Lib.DB.find (Scope.libs scope) implements
>>= (function
| None ->
User_error.raise
~loc
[ Pp.textf
"Cannot implement %s as that library isn't available"
(Lib_name.to_string implements)
]
| Some vlib ->
let info = Lib.info vlib in
let virtual_ =
match Lib_info.virtual_ info with
| Some v -> v
| None ->
User_error.raise
~loc:lib.buildable.loc
[ Pp.textf
"Library %s isn't virtual and cannot be implemented"
(Lib_name.to_string implements)
]
in
let+ vlib_modules, vlib_foreign_objects =
let foreign_objects = Lib_info.foreign_objects info in
match virtual_, foreign_objects with
| External _, Local | Local, External _ -> assert false
| External modules, External fa -> Memo.return (modules, fa)
| Local, Local ->
let name = Lib.name vlib in
let vlib = Lib.Local.of_lib_exn vlib in
let* dir_contents =
let info = Lib.Local.info vlib in
let dir = Lib_info.src_dir info in
Dir_contents.get sctx ~dir
in
let* ocaml = Context.ocaml (Super_context.context sctx) in
let* modules =
let db = Scope.libs scope in
let* preprocess =
(* TODO wrong, this should be delayed *)
Preprocess.Per_module.with_instrumentation
lib.buildable.preprocess
~instrumentation_backend:(Lib.DB.instrumentation_backend db)
|> Resolve.Memo.read_memo
in
Dir_contents.ocaml dir_contents
>>= Ml_sources.modules
~libs:db
~for_:(Library (Lib_info.lib_id info |> Lib_id.to_local_exn))
>>=
let pp_spec =
Staged.unstage (Pp_spec.pped_modules_map preprocess ocaml.version)
in
Modules.map_user_written ~f:(fun m -> Memo.return (pp_spec m))
in
let+ foreign_objects =
Dir_contents.foreign_sources dir_contents
>>| Foreign_sources.for_lib ~name
>>| (let ext_obj = ocaml.lib_config.ext_obj in
let dir = Obj_dir.obj_dir (Lib.Local.obj_dir vlib) in
Foreign.Sources.object_files ~ext_obj ~dir)
>>| List.map ~f:Path.build
in
modules, foreign_objects
in
Some (Vimpl.make ~impl:lib ~vlib ~vlib_modules ~vlib_foreign_objects))
;;