2016-11-13 10:01:32 +00:00
|
|
|
open Import
|
2016-11-12 11:48:24 +00:00
|
|
|
|
|
|
|
type t =
|
2016-11-13 10:01:32 +00:00
|
|
|
{ name : string
|
|
|
|
; entries : entry list
|
2016-11-12 11:48:24 +00:00
|
|
|
}
|
|
|
|
|
2016-11-13 10:01:32 +00:00
|
|
|
and entry =
|
|
|
|
| Comment of string
|
2016-12-02 13:54:32 +00:00
|
|
|
| Rule of rule
|
2016-11-13 10:01:32 +00:00
|
|
|
| Package of t
|
2016-11-12 11:48:24 +00:00
|
|
|
|
2016-12-02 13:54:32 +00:00
|
|
|
and rule =
|
|
|
|
{ var : string
|
|
|
|
; predicates : predicate list
|
|
|
|
; action : action
|
|
|
|
; value : string
|
|
|
|
}
|
2016-11-13 11:13:47 +00:00
|
|
|
|
2016-11-13 10:01:32 +00:00
|
|
|
and action = Set | Add
|
2016-11-12 11:48:24 +00:00
|
|
|
|
|
|
|
and predicate =
|
2016-12-02 13:54:32 +00:00
|
|
|
| Pos of string
|
|
|
|
| Neg of string
|
2016-11-13 10:01:32 +00:00
|
|
|
|
|
|
|
module Parse = struct
|
2016-11-13 11:13:47 +00:00
|
|
|
let error = Loc.fail_lex
|
2016-11-13 10:01:32 +00:00
|
|
|
|
|
|
|
let next = Meta_lexer.token
|
|
|
|
|
|
|
|
let package_name lb =
|
|
|
|
match next lb with
|
|
|
|
| String s ->
|
|
|
|
if String.contains s '.' then
|
|
|
|
error lb "'.' not allowed in sub-package names";
|
|
|
|
s
|
|
|
|
| _ -> error lb "package name expected"
|
|
|
|
|
|
|
|
let string lb =
|
2016-11-13 11:27:31 +00:00
|
|
|
match next lb with
|
2016-11-13 10:01:32 +00:00
|
|
|
| String s -> s
|
|
|
|
| _ -> error lb "string expected"
|
|
|
|
|
|
|
|
let lparen lb =
|
|
|
|
match next lb with
|
|
|
|
| Lparen -> ()
|
|
|
|
| _ -> error lb "'(' expected"
|
|
|
|
|
|
|
|
let action lb =
|
|
|
|
match next lb with
|
|
|
|
| Equal -> Set
|
|
|
|
| Plus_equal -> Add
|
|
|
|
| _ -> error lb "'=' or '+=' expected"
|
|
|
|
|
|
|
|
let rec predicates_and_action lb acc =
|
|
|
|
match next lb with
|
|
|
|
| Rparen -> (List.rev acc, action lb)
|
2016-12-02 13:54:32 +00:00
|
|
|
| Name n -> after_predicate lb (Pos n :: acc)
|
2016-11-13 10:01:32 +00:00
|
|
|
| Minus ->
|
|
|
|
let n =
|
|
|
|
match next lb with
|
|
|
|
| Name p -> p
|
|
|
|
| _ -> error lb "name expected"
|
|
|
|
in
|
2016-12-02 13:54:32 +00:00
|
|
|
after_predicate lb (Neg n :: acc)
|
2016-11-13 10:01:32 +00:00
|
|
|
| _ -> error lb "name, '-' or ')' expected"
|
|
|
|
|
2016-11-13 12:37:18 +00:00
|
|
|
and after_predicate lb acc =
|
|
|
|
match next lb with
|
|
|
|
| Rparen -> (List.rev acc, action lb)
|
|
|
|
| Comma -> predicates_and_action lb acc
|
|
|
|
| _ -> error lb "')' or ',' expected"
|
|
|
|
|
2016-11-13 10:01:32 +00:00
|
|
|
let rec entries lb depth acc =
|
|
|
|
match next lb with
|
|
|
|
| Rparen ->
|
|
|
|
if depth > 0 then
|
|
|
|
List.rev acc
|
|
|
|
else
|
|
|
|
error lb "closing parenthesis without matching opening one"
|
2016-11-13 12:37:18 +00:00
|
|
|
| Eof ->
|
|
|
|
if depth = 0 then
|
|
|
|
List.rev acc
|
|
|
|
else
|
|
|
|
error lb "%d closing parentheses missing" depth
|
2016-11-13 10:01:32 +00:00
|
|
|
| Name "package" ->
|
|
|
|
let name = package_name lb in
|
|
|
|
lparen lb;
|
2016-11-13 11:27:31 +00:00
|
|
|
let sub_entries = entries lb (depth + 1) [] in
|
|
|
|
entries lb depth (Package { name; entries = sub_entries } :: acc)
|
2016-11-13 10:01:32 +00:00
|
|
|
| Name var ->
|
2016-12-02 13:54:32 +00:00
|
|
|
let predicates, action =
|
2016-11-13 10:01:32 +00:00
|
|
|
match next lb with
|
|
|
|
| Equal -> ([], Set)
|
|
|
|
| Plus_equal -> ([], Add)
|
|
|
|
| Lparen -> predicates_and_action lb []
|
|
|
|
| _ -> error lb "'=', '+=' or '(' expected"
|
|
|
|
in
|
|
|
|
let value = string lb in
|
2016-12-02 13:54:32 +00:00
|
|
|
entries lb depth (Rule { var; predicates; action; value } :: acc)
|
2016-11-13 10:01:32 +00:00
|
|
|
| _ ->
|
|
|
|
error lb "'package' or variable name expected"
|
|
|
|
end
|
2016-11-12 11:48:24 +00:00
|
|
|
|
2018-04-05 15:02:57 +00:00
|
|
|
let pp_action fmt = function
|
|
|
|
| Set -> Format.pp_print_string fmt "Set"
|
|
|
|
| Add -> Format.pp_print_string fmt "Add"
|
|
|
|
|
|
|
|
let pp_predicate fmt = function
|
|
|
|
| Pos s -> Format.fprintf fmt "%S" ("+" ^ s)
|
|
|
|
| Neg s -> Format.fprintf fmt "%S" ("-" ^ s)
|
|
|
|
|
|
|
|
let pp_rule fmt (t : rule) =
|
|
|
|
Fmt.record fmt
|
|
|
|
[ "var", (Fmt.const Fmt.quoted t.var)
|
|
|
|
; "predicates", (Fmt.const (Fmt.ocaml_list pp_predicate) t.predicates)
|
|
|
|
; "action", (Fmt.const pp_action t.action)
|
|
|
|
; "value", (Fmt.const Fmt.quoted t.value)
|
|
|
|
]
|
|
|
|
|
2016-12-02 13:54:32 +00:00
|
|
|
module Simplified = struct
|
|
|
|
module Rules = struct
|
|
|
|
type t =
|
|
|
|
{ set_rules : rule list
|
|
|
|
; add_rules : rule list
|
|
|
|
}
|
2018-04-05 15:02:57 +00:00
|
|
|
|
|
|
|
let pp fmt t =
|
|
|
|
Fmt.record fmt
|
|
|
|
[ "set_rules", Fmt.const (Fmt.ocaml_list pp_rule) t.set_rules
|
|
|
|
; "add_rules", Fmt.const (Fmt.ocaml_list pp_rule) t.add_rules
|
|
|
|
]
|
2016-12-02 13:54:32 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
type t =
|
|
|
|
{ name : string
|
|
|
|
; vars : Rules.t String_map.t
|
|
|
|
; subs : t list
|
|
|
|
}
|
2018-04-05 15:02:57 +00:00
|
|
|
|
|
|
|
let rec pp fmt t =
|
|
|
|
Fmt.record fmt
|
|
|
|
[ "name", Fmt.const Fmt.quoted t.name
|
|
|
|
; "vars", Fmt.const (String_map.pp Rules.pp) t.vars
|
|
|
|
; "subs", Fmt.const (Fmt.ocaml_list pp) t.subs
|
|
|
|
]
|
2016-12-02 13:54:32 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
let rec simplify t =
|
|
|
|
List.fold_right t.entries
|
|
|
|
~init:
|
|
|
|
{ name = t.name
|
|
|
|
; vars = String_map.empty
|
|
|
|
; subs = []
|
|
|
|
}
|
|
|
|
~f:(fun entry (pkg : Simplified.t) ->
|
2016-11-13 11:13:47 +00:00
|
|
|
match entry with
|
2016-12-02 13:54:32 +00:00
|
|
|
| Comment _ -> pkg
|
|
|
|
| Package sub ->
|
|
|
|
{ pkg with subs = simplify sub :: pkg.subs }
|
|
|
|
| Rule rule ->
|
|
|
|
let rules =
|
2018-02-25 16:35:25 +00:00
|
|
|
Option.value (String_map.find pkg.vars rule.var)
|
2016-12-02 13:54:32 +00:00
|
|
|
~default:{ set_rules = []; add_rules = [] }
|
|
|
|
in
|
|
|
|
let rules =
|
|
|
|
match rule.action with
|
|
|
|
| Set -> { rules with set_rules = rule :: rules.set_rules }
|
|
|
|
| Add -> { rules with add_rules = rule :: rules.add_rules }
|
|
|
|
in
|
2018-02-25 16:35:25 +00:00
|
|
|
{ pkg with vars = String_map.add pkg.vars rule.var rules })
|
2016-12-02 13:54:32 +00:00
|
|
|
|
2018-03-22 08:39:43 +00:00
|
|
|
let load ~fn ~name =
|
|
|
|
{ name
|
|
|
|
; entries =
|
|
|
|
Io.with_lexbuf_from_file fn ~f:(fun lb ->
|
|
|
|
Parse.entries lb 0 [])
|
|
|
|
}
|
|
|
|
|> simplify
|
|
|
|
|
2016-12-15 11:20:46 +00:00
|
|
|
let rule var predicates action value =
|
|
|
|
Rule { var; predicates; action; value }
|
|
|
|
let requires ?(preds=[]) pkgs =
|
|
|
|
rule "requires" preds Set (String.concat ~sep:" " pkgs)
|
|
|
|
let version s = rule "version" [] Set s
|
|
|
|
let directory s = rule "directory" [] Set s
|
|
|
|
let archive p s = rule "archive" [Pos p] Set s
|
|
|
|
let plugin p s = rule "plugin" [Pos p] Set s
|
|
|
|
let archives name =
|
|
|
|
[ archive "byte" (name ^ ".cma" )
|
|
|
|
; archive "native" (name ^ ".cmxa")
|
|
|
|
; plugin "byte" (name ^ ".cma" )
|
|
|
|
; plugin "native" (name ^ ".cmxs")
|
|
|
|
]
|
|
|
|
|
2017-12-11 13:05:20 +00:00
|
|
|
let builtins ~stdlib_dir =
|
2016-12-15 11:20:46 +00:00
|
|
|
let version = version "[distributed with Ocaml]" in
|
2016-12-02 13:54:32 +00:00
|
|
|
let simple name ?dir ?(archive_name=name) deps =
|
|
|
|
let archives = archives archive_name in
|
|
|
|
{ name
|
|
|
|
; entries =
|
|
|
|
(requires deps ::
|
|
|
|
version ::
|
|
|
|
match dir with
|
|
|
|
| None -> archives
|
|
|
|
| Some d -> directory d :: archives)
|
|
|
|
}
|
|
|
|
in
|
|
|
|
let compiler_libs =
|
|
|
|
let sub name deps =
|
|
|
|
Package (simple name deps ~archive_name:("ocaml" ^ name))
|
|
|
|
in
|
|
|
|
{ name = "compiler-libs"
|
|
|
|
; entries =
|
|
|
|
[ requires []
|
|
|
|
; version
|
|
|
|
; directory "+compiler-libs"
|
|
|
|
; sub "common" []
|
|
|
|
; sub "bytecomp" ["compiler-libs.common" ]
|
|
|
|
; sub "optcomp" ["compiler-libs.common" ]
|
|
|
|
; sub "toplevel" ["compiler-libs.bytecomp"]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
in
|
|
|
|
let str = simple "str" [] ~dir:"+" in
|
2016-12-16 12:56:34 +00:00
|
|
|
let unix = simple "unix" [] ~dir:"+" in
|
2016-12-15 13:00:30 +00:00
|
|
|
let bigarray = simple "bigarray" ["unix"] ~dir:"+" in
|
2016-12-02 13:54:32 +00:00
|
|
|
let threads =
|
|
|
|
{ name = "threads"
|
|
|
|
; entries =
|
|
|
|
[ version
|
|
|
|
; requires ~preds:[Pos "mt"; Pos "mt_vm" ] ["threads.vm"]
|
|
|
|
; requires ~preds:[Pos "mt"; Pos "mt_posix"] ["threads.posix"]
|
|
|
|
; directory "+"
|
|
|
|
; rule "type_of_threads" [] Set "posix"
|
|
|
|
; rule "error" [Neg "mt"] Set "Missing -thread or -vmthread switch"
|
|
|
|
; rule "error" [Neg "mt_vm"; Neg "mt_posix"] Set "Missing -thread or -vmthread switch"
|
|
|
|
; Package (simple "vm" ["unix"] ~dir:"+vmthreads" ~archive_name:"threads")
|
|
|
|
; Package (simple "posix" ["unix"] ~dir:"+threads" ~archive_name:"threads")
|
|
|
|
]
|
|
|
|
}
|
|
|
|
in
|
|
|
|
let num =
|
|
|
|
{ name = "num"
|
|
|
|
; entries =
|
|
|
|
[ requires ["num.core"]
|
|
|
|
; version
|
|
|
|
; Package (simple "core" [] ~dir:"+" ~archive_name:"nums")
|
|
|
|
]
|
|
|
|
}
|
|
|
|
in
|
2017-12-11 13:05:20 +00:00
|
|
|
let libs =
|
|
|
|
(* We do not rely on an "exists_if" ocamlfind variable,
|
|
|
|
because it would produce an error message mentioning
|
|
|
|
a "hidden" package (which could be confusing). *)
|
|
|
|
if Path.exists (Path.relative stdlib_dir "nums.cma") then
|
|
|
|
[ compiler_libs; str; unix; bigarray; threads; num ]
|
|
|
|
else
|
|
|
|
[ compiler_libs; str; unix; bigarray; threads ]
|
|
|
|
in
|
2018-03-22 08:39:43 +00:00
|
|
|
List.map libs ~f:(fun t -> t.name, simplify t)
|
2018-02-25 16:35:25 +00:00
|
|
|
|> String_map.of_list_exn
|
2016-12-02 13:54:32 +00:00
|
|
|
|
2016-12-15 11:20:46 +00:00
|
|
|
let string_of_action = function
|
|
|
|
| Set -> "="
|
|
|
|
| Add -> "+="
|
|
|
|
|
|
|
|
let string_of_predicate = function
|
|
|
|
| Pos p -> p
|
|
|
|
| Neg p -> "-" ^ p
|
|
|
|
|
|
|
|
let pp_list f ppf l =
|
|
|
|
match l with
|
|
|
|
| [] -> ()
|
|
|
|
| x :: l ->
|
|
|
|
f ppf x;
|
|
|
|
List.iter l ~f:(fun x ->
|
|
|
|
Format.pp_print_cut ppf ();
|
|
|
|
f ppf x)
|
|
|
|
|
2017-11-24 15:08:34 +00:00
|
|
|
let pp_print_text ppf s =
|
|
|
|
Format.fprintf ppf "\"@[<hv>";
|
|
|
|
Format.pp_print_text ppf (String.escape_double_quote s);
|
|
|
|
Format.fprintf ppf "@]\""
|
2017-11-23 18:25:45 +00:00
|
|
|
|
2017-11-24 15:08:34 +00:00
|
|
|
let pp_print_string ppf s =
|
|
|
|
Format.fprintf ppf "\"@[<hv>";
|
|
|
|
Format.pp_print_string ppf (String.escape_double_quote s);
|
|
|
|
Format.fprintf ppf "@]\""
|
2017-11-23 18:25:45 +00:00
|
|
|
|
2017-11-24 15:08:34 +00:00
|
|
|
let pp_quoted_value var =
|
2017-06-07 10:15:15 +00:00
|
|
|
match var with
|
|
|
|
| "archive" | "plugin" | "requires"
|
|
|
|
| "ppx_runtime_deps" | "linkopts" | "jsoo_runtime" ->
|
2017-11-23 18:25:45 +00:00
|
|
|
pp_print_text
|
2017-06-07 10:15:15 +00:00
|
|
|
| _ ->
|
2017-11-23 18:25:45 +00:00
|
|
|
pp_print_string
|
2017-06-07 10:15:15 +00:00
|
|
|
|
2016-12-15 11:20:46 +00:00
|
|
|
let rec pp ppf entries =
|
|
|
|
Format.fprintf ppf "@[<v>%a@]" (pp_list pp_entry) entries
|
|
|
|
|
|
|
|
and pp_entry ppf entry =
|
|
|
|
let open Format in
|
|
|
|
match entry with
|
|
|
|
| Comment s ->
|
|
|
|
fprintf ppf "# %s" s
|
|
|
|
| Rule { var; predicates = []; action; value } ->
|
2017-11-24 15:08:34 +00:00
|
|
|
fprintf ppf "@[%s %s %a@]"
|
|
|
|
var (string_of_action action) (pp_quoted_value var) value
|
2016-12-15 11:20:46 +00:00
|
|
|
| Rule { var; predicates; action; value } ->
|
2017-11-24 15:08:34 +00:00
|
|
|
fprintf ppf "@[%s(%s) %s %a@]"
|
2016-12-15 11:20:46 +00:00
|
|
|
var (String.concat ~sep:"," (List.map predicates ~f:string_of_predicate))
|
2017-11-24 15:08:34 +00:00
|
|
|
(string_of_action action) (pp_quoted_value var) value
|
2016-12-15 11:20:46 +00:00
|
|
|
| Package { name; entries } ->
|
|
|
|
fprintf ppf "@[<v 2>package %S (@,%a@]@,)"
|
|
|
|
name pp entries
|