Skip to content

Commit 258df6b

Browse files
committed
feat(oxcaml): add parameters field for libraries
Signed-off-by: ArthurW <arthur@tarides.com>
1 parent ccbb32a commit 258df6b

File tree

16 files changed

+568
-13
lines changed

16 files changed

+568
-13
lines changed

doc/reference/dune/library.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,14 @@ order to declare a multi-directory library, you need to use the
217217

218218
See :doc:`/virtual-libraries` or :doc:`/reference/dune/library_parameter`.
219219

220+
.. describe:: (parameters <library-parameter-names>)
221+
222+
List the library parameters used by the library and its dependencies.
223+
224+
This feature is experimental and requires the compiler you are using to
225+
support parameterized libraries.
226+
See :doc:`/reference/dune/library_parameter`.
227+
220228
.. describe:: (js_of_ocaml ...)
221229

222230
Sets options for JavaScript compilation, see :ref:`jsoo-field`.

src/dune_rules/compilation_context.ml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ type t =
8888
; requires_hidden : Lib.t list Resolve.Memo.t
8989
; requires_link : Lib.t list Resolve.t Memo.Lazy.t
9090
; implements : Virtual_rules.t
91+
; parameters : Module_name.t list Resolve.Memo.t
9192
; includes : Includes.t
9293
; preprocessing : Pp_spec.t
9394
; opaque : bool
@@ -112,6 +113,7 @@ let flags t = t.flags
112113
let requires_compile t = t.requires_compile
113114
let requires_hidden t = t.requires_hidden
114115
let requires_link t = Memo.Lazy.force t.requires_link
116+
let parameters t = t.parameters
115117
let includes t = t.includes
116118
let preprocessing t = t.preprocessing
117119
let opaque t = t.opaque
@@ -128,6 +130,19 @@ let context t = Super_context.context t.super_context
128130
let dep_graphs t = t.modules.dep_graphs
129131
let ocaml t = t.ocaml
130132

133+
let parameters_main_modules parameters =
134+
let open Resolve.Memo.O in
135+
let* parameters = parameters in
136+
Resolve.Memo.List.map parameters ~f:(fun param ->
137+
let+ main = Lib.main_module_name param in
138+
match main with
139+
| Some main -> main
140+
| None ->
141+
Code_error.raise
142+
"Expected library parameter to have a main module"
143+
[ "param", Lib.to_dyn param ])
144+
;;
145+
131146
let create
132147
~super_context
133148
~scope
@@ -143,6 +158,7 @@ let create
143158
~package
144159
~melange_package_name
145160
?(implements = Virtual_rules.no_implements)
161+
?parameters
146162
?modes
147163
?bin_annot
148164
?loc
@@ -166,6 +182,11 @@ let create
166182
in
167183
requires_compile, requires_hidden
168184
in
185+
let parameters =
186+
match parameters with
187+
| None -> Resolve.Memo.return []
188+
| Some parameters -> parameters_main_modules parameters
189+
in
169190
let sandbox = Sandbox_config.no_special_requirements in
170191
let modes =
171192
let default =
@@ -201,6 +222,7 @@ let create
201222
; requires_hidden = hidden_requires
202223
; requires_link
203224
; implements
225+
; parameters
204226
; includes =
205227
Includes.make ~project ~opaque ~direct_requires ~hidden_requires ocaml.lib_config
206228
; preprocessing

src/dune_rules/compilation_context.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ val create
3434
-> package:Package.t option
3535
-> melange_package_name:Lib_name.t option
3636
-> ?implements:Virtual_rules.t
37+
-> ?parameters:Lib.t list Resolve.Memo.t
3738
-> ?modes:Mode_conf.Set.Details.t Lib_mode.Map.t
3839
-> ?bin_annot:bool
3940
-> ?loc:Loc.t
@@ -57,6 +58,7 @@ val flags : t -> Ocaml_flags.t
5758
val requires_link : t -> Lib.t list Resolve.Memo.t
5859
val requires_hidden : t -> Lib.t list Resolve.Memo.t
5960
val requires_compile : t -> Lib.t list Resolve.Memo.t
61+
val parameters : t -> Module_name.t list Resolve.Memo.t
6062
val includes : t -> Command.Args.without_targets Command.Args.t Lib_mode.Cm_kind.Map.t
6163
val preprocessing : t -> Pp_spec.t
6264
val opaque : t -> bool

src/dune_rules/dune_package.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ module Lib = struct
9292
let sub_systems = Lib_info.sub_systems info in
9393
let plugins = Lib_info.plugins info in
9494
let requires = Lib_info.requires info in
95+
let parameters = Lib_info.parameters info in
9596
let foreign_objects =
9697
match Lib_info.foreign_objects info with
9798
| External e -> e
@@ -138,6 +139,7 @@ module Lib = struct
138139
; paths "jsoo_runtime" jsoo_runtime
139140
; paths "wasmoo_runtime" wasmoo_runtime
140141
; Lib_dep.L.field_encode requires ~name:"requires"
142+
; field_l "parameters" (no_loc Lib_name.encode) parameters
141143
; libs "ppx_runtime_deps" ppx_runtime_deps
142144
; field_o "implements" (no_loc Lib_name.encode) implements
143145
; field_o "default_implementation" (no_loc Lib_name.encode) default_implementation
@@ -228,6 +230,7 @@ module Lib = struct
228230
and+ wasmoo_runtime = paths "wasmoo_runtime"
229231
and+ melange_runtime_deps = paths "melange_runtime_deps"
230232
and+ requires = field_l "requires" (Lib_dep.decode ~allow_re_export:true)
233+
and+ parameters = field "parameters" ~default:[] (repeat (located Lib_name.decode))
231234
and+ ppx_runtime_deps = libs "ppx_runtime_deps"
232235
and+ sub_systems = Sub_system_info.record_parser
233236
and+ orig_src_dir = field_o "orig_src_dir" path
@@ -280,6 +283,7 @@ module Lib = struct
280283
~main_module_name
281284
~sub_systems
282285
~requires
286+
~parameters
283287
~foreign_objects
284288
~public_headers
285289
~plugins

src/dune_rules/findlib.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ let to_dune_library (t : Findlib.Package.t) ~dir_contents ~ext_lib ~external_loc
141141
let dune_version = None in
142142
let virtual_deps = [] in
143143
let implements = None in
144+
let parameters = [] in
144145
let orig_src_dir = None in
145146
let main_module_name : Lib_info.Main_module_name.t = This None in
146147
let enabled = Memo.return Lib_info.Enabled_status.Normal in
@@ -253,6 +254,7 @@ let to_dune_library (t : Findlib.Package.t) ~dir_contents ~ext_lib ~external_loc
253254
~main_module_name
254255
~sub_systems
255256
~requires
257+
~parameters
256258
~foreign_objects
257259
~public_headers
258260
~plugins

src/dune_rules/lib.ml

Lines changed: 101 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,30 @@ module Error = struct
247247
(Lib_name.to_string lib)
248248
]
249249
;;
250+
251+
let expected_parameter ~loc ~name =
252+
make
253+
~loc
254+
[ Pp.textf "Expected %S to be a library parameter." (Lib_name.to_string name) ]
255+
;;
256+
257+
let duplicate_parameters ~loc name name' =
258+
make
259+
~loc
260+
[ Pp.textf
261+
"Duplicate library parameters: %S and %S."
262+
(Lib_name.to_string name)
263+
(Lib_name.to_string name')
264+
]
265+
;;
266+
267+
let missing_parameter ~loc p =
268+
let name = Lib_name.to_string (Lib_info.name p) in
269+
make_resolve
270+
~loc
271+
[ Pp.textf "Parameter %S is missing." name ]
272+
~hints:[ Pp.textf "Add (parameters %s)" name ]
273+
;;
250274
end
251275

252276
(* Types *)
@@ -337,6 +361,7 @@ module T = struct
337361
; ppx_runtime_deps : t list Resolve.t
338362
; pps : t list Resolve.t
339363
; resolved_selects : Resolved_select.t list Resolve.t
364+
; parameters : t list Resolve.t
340365
; implements : t Resolve.t option
341366
; project : Dune_project.t option
342367
; (* these fields cannot be forced until the library is instantiated *)
@@ -430,6 +455,7 @@ let name t = t.name
430455
let info t = t.info
431456
let project t = t.project
432457
let implements t = Option.map ~f:Memo.return t.implements
458+
let parameters t = Resolve.Memo.lift t.parameters
433459
let requires t = Memo.return t.requires
434460
let re_exports t = Memo.return t.re_exports
435461
let ppx_runtime_deps t = Memo.return t.ppx_runtime_deps
@@ -456,6 +482,21 @@ let main_module_name t =
456482
| From _ -> assert false)
457483
;;
458484

485+
module Parameterized = struct
486+
let check ~loc ~parameters lib =
487+
let open Resolve.O in
488+
let* lib = lib in
489+
let* required_parameters = lib.parameters in
490+
let+ () =
491+
Resolve.List.iter required_parameters ~f:(function
492+
| param when not (List.exists parameters ~f:(equal param)) ->
493+
Error.missing_parameter ~loc param.info
494+
| _ -> Resolve.return ())
495+
in
496+
lib
497+
;;
498+
end
499+
459500
let wrapped t =
460501
match Lib_info.wrapped t.info with
461502
| None -> Resolve.Memo.return None
@@ -861,6 +902,7 @@ module rec Resolve_names : sig
861902
: db
862903
-> Lib_dep.t list
863904
-> private_deps:private_deps
905+
-> parameters:t list
864906
-> pps:(Loc.t * Lib_name.t) list
865907
-> dune_version:Dune_lang.Syntax.Version.t option
866908
-> Resolved.t Memo.t
@@ -898,6 +940,32 @@ end = struct
898940
>>| Package.Name.Map.of_list_exn)
899941
;;
900942

943+
let resolve_parameters db ~private_deps info =
944+
let open Resolve.Memo.O in
945+
let* parameters =
946+
Resolve.Memo.List.filter_map (Lib_info.parameters info) ~f:(fun (loc, name) ->
947+
let* lib = Resolve.Memo.lift_memo (resolve_dep db ~private_deps (loc, name)) in
948+
match lib with
949+
| None -> Resolve.Memo.return None
950+
| Some lib ->
951+
let* lib = Resolve.Memo.lift lib in
952+
(match Lib_info.kind lib.info with
953+
| Parameter -> Resolve.Memo.return (Some (loc, name, lib))
954+
| _ -> Error.expected_parameter ~loc ~name))
955+
in
956+
let parameters =
957+
List.stable_sort parameters ~compare:(fun (_, _, a) (_, _, b) -> compare a b)
958+
in
959+
let rec check_duplicates = function
960+
| [] | [ _ ] -> Resolve.Memo.return ()
961+
| (_, name, p) :: (loc, name', p') :: _ when p = p' ->
962+
Error.duplicate_parameters ~loc name name'
963+
| _ :: ps -> check_duplicates ps
964+
in
965+
let+ () = check_duplicates parameters in
966+
List.map parameters ~f:(fun (_, _, param) -> param)
967+
;;
968+
901969
let instantiate_impl db (name, info, hidden) =
902970
let db = Lazy.force db in
903971
let open Memo.O in
@@ -925,6 +993,7 @@ end = struct
925993
in this position."
926994
]
927995
in
996+
let* parameters = resolve_parameters db ~private_deps info in
928997
let* resolved =
929998
let open Resolve.Memo.O in
930999
let* pps =
@@ -935,9 +1004,10 @@ end = struct
9351004
|> Instrumentation.with_instrumentation ~instrumentation_backend
9361005
>>| Preprocess.Per_module.pps
9371006
in
1007+
let* parameters = Resolve.Memo.lift parameters in
9381008
let dune_version = Lib_info.dune_version info in
9391009
Lib_info.requires info
940-
|> resolve_deps_and_add_runtime_deps db ~private_deps ~dune_version ~pps
1010+
|> resolve_deps_and_add_runtime_deps db ~private_deps ~parameters ~dune_version ~pps
9411011
|> Memo.map ~f:Resolve.return
9421012
in
9431013
let* implements =
@@ -1067,6 +1137,7 @@ end = struct
10671137
; resolved_selects
10681138
; re_exports
10691139
; implements
1140+
; parameters
10701141
; default_implementation
10711142
; project
10721143
; sub_systems =
@@ -1398,17 +1469,23 @@ end = struct
13981469
res, { Resolved_select.src_fn; dst_fn = result_fn }
13991470
;;
14001471

1401-
let resolve_complex_deps db deps ~private_deps : Resolved.deps Memo.t =
1472+
let resolve_complex_deps db deps ~private_deps ~parameters : Resolved.deps Memo.t =
1473+
let open Memo.O in
1474+
let resolve_parameterized_dep (loc, lib) =
1475+
resolve_dep db (loc, lib) ~private_deps
1476+
>>| function
1477+
| None -> None
1478+
| Some dep -> Some (Parameterized.check ~loc ~parameters dep)
1479+
in
14021480
Memo.List.fold_left ~init:Resolved.Builder.empty deps ~f:(fun acc (dep : Lib_dep.t) ->
1403-
let open Memo.O in
14041481
match dep with
14051482
| Re_export lib ->
1406-
resolve_dep db lib ~private_deps
1483+
resolve_parameterized_dep lib
14071484
>>| (function
14081485
| None -> acc
14091486
| Some lib -> Resolved.Builder.add_re_exports acc lib)
14101487
| Direct lib ->
1411-
resolve_dep db lib ~private_deps
1488+
resolve_parameterized_dep lib
14121489
>>| (function
14131490
| None -> acc
14141491
| Some lib -> Resolved.Builder.add_resolved acc lib)
@@ -1475,6 +1552,7 @@ end = struct
14751552
db
14761553
{ Resolved.resolved; selects; re_exports }
14771554
~private_deps
1555+
~parameters
14781556
~pps
14791557
~dune_version
14801558
: Resolved.t Memo.t
@@ -1485,15 +1563,22 @@ end = struct
14851563
let open Resolve.Memo.O in
14861564
let* resolved = Memo.return resolved in
14871565
let* runtime_deps = runtime_deps in
1488-
re_exports_closure (resolved @ runtime_deps)
1566+
re_exports_closure (resolved @ runtime_deps @ parameters)
14891567
and+ pps = pps in
14901568
{ Resolved.requires; pps; selects; re_exports }
14911569
;;
14921570

1493-
let resolve_deps_and_add_runtime_deps db deps ~private_deps ~pps ~dune_version =
1571+
let resolve_deps_and_add_runtime_deps
1572+
db
1573+
deps
1574+
~private_deps
1575+
~parameters
1576+
~pps
1577+
~dune_version
1578+
=
14941579
let open Memo.O in
1495-
resolve_complex_deps db ~private_deps deps
1496-
>>= add_pp_runtime_deps db ~private_deps ~dune_version ~pps
1580+
resolve_complex_deps db ~private_deps ~parameters deps
1581+
>>= add_pp_runtime_deps db ~private_deps ~parameters ~dune_version ~pps
14971582
;;
14981583

14991584
(* Compute transitive closure of libraries to figure which ones will trigger
@@ -2058,6 +2143,7 @@ module DB = struct
20582143
t
20592144
deps
20602145
~pps
2146+
~parameters:[]
20612147
~private_deps:Allow_all
20622148
~dune_version:(Some dune_version))
20632149
in
@@ -2193,6 +2279,11 @@ let to_dune_lib
21932279
use_public_name
21942280
~info_field:(Lib_info.implements info)
21952281
~lib_field:(Option.map ~f:Memo.return lib.implements)
2282+
and+ parameters =
2283+
let+ lib_parameters = Resolve.Memo.lift lib.parameters in
2284+
List.map
2285+
(List.combine (Lib_info.parameters info) lib_parameters)
2286+
~f:(fun ((loc, _), param) -> loc, mangled_name param)
21962287
and+ default_implementation =
21972288
use_public_name
21982289
~info_field:(Lib_info.default_implementation info)
@@ -2223,6 +2314,7 @@ let to_dune_lib
22232314
~foreign_objects
22242315
~obj_dir
22252316
~implements
2317+
~parameters
22262318
~default_implementation
22272319
~sub_systems
22282320
~modules

src/dune_rules/lib.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ val to_dyn : t -> Dyn.t
1212
val name : t -> Lib_name.t
1313

1414
val implements : t -> t Resolve.Memo.t option
15+
val parameters : t -> t list Resolve.Memo.t
1516

1617
(** [is_local t] returns [true] whenever [t] is defined in the local workspace *)
1718
val is_local : t -> bool

0 commit comments

Comments
 (0)