Skip to content

Commit

Permalink
[plugins] Support for a findlib-based loader.
Browse files Browse the repository at this point in the history
We introduce new syntax
```
Require ML Module pkg1 ... pkgn.
```
that uses findlib to locate and load a Coq plugin and its dependencies.

This makes feasible to actually develop Coq plugins that depend on
OCaml libraries not linked into the Coq main binaries without hitting
problems.

Fixes coq#5028, fixes coq#7698 .

This provides a workaround for coq#12607 , and helps with coq#9547 .
  • Loading branch information
ejgallego committed Mar 27, 2021
1 parent 0b54cb6 commit 61be049
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 12 deletions.
2 changes: 1 addition & 1 deletion vernac/dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
(synopsis "Coq's Vernacular Language")
(public_name coq-core.vernac)
(wrapped false)
(libraries tactics parsing))
(libraries findlib.dynload tactics parsing))

(coq.pp (modules g_proofs g_vernac))
5 changes: 4 additions & 1 deletion vernac/g_vernac.mlg
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,10 @@ GRAMMAR EXTEND Gram
s = [ s = ne_string -> { s } | s = IDENT -> { s } ] ->
{ VernacLoad (verbosely, s) }
| IDENT "Declare"; IDENT "ML"; IDENT "Module"; l = LIST1 ne_string ->
{ VernacDeclareMLModule l }
{ VernacDeclareMLModule { loader = CoqLoader ; modules = l } }

| IDENT "Require"; IDENT "ML"; IDENT "Module"; l = LIST1 ne_string ->
{ VernacDeclareMLModule { loader = Findlib ; modules = l } }

| IDENT "Locate"; l = locatable -> { VernacLocate l }

Expand Down
47 changes: 47 additions & 0 deletions vernac/mltop.ml
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,50 @@ let print_gc () =
str "stack_size: " ++ int stat.Gc.stack_size
in
hv 0 msg

(* TODO, what should we do here? *)
type fl_module_object = {
mlocal : Vernacexpr.locality_flag;
mnames : (string * ml_module_digest) list
}

let cache_fl_objects (_,{mnames=mnames}) =
let iter (obj, _) = trigger_ml_object true true true obj in
List.iter iter mnames

let load_fl_objects _ (_,{mnames=mnames}) =
let iter (obj, _) = trigger_ml_object true false true obj in
List.iter iter mnames

let classify_fl_objects ({mlocal=mlocal} as o) =
if mlocal then Libobject.Dispose else Libobject.Substitute o

let inFLModule : fl_module_object -> Libobject.obj =
let open Libobject in
declare_object
{(default_object "FL-MODULE") with
cache_function = cache_fl_objects;
load_function = load_fl_objects;
subst_function = (fun (_,o) -> o);
classify_function = classify_fl_objects }

(* To get the location of a plugin we do
ocamlfind query -predicates native -format '%+(plugin)' coq.plugins.ltac
In code this is:
let pkg = "coq.plugins.ltac" in
let d = Find.package_director pkg in
let archs = Findlib.package_property ["native"] pkg "plugin" in
let paths = Findlib.resolve_path ~base:d archs in
...
TODO: not clear if archs can return multiple objects so we'd need to
call `Fl_split.in_words`
*)
let load_plugins ~local fl_names =
Fl_dynload.load_packages fl_names;
(* XXX: Fix with above info. *)
let l = List.map mod_of_name fl_names in
let l = List.map add_module_digest l in
Lib.add_anonymous_leaf ~cache_first:false (inFLModule {mlocal=local; mnames=l})
17 changes: 14 additions & 3 deletions vernac/mltop.mli
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,21 @@ val declare_cache_obj : (unit -> unit) -> string -> unit

(** {5 Declaring modules} *)

(** [declare_ml_modules mods] Load dynamically modules [mods] calling
low-level [Dynlink] API, cmxs/cma files are searched in the path
specified with add_ml_dir . [mods] are a string such that
[mod.cmxs] is the expected object file. Note this is a simple
wrapper over [Dynlink] thus no dependency or double-loading are, in
principle handled. *)
val declare_ml_modules : Vernacexpr.locality_flag -> string list -> unit

(** [load_plugins fl_name] load dynamically a plugin with findlib name
[fl_name] using [Fl_dynload]. Findlib will handle locating, and
loading the dependencies for the plugin, so the plugin should
install a META file and be in scope. *)
val load_plugins : local:Vernacexpr.locality_flag -> string list -> unit

(** {5 Utilities} *)

val print_ml_path : unit -> Pp.t
val print_ml_modules : unit -> Pp.t
val print_gc : unit -> Pp.t
val print_ml_path : unit -> Pp.t val print_ml_modules : unit -> Pp.t
val print_gc : unit -> Pp.t
8 changes: 6 additions & 2 deletions vernac/ppvernac.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1077,9 +1077,13 @@ let pr_vernac_expr v =
++ keyword "ML Path"
++ qs s
)
| VernacDeclareMLModule (l) ->
| VernacDeclareMLModule { loader; modules } ->
return (
hov 2 (keyword "Declare ML Module" ++ spc() ++ prlist_with_sep sep qs l)
let require_type = function
| CoqLoader -> keyword "Declare ML Module"
| Findlib -> keyword "Require ML Module"
in
hov 2 (require_type loader ++ spc() ++ prlist_with_sep sep qs modules)
)
| VernacChdir s ->
return (keyword "Cd" ++ pr_opt qs s)
Expand Down
13 changes: 9 additions & 4 deletions vernac/vernacentries.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1364,9 +1364,13 @@ let vernac_remove_loadpath path =
let vernac_add_ml_path path =
Mltop.add_ml_dir (expand path)

let vernac_declare_ml_module ~local l =
let vernac_declare_ml_module ~local loader modules =
let local = Option.default false local in
Mltop.declare_ml_modules local (List.map expand l)
match loader with
| CoqLoader ->
Mltop.declare_ml_modules local (List.map expand modules)
| Findlib ->
Mltop.load_plugins ~local modules

let vernac_chdir = function
| None -> Feedback.msg_notice (str (Sys.getcwd()))
Expand Down Expand Up @@ -2263,8 +2267,9 @@ let translate_vernac ?loc ~atts v = let open Vernacextend in match v with
VtDefault(fun () ->
unsupported_attributes atts;
vernac_add_ml_path s)
| VernacDeclareMLModule l ->
VtDefault(fun () -> with_locality ~atts vernac_declare_ml_module l)
| VernacDeclareMLModule { loader; modules } ->
VtDefault(fun () ->
with_locality ~atts vernac_declare_ml_module loader modules)
| VernacChdir s ->
VtDefault(fun () -> unsupported_attributes atts; vernac_chdir s)

Expand Down
4 changes: 3 additions & 1 deletion vernac/vernacexpr.ml
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ type reference_or_constr =
| HintsReference of Libnames.qualid
| HintsConstr of Constrexpr.constr_expr

type ml_loader = CoqLoader | Findlib

type hints_expr =
| HintsResolve of (hint_info_expr * bool * reference_or_constr) list
| HintsResolveIFF of bool * Libnames.qualid list * int option
Expand Down Expand Up @@ -394,7 +396,7 @@ type nonrec vernac_expr =

| VernacRemoveLoadPath of string
| VernacAddMLPath of string
| VernacDeclareMLModule of string list
| VernacDeclareMLModule of { loader : ml_loader; modules : string list }
| VernacChdir of string option

(* State management *)
Expand Down

0 comments on commit 61be049

Please sign in to comment.