Allow to use installed libraries in jbuild plugins
This commit is contained in:
parent
0462d4a11f
commit
ac372ce63a
|
@ -189,11 +189,34 @@ everything Jbuilder needs to know about.
|
|||
*** OCaml syntax
|
||||
|
||||
If a =jbuild= file starts with =(* -*- tuareg -*- *)=, then it is
|
||||
interpreted as an OCaml script that generated the =jbuild= file as
|
||||
interpreted as an OCaml script that generates the =jbuild= file as
|
||||
described in the rest of this section. The code in the script will
|
||||
have access to a [[../plugin/jbuild_plugin.mli][Jbuild_plugin]] module containing details about the
|
||||
build context it is executed in.
|
||||
|
||||
The script can use the directive =#require= to access libraries:
|
||||
|
||||
#+begin_src ocaml
|
||||
#require "base,re";;
|
||||
#+end_src
|
||||
|
||||
Note that any library required by a =jbuild= file must be part of the
|
||||
installed world. This mean that your project won't be compilable in
|
||||
the same workspace as the required library, unless the library has
|
||||
been previously installed.
|
||||
|
||||
If you don't like the S-expression syntax, then this method gives you
|
||||
a way to use whatever else you want. For instance you could have an
|
||||
API to describe your project in OCaml directly:
|
||||
|
||||
#+begin_src ocaml
|
||||
(* -*- tuareg -*- *)
|
||||
#require "my_jbuild_api";;
|
||||
include My_jbuild_api.Make(Jbuild_plugin);;
|
||||
|
||||
library "foo" ~modules:["plop"; "bidule"];;
|
||||
#+end_src
|
||||
|
||||
*** Specification
|
||||
|
||||
=jbuild= files are composed of stanzas. For instance a typical
|
||||
|
|
|
@ -18,6 +18,7 @@ type t =
|
|||
; for_host : t option
|
||||
; build_dir : Path.t
|
||||
; path : Path.t list
|
||||
; toplevel_path : Path.t option
|
||||
; ocaml_bin : Path.t
|
||||
; ocaml : Path.t
|
||||
; ocamlc : Path.t
|
||||
|
@ -86,6 +87,21 @@ let opam_config_var ~env ~cache var =
|
|||
Hashtbl.add cache ~key:var ~data:s;
|
||||
Some s
|
||||
|
||||
let get_env env var =
|
||||
let prefix = var ^ "=" in
|
||||
let rec loop i =
|
||||
if i = Array.length env then
|
||||
None
|
||||
else
|
||||
let entry = env.(i) in
|
||||
if String.is_prefix entry ~prefix then
|
||||
let len_p = String.length prefix in
|
||||
Some (String.sub entry ~pos:len_p ~len:(String.length entry - len_p))
|
||||
else
|
||||
loop (i + 1)
|
||||
in
|
||||
loop 0
|
||||
|
||||
let create ~(kind : Kind.t) ~path ~env ~name ~merlin =
|
||||
let opam_var_cache = Hashtbl.create 128 in
|
||||
(match kind with
|
||||
|
@ -183,6 +199,7 @@ let create ~(kind : Kind.t) ~path ~env ~name ~merlin =
|
|||
; for_host = None
|
||||
; build_dir
|
||||
; path
|
||||
; toplevel_path = Option.map (get_env env "OCAML_TOPLEVEL_PATH") ~f:Path.of_string
|
||||
|
||||
; ocaml_bin = dir
|
||||
; ocaml = Path.relative dir "ocaml"
|
||||
|
|
|
@ -47,6 +47,9 @@ type t =
|
|||
; (** [PATH] *)
|
||||
path : Path.t list
|
||||
|
||||
; (** [OCAML_TOPLEVEL_PATH] *)
|
||||
toplevel_path : Path.t option
|
||||
|
||||
; (** Ocaml bin directory with all ocaml tools *)
|
||||
ocaml_bin : Path.t
|
||||
; ocaml : Path.t
|
||||
|
|
|
@ -34,6 +34,7 @@ module Jbuilds = struct
|
|||
let plugin_contents = read_file plugin in
|
||||
with_file_out (Path.to_string wrapper) ~f:(fun oc ->
|
||||
Printf.fprintf oc {|
|
||||
let () = Hashtbl.add Toploop.directive_table "require" (Toploop.Directive_string ignore)
|
||||
module Jbuild_plugin = struct
|
||||
module V1 = struct
|
||||
let context = %S
|
||||
|
@ -75,12 +76,43 @@ end
|
|||
in
|
||||
let wrapper = Path.extend_basename generated_jbuild ~suffix:".ml" in
|
||||
ensure_parent_dir_exists generated_jbuild;
|
||||
let _requires =
|
||||
let requires =
|
||||
create_plugin_wrapper context ~exec_dir:dir ~plugin:file ~wrapper ~target:generated_jbuild
|
||||
in
|
||||
let pkgs =
|
||||
List.map requires ~f:(Findlib.find_exn context.findlib)
|
||||
|> Findlib.closure
|
||||
in
|
||||
let includes =
|
||||
List.fold_left pkgs ~init:Path.Set.empty ~f:(fun acc pkg ->
|
||||
Path.Set.add pkg.Findlib.dir acc)
|
||||
|> Path.Set.elements
|
||||
|> List.concat_map ~f:(fun path ->
|
||||
[ "-I"; Path.to_string path ])
|
||||
in
|
||||
let cmas =
|
||||
List.concat_map pkgs ~f:(fun pkg -> pkg.archives.byte)
|
||||
in
|
||||
let args =
|
||||
List.concat
|
||||
[ [ "-I"; "+compiler-libs" ]
|
||||
; includes
|
||||
; cmas
|
||||
; [ Path.reach ~from:dir wrapper ]
|
||||
]
|
||||
in
|
||||
(* CR-someday jdimino: if we want to allow plugins to use findlib:
|
||||
{[
|
||||
let args =
|
||||
match context.toplevel_path with
|
||||
| None -> args
|
||||
| Some path -> "-I" :: Path.reach ~from:dir path :: args
|
||||
in
|
||||
]}
|
||||
*)
|
||||
Future.run Strict ~dir:(Path.to_string dir) ~env:context.env
|
||||
(Path.to_string context.Context.ocaml)
|
||||
[ Path.reach ~from:dir wrapper ]
|
||||
(Path.to_string context.ocaml)
|
||||
args
|
||||
>>= fun () ->
|
||||
let sexps = Sexp_load.many (Path.to_string generated_jbuild) in
|
||||
return (dir, Stanzas.parse sexps ~dir ~visible_packages))
|
||||
|
|
Loading…
Reference in New Issue