dune/src/gen_meta.ml

174 lines
5.2 KiB
OCaml

open! Stdune
open Import
open Meta
module Pub_name = struct
type t =
| Dot of t * string
| Id of string
let parse s =
let s = Lib_name.to_string s in
match String.split s ~on:'.' with
| [] -> assert false
| x :: l ->
let rec loop acc l =
match l with
| [] -> acc
| x :: l -> loop (Dot (acc, x)) l
in
loop (Id x) l
let rec root = function
| Dot (t, _) -> root t
| Id n -> n
let to_list =
let rec loop acc = function
| Dot (t, n) -> loop (n :: acc) t
| Id n -> n :: acc
in
fun t -> loop [] t
let to_string t = String.concat ~sep:"." (to_list t)
end
let string_of_deps deps =
Lib_name.Set.to_string_list deps
|> String.concat ~sep:" "
let rule var predicates action value =
Rule { var; predicates; action; value }
let requires ?(preds=[]) pkgs =
rule "requires" preds Set (string_of_deps pkgs)
let ppx_runtime_deps ?(preds=[]) pkgs =
rule "ppx_runtime_deps" preds Set (string_of_deps pkgs)
let description s = rule "description" [] Set s
let directory s = rule "directory" [] Set s
let archive preds s = rule "archive" preds Set s
let plugin preds s = rule "plugin" preds Set s
let archives ?(preds=[]) lib =
let archives = Lib.archives lib in
let plugins = Lib.plugins lib in
let make ps =
String.concat ~sep:" " (List.map ps ~f:Path.basename)
in
[ archive (preds @ [Pos "byte" ]) (make archives.byte )
; archive (preds @ [Pos "native"]) (make archives.native)
; plugin (preds @ [Pos "byte" ]) (make plugins .byte )
; plugin (preds @ [Pos "native"]) (make plugins .native)
]
let gen_lib pub_name lib ~version =
let desc =
match Lib.synopsis lib with
| Some s -> s
| None ->
(* CR-someday jdimino: wut? this looks old *)
match (pub_name : Pub_name.t) with
| Dot (p, "runtime-lib") ->
sprintf "Runtime library for %s" (Pub_name.to_string p)
| Dot (p, "expander") ->
sprintf "Expander for %s" (Pub_name.to_string p)
| _ -> ""
in
let preds =
match Lib.kind lib with
| Normal -> []
| Ppx_rewriter | Ppx_deriver -> [Pos "ppx_driver"]
in
let lib_deps = Lib.Meta.requires lib in
let ppx_rt_deps = Lib.Meta.ppx_runtime_deps lib in
List.concat
[ version
; [ description desc
; requires ~preds lib_deps
]
; archives ~preds lib
; if Lib_name.Set.is_empty ppx_rt_deps then
[]
else
[ Comment "This is what dune uses to find out the runtime \
dependencies of"
; Comment "a preprocessor"
; ppx_runtime_deps ppx_rt_deps
]
; (match Lib.kind lib with
| Normal -> []
| Ppx_rewriter | Ppx_deriver ->
(* Deprecated ppx method support *)
let no_ppx_driver = Neg "ppx_driver" and no_custom_ppx = Neg "custom_ppx" in
List.concat
[ [ Comment "This line makes things transparent for people mixing \
preprocessors"
; Comment "and normal dependencies"
; requires ~preds:[no_ppx_driver]
(Lib.Meta.ppx_runtime_deps_for_deprecated_method lib)
]
; match Lib.kind lib with
| Normal -> assert false
| Ppx_rewriter ->
[ rule "ppx" [no_ppx_driver; no_custom_ppx]
Set "./ppx.exe --as-ppx" ]
| Ppx_deriver ->
[ rule "requires" [no_ppx_driver; no_custom_ppx] Add
"ppx_deriving"
; rule "ppxopt" [no_ppx_driver; no_custom_ppx] Set
("ppx_deriving,package:" ^ Pub_name.to_string pub_name)
]
]
)
; (match Lib.jsoo_runtime lib with
| [] -> []
| l ->
let root = Pub_name.root pub_name in
let l = List.map l ~f:Path.basename in
[ rule "linkopts" [Pos "javascript"] Set
(List.map l ~f:(sprintf "+%s/%s" root) |> String.concat ~sep:" ")
; rule "jsoo_runtime" [] Set
(String.concat l ~sep:" ")
]
)
]
let gen ~package ~version libs =
let version =
match version with
| None -> []
| Some s -> [rule "version" [] Set s]
in
let pkgs =
List.map libs ~f:(fun lib ->
let pub_name = Pub_name.parse (Lib.name lib) in
(pub_name,
gen_lib pub_name lib ~version))
in
let pkgs =
List.map pkgs ~f:(fun (pn, meta) ->
match Pub_name.to_list pn with
| [] -> assert false
| _package :: path -> (path, meta))
in
let pkgs = List.sort pkgs ~compare:(fun (a, _) (b, _) -> compare a b) in
let rec loop name pkgs =
let entries, sub_pkgs =
List.partition_map pkgs ~f:(function
| ([] , entries) -> Left entries
| (x :: p, entries) -> Right (x, (p, entries)))
in
let entries = List.concat entries in
let subs =
String.Map.of_list_multi sub_pkgs
|> String.Map.to_list
|> List.map ~f:(fun (name, pkgs) ->
let pkg = loop name pkgs in
Package { pkg with
entries = directory name :: pkg.entries
})
in
{ name = Some (Lib_name.of_string_exn ~loc:None name)
; entries = entries @ subs
}
in
loop package pkgs