170 lines
5.1 KiB
OCaml
170 lines
5.1 KiB
OCaml
open Import
|
|
open Meta
|
|
|
|
module Pub_name = struct
|
|
type t =
|
|
| Dot of t * string
|
|
| Id of string
|
|
|
|
let parse s =
|
|
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 = String.Set.to_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 String.Set.is_empty ppx_rt_deps then
|
|
[]
|
|
else
|
|
[ Comment "This is what jbuilder 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
|
|
; entries = entries @ subs
|
|
}
|
|
in
|
|
loop package pkgs
|