Add target support

* Create targets from findlib toolchains by reading findlib configs
* Define targets inside workspace files
* Set cross compilation targets with -x argument
This commit is contained in:
Jeremie Dimino 2017-12-21 19:54:00 +08:00 committed by Rudi Grinberg
parent afb602d7ef
commit 6e64156913
8 changed files with 401 additions and 246 deletions

View File

@ -21,6 +21,7 @@ type common =
; target_prefix : string ; target_prefix : string
; only_packages : String_set.t option ; only_packages : String_set.t option
; capture_outputs : bool ; capture_outputs : bool
; x : string option
; (* Original arguments for the external-lib-deps hint *) ; (* Original arguments for the external-lib-deps hint *)
orig_args : string list orig_args : string list
} }
@ -74,7 +75,9 @@ module Main = struct
?unlink_aliases ?unlink_aliases
?workspace_file:common.workspace_file ?workspace_file:common.workspace_file
?only_packages:common.only_packages ?only_packages:common.only_packages
?filter_out_optional_stanzas_with_missing_deps () ?filter_out_optional_stanzas_with_missing_deps
?x:common.x
()
end end
type target = type target =
@ -154,6 +157,7 @@ let common =
no_buffer no_buffer
workspace_file workspace_file
(root, only_packages, orig) (root, only_packages, orig)
x
= =
let root, to_cwd = let root, to_cwd =
match root with match root with
@ -181,6 +185,7 @@ let common =
; only_packages = ; only_packages =
Option.map only_packages Option.map only_packages
~f:(fun s -> String_set.of_list (String.split s ~on:',')) ~f:(fun s -> String_set.of_list (String.split s ~on:','))
; x
} }
in in
let docs = copts_sect in let docs = copts_sect in
@ -304,6 +309,12 @@ let common =
$ only_packages $ only_packages
$ frop)) $ frop))
in in
let x =
Arg.(value
& opt (some string) None
& info ["x"] ~docs
~doc:{|Cross-compile using this toolchain.|})
in
Term.(const make Term.(const make
$ concurrency $ concurrency
$ ddep_path $ ddep_path
@ -314,6 +325,7 @@ let common =
$ no_buffer $ no_buffer
$ workspace_file $ workspace_file
$ root_and_only_packages $ root_and_only_packages
$ x
) )
let installed_libraries = let installed_libraries =
@ -321,7 +333,8 @@ let installed_libraries =
let go common na = let go common na =
set_common common ~targets:[]; set_common common ~targets:[];
Future.Scheduler.go ~log:(Log.create ()) Future.Scheduler.go ~log:(Log.create ())
(Context.default () >>= fun ctx -> (Context.create (Default [Native]) >>= fun ctxs ->
let ctx = List.hd ctxs in
let findlib = ctx.findlib in let findlib = ctx.findlib in
if na then begin if na then begin
let pkgs = Findlib.all_unavailable_packages findlib in let pkgs = Findlib.all_unavailable_packages findlib in

View File

@ -1,7 +1,7 @@
;; This file is used by `make all-supported-ocaml-versions` ;; This file is used by `make all-supported-ocaml-versions`
(context ((switch 4.02.3))) (context (opam (switch 4.02.3)))
(context ((switch 4.03.0))) (context (opam (switch 4.03.0)))
(context ((switch 4.04.2))) (context (opam (switch 4.04.2)))
(context ((switch 4.05.0))) (context (opam (switch 4.05.0)))
(context ((switch 4.06.0))) (context (opam (switch 4.06.0)))
(context ((switch 4.07.0+trunk))) (context (opam (switch 4.07.0+trunk)))

View File

@ -34,6 +34,7 @@ type t =
; kind : Kind.t ; kind : Kind.t
; merlin : bool ; merlin : bool
; for_host : t option ; for_host : t option
; implicit : bool
; build_dir : Path.t ; build_dir : Path.t
; path : Path.t list ; path : Path.t list
; toplevel_path : Path.t option ; toplevel_path : Path.t option
@ -46,6 +47,7 @@ type t =
; env : string array ; env : string array
; env_extra : string Env_var_map.t ; env_extra : string Env_var_map.t
; findlib : Findlib.t ; findlib : Findlib.t
; findlib_toolchain : string option
; arch_sixtyfour : bool ; arch_sixtyfour : bool
; opam_var_cache : (string, string) Hashtbl.t ; opam_var_cache : (string, string) Hashtbl.t
; natdynlink_supported : bool ; natdynlink_supported : bool
@ -175,7 +177,8 @@ let extend_env ~vars ~env =
imported imported
|> Array.of_list |> Array.of_list
let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findlib = let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin
~use_findlib ~targets () =
let env = extend_env ~env:base_env ~vars:env_extra in let env = extend_env ~env:base_env ~vars:env_extra in
let opam_var_cache = Hashtbl.create 128 in let opam_var_cache = Hashtbl.create 128 in
(match kind with (match kind with
@ -187,37 +190,83 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli
in in
let which_cache = Hashtbl.create 128 in let which_cache = Hashtbl.create 128 in
let which x = which ~cache:which_cache ~path x in let which x = which ~cache:which_cache ~path x in
let findlib_config_path = lazy (
match which "ocamlfind" with
| None -> prog_not_found_in_path "ocamlfind"
| Some fn ->
(* When OCAMLFIND_CONF is set, "ocamlfind printconf" does print the contents of the
variable, but "ocamlfind printconf conf" still prints the configuration file set
at the configuration time of ocamlfind, sigh... *)
match Sys.getenv "OCAMLFIND_CONF" with
| s -> Future.return (Path.absolute s)
| exception Not_found ->
Future.run_capture_line ~env Strict
(Path.to_string fn) ["printconf"; "conf"]
>>| Path.absolute)
in
let create_one ~name ~implicit ?findlib_toolchain ?host ~merlin () =
(match findlib_toolchain with
| None -> Future.return None
| Some toolchain ->
Lazy.force findlib_config_path >>| fun path ->
Some (Findlib.Config.load path ~toolchain ~context:name))
>>= fun findlib_config ->
let get_tool_using_findlib_config prog =
match findlib_config with
| None -> None
| Some conf ->
match Findlib.Config.get conf prog with
| "" -> None
| s ->
match Filename.analyze_program_name s with
| In_path | Relative_to_current_dir -> which s
| Absolute -> Some (Path.absolute s)
in
let ocamlc = let ocamlc =
match which "ocamlc" with match get_tool_using_findlib_config "ocamlc" with
| None -> prog_not_found_in_path "ocamlc"
| Some x -> x | Some x -> x
| None ->
match which "ocamlc" with
| Some x -> x
| None -> prog_not_found_in_path "ocamlc"
in in
let dir = Path.parent ocamlc in let dir = Path.parent ocamlc in
let prog_not_found prog = let ocaml_tool_not_found prog =
die "ocamlc found in %s, but %s/%s doesn't exist (context: %s)" die "ocamlc found in %s, but %s/%s doesn't exist (context: %s)"
(Path.to_string dir) (Path.to_string dir) prog name (Path.to_string dir) (Path.to_string dir) prog name
in in
let best_prog prog = Bin.best_prog dir prog in let get_ocaml_tool prog =
let get_prog prog = match get_tool_using_findlib_config prog with
match best_prog prog with | None -> Bin.best_prog dir prog
| None -> prog_not_found prog | Some _ as x -> x
in
let get_ocaml_tool_exn prog =
match get_ocaml_tool prog with
| None -> ocaml_tool_not_found prog
| Some fn -> fn | Some fn -> fn
in in
let build_dir =
Path.of_string (sprintf "_build/%s" name) let build_dir = Path.of_string (sprintf "_build/%s" name) in
in
let ocamlc_config_cmd = sprintf "%s -config" (Path.to_string ocamlc) in let ocamlc_config_cmd = sprintf "%s -config" (Path.to_string ocamlc) in
let findlib_path = let findlib_path =
if use_findlib then if use_findlib then
(* If ocamlfind is present, it has precedence over everything else. *) (* If ocamlfind is present, it has precedence over everything else. *)
match which "ocamlfind" with match which "ocamlfind" with
| Some fn -> | Some fn ->
(Future.run_capture_lines ~env Strict let args =
(Path.to_string fn) ["printconf"; "path"] let args = ["printconf"; "path"] in
>>| List.map ~f:Path.absolute) match findlib_toolchain with
| None -> args
| Some s -> "-toolchain" :: s :: args
in
Future.run_capture_lines ~env Strict (Path.to_string fn) args
>>| List.map ~f:Path.absolute
| None -> | None ->
(* If there no ocamlfind in the PATH, check if we have opam and assume a stan opam (* If there no ocamlfind in the PATH, check if we have opam
setup *) and assume a standard opam setup *)
opam_config_var ~env ~cache:opam_var_cache "lib" opam_config_var ~env ~cache:opam_var_cache "lib"
>>| function >>| function
| Some s -> [Path.absolute s] | Some s -> [Path.absolute s]
@ -232,6 +281,7 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli
findlib_path findlib_path
(Future.run_capture_lines ~env Strict (Path.to_string ocamlc) ["-config"]) (Future.run_capture_lines ~env Strict (Path.to_string ocamlc) ["-config"])
>>= fun (findlib_path, ocamlc_config) -> >>= fun (findlib_path, ocamlc_config) ->
let ocamlc_config = let ocamlc_config =
List.map ocamlc_config ~f:(fun line -> List.map ocamlc_config ~f:(fun line ->
match String.index line ':' with match String.index line ':' with
@ -268,7 +318,7 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli
let stdlib_dir = get_path "standard_library" in let stdlib_dir = get_path "standard_library" in
let natdynlink_supported = Path.exists (Path.relative stdlib_dir "dynlink.cmxa") in let natdynlink_supported = Path.exists (Path.relative stdlib_dir "dynlink.cmxa") in
let version = get "version" in let version = get "version" in
let env,env_extra = let env, env_extra =
(* See comment in ansi_color.ml for setup_env_for_colors. For OCaml < 4.05, (* See comment in ansi_color.ml for setup_env_for_colors. For OCaml < 4.05,
OCAML_COLOR is not supported so we use OCAMLPARAM. OCaml 4.02 doesn't support OCAML_COLOR is not supported so we use OCAMLPARAM. OCaml 4.02 doesn't support
'color' in OCAMLPARAM, so we just don't force colors with 4.02. *) 'color' in OCAMLPARAM, so we just don't force colors with 4.02. *)
@ -317,23 +367,25 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli
in in
return return
{ name { name
; implicit
; kind ; kind
; merlin ; merlin
; for_host = None ; for_host = host
; build_dir ; build_dir
; path ; path
; toplevel_path = Option.map (get_env env "OCAML_TOPLEVEL_PATH") ~f:Path.absolute ; toplevel_path = Option.map (get_env env "OCAML_TOPLEVEL_PATH") ~f:Path.absolute
; ocaml_bin = dir ; ocaml_bin = dir
; ocaml = Path.relative dir ("ocaml" ^ Bin.exe) ; ocaml = (match which "ocaml" with Some p -> p | None -> prog_not_found_in_path "ocaml")
; ocamlc ; ocamlc
; ocamlopt = best_prog "ocamlopt" ; ocamlopt = get_ocaml_tool "ocamlopt"
; ocamldep = get_prog "ocamldep" ; ocamldep = get_ocaml_tool_exn "ocamldep"
; ocamlmklib = get_prog "ocamlmklib" ; ocamlmklib = get_ocaml_tool_exn "ocamlmklib"
; env ; env
; env_extra ; env_extra
; findlib = Findlib.create ~stdlib_dir ~path:findlib_path ; findlib = Findlib.create ~stdlib_dir ~path:findlib_path
; findlib_toolchain
; arch_sixtyfour ; arch_sixtyfour
; opam_var_cache ; opam_var_cache
@ -376,6 +428,20 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli
; which_cache ; which_cache
} }
in
let implicit = not (List.mem ~set:targets Workspace.Context.Target.Native) in
create_one () ~implicit ~name ~merlin >>= fun native ->
Future.all (
List.filter_map targets ~f:(function
| Native -> None
| Named findlib_toolchain ->
let name = sprintf "%s.%s" name findlib_toolchain in
Some (create_one () ~implicit:false ~name ~findlib_toolchain ~host:native
~merlin:false)
)
) >>| fun others ->
native :: others
let opam_config_var t var = opam_config_var ~env:t.env ~cache:t.opam_var_cache var let opam_config_var t var = opam_config_var ~env:t.env ~cache:t.opam_var_cache var
@ -383,7 +449,7 @@ let initial_env = lazy (
Lazy.force Ansi_color.setup_env_for_colors; Lazy.force Ansi_color.setup_env_for_colors;
Unix.environment ()) Unix.environment ())
let default ?(merlin=true) ?(use_findlib=true) () = let default ?(merlin=true) ?(use_findlib=true) ~targets () =
let env = Lazy.force initial_env in let env = Lazy.force initial_env in
let path = let path =
match get_env env "PATH" with match get_env env "PATH" with
@ -391,9 +457,9 @@ let default ?(merlin=true) ?(use_findlib=true) () =
| None -> [] | None -> []
in in
create ~kind:Default ~path ~base_env:env ~env_extra:Env_var_map.empty create ~kind:Default ~path ~base_env:env ~env_extra:Env_var_map.empty
~name:"default" ~merlin ~use_findlib ~name:"default" ~merlin ~use_findlib ~targets ()
let create_for_opam ?root ~switch ~name ?(merlin=false) () = let create_for_opam ?root ~targets ~switch ~name ?(merlin=false) () =
match Bin.opam with match Bin.opam with
| None -> Utils.program_not_found "opam" | None -> Utils.program_not_found "opam"
| Some fn -> | Some fn ->
@ -430,8 +496,14 @@ let create_for_opam ?root ~switch ~name ?(merlin=false) () =
| Some s -> Bin.parse_path s | Some s -> Bin.parse_path s
in in
let env = Lazy.force initial_env in let env = Lazy.force initial_env in
create ~kind:(Opam { root; switch }) ~path ~base_env:env ~env_extra:vars create ~kind:(Opam { root; switch }) ~targets
~name ~merlin ~use_findlib:true ~path ~base_env:env ~env_extra:vars ~name ~merlin ~use_findlib:true ()
let create ?use_findlib ?merlin def =
match (def : Workspace.Context.t) with
| Default targets -> default ~targets ?merlin ?use_findlib ()
| Opam { name; switch; root; targets; _ } ->
create_for_opam ?root ~switch ~name ?merlin ~targets ()
let which t s = which ~cache:t.which_cache ~path:t.path s let which t s = which ~cache:t.which_cache ~path:t.path s

View File

@ -48,6 +48,10 @@ type t =
building tools used for the compilation that run on the host. *) building tools used for the compilation that run on the host. *)
for_host : t option for_host : t option
; (** [false] if a user explicitly listed this context in the workspace.
Controls whether we add artifacts from this context @install *)
implicit : bool
; (** Directory where artifact are stored, for instance "_build/default" *) ; (** Directory where artifact are stored, for instance "_build/default" *)
build_dir : Path.t build_dir : Path.t
@ -72,6 +76,7 @@ type t =
env_extra : string Env_var_map.t env_extra : string Env_var_map.t
; findlib : Findlib.t ; findlib : Findlib.t
; findlib_toolchain : string option
; (** Misc *) ; (** Misc *)
arch_sixtyfour : bool arch_sixtyfour : bool
@ -124,18 +129,14 @@ val sexp_of_t : t -> Sexp.t
(** Compare the context names *) (** Compare the context names *)
val compare : t -> t -> int val compare : t -> t -> int
val create_for_opam
: ?root:string
-> switch:string
-> name:string
-> ?merlin:bool
-> unit
-> t Future.t
(** If [use_findlib] is [false], don't try to guess the library search path with opam or (** If [use_findlib] is [false], don't try to guess the library search path with opam or
ocamlfind. This is only for building jbuilder itself, so that its build is completely ocamlfind. This is only for building jbuilder itself, so that its build is completely
independent of the user setup. *) independent of the user setup. *)
val default : ?merlin:bool -> ?use_findlib:bool -> unit -> t Future.t val create
: ?use_findlib:bool
-> ?merlin:bool
-> Workspace.Context.t
-> t list Future.t
val which : t -> string -> Path.t option val which : t -> string -> Path.t option

View File

@ -12,7 +12,8 @@ type setup =
let package_install_file { packages; _ } pkg = let package_install_file { packages; _ } pkg =
match String_map.find pkg packages with match String_map.find pkg packages with
| None -> Error () | None -> Error ()
| Some p -> Ok (Path.relative p.path (p.name ^ ".install")) | Some p ->
Ok (Path.relative p.path (Utils.install_file ~package:p.name ~findlib_toolchain:None))
let setup ?(log=Log.no_log) ?unlink_aliases let setup ?(log=Log.no_log) ?unlink_aliases
?filter_out_optional_stanzas_with_missing_deps ?filter_out_optional_stanzas_with_missing_deps
@ -20,6 +21,7 @@ let setup ?(log=Log.no_log) ?unlink_aliases
?(use_findlib=true) ?(use_findlib=true)
?only_packages ?only_packages
?extra_ignored_subtrees ?extra_ignored_subtrees
?x
() = () =
let conf = Jbuild_load.load ?extra_ignored_subtrees () in let conf = Jbuild_load.load ?extra_ignored_subtrees () in
Option.iter only_packages ~f:(fun set -> Option.iter only_packages ~f:(fun set ->
@ -33,26 +35,34 @@ let setup ?(log=Log.no_log) ?unlink_aliases
| Some w -> w | Some w -> w
| None -> | None ->
if Sys.file_exists workspace_file then if Sys.file_exists workspace_file then
Workspace.load workspace_file Workspace.load ?x workspace_file
else else
{ merlin_context = Some "default"; contexts = [Default] } { merlin_context = Some "default"
; contexts = [Default [
match x with
| None -> Native
| Some x -> Named x
]]
}
in in
Future.all
(List.map workspace.contexts ~f:(function Future.all (
| Workspace.Context.Default -> List.map workspace.contexts ~f:(fun ctx_def ->
Context.default ~merlin:(workspace.merlin_context = Some "default") let name = Workspace.Context.name ctx_def in
~use_findlib () Context.create ctx_def ~merlin:(workspace.merlin_context = Some name) ~use_findlib)
| Opam { name; switch; root; merlin } -> )
Context.create_for_opam ~name ~switch ?root ~merlin ()))
>>= fun contexts -> >>= fun contexts ->
List.iter contexts ~f:(fun ctx -> let contexts = List.concat contexts in
List.iter contexts ~f:(fun (ctx : Context.t) ->
Log.infof log "@[<1>Jbuilder context:@,%a@]@." Sexp.pp (Context.sexp_of_t ctx)); Log.infof log "@[<1>Jbuilder context:@,%a@]@." Sexp.pp (Context.sexp_of_t ctx));
Gen_rules.gen conf ~contexts Gen_rules.gen conf
~contexts
?unlink_aliases ?unlink_aliases
?only_packages ?only_packages
?filter_out_optional_stanzas_with_missing_deps ?filter_out_optional_stanzas_with_missing_deps
>>= fun (rules, stanzas) -> >>= fun (rules, stanzas) ->
let build_system = Build_system.create ~contexts ~file_tree:conf.file_tree ~rules in let build_system = Build_system.create ~contexts
~file_tree:conf.file_tree ~rules in
return { build_system return { build_system
; stanzas ; stanzas
; contexts ; contexts
@ -211,7 +221,7 @@ let bootstrap () =
Clflags.debug_dep_path := true; Clflags.debug_dep_path := true;
let log = Log.create () in let log = Log.create () in
Future.Scheduler.go ~log Future.Scheduler.go ~log
(setup ~log ~workspace:{ merlin_context = Some "default"; contexts = [Default] } (setup ~log ~workspace:{ merlin_context = Some "default"; contexts = [Default [Native]] }
~use_findlib:false ~use_findlib:false
~extra_ignored_subtrees:ignored_during_bootstrap ~extra_ignored_subtrees:ignored_during_bootstrap
() ()

View File

@ -22,6 +22,7 @@ val setup
-> ?workspace:Workspace.t -> ?workspace:Workspace.t
-> ?workspace_file:string -> ?workspace_file:string
-> ?only_packages:String_set.t -> ?only_packages:String_set.t
-> ?x:string
-> unit -> unit
-> setup Future.t -> setup Future.t
val external_lib_deps val external_lib_deps

View File

@ -2,36 +2,69 @@ open Import
open Sexp.Of_sexp open Sexp.Of_sexp
module Context = struct module Context = struct
module Target = struct
type t =
| Native
| Named of string
let t sexp =
match string sexp with
| "native" -> Native
| s -> Named s
end
module Opam = struct module Opam = struct
type t = type t =
{ name : string { name : string
; switch : string ; switch : string
; root : string option ; root : string option
; merlin : bool ; merlin : bool
; targets : Target.t list
} }
let t = let t =
record field "switch" string >>= fun switch ->
(field "switch" string >>= fun switch ->
field "name" string ~default:switch >>= fun name -> field "name" string ~default:switch >>= fun name ->
field "targets" (list Target.t) ~default:[Target.Native] >>= fun targets ->
field_o "root" string >>= fun root -> field_o "root" string >>= fun root ->
field_b "merlin" >>= fun merlin -> field_b "merlin" >>= fun merlin ->
return { switch return { switch
; name ; name
; root ; root
; merlin ; merlin
}) ; targets
}
end end
type t = Default | Opam of Opam.t type t = Default of Target.t list | Opam of Opam.t
let t = function let t = function
| Atom (_, "default") -> Default | Atom (_, "default") -> Default [Native]
| sexp -> Opam (Opam.t sexp) | List (_, List _ :: _) as sexp -> Opam (record Opam.t sexp)
| sexp ->
sum
[ cstr_record "default"
(field "targets" (list Target.t) ~default:[Target.Native]
>>= fun targets ->
return (Default targets))
; cstr_record "opam"
(Opam.t >>= fun x -> return (Opam x))
]
sexp
let name = function let name = function
| Default -> "default" | Default _ -> "default"
| Opam o -> o.name | Opam o -> o.name
let targets = function
| Default l -> l
| Opam o -> o.targets
let all_names t =
let n = name t in
n :: List.filter_map (targets t) ~f:(function
| Native -> None
| Named s -> Some (n ^ "." ^ s))
end end
type t = type t =
@ -39,7 +72,8 @@ type t =
; contexts : Context.t list ; contexts : Context.t list
} }
let t sexps = let t ?x sexps =
let defined_names = ref String_set.empty in
let merlin_ctx, contexts = let merlin_ctx, contexts =
List.fold_left sexps ~init:(None, []) ~f:(fun (merlin_ctx, ctxs) sexp -> List.fold_left sexps ~init:(None, []) ~f:(fun (merlin_ctx, ctxs) sexp ->
let ctx = let ctx =
@ -47,6 +81,21 @@ let t sexps =
[ cstr "context" (Context.t @> nil) (fun x -> x) ] [ cstr "context" (Context.t @> nil) (fun x -> x) ]
sexp sexp
in in
let ctx =
match x with
| None -> ctx
| Some s ->
let target = Context.Target.Named s in
let add_target target targets =
if List.mem target ~set:targets then
targets
else
targets @ [target]
in
match ctx with
| Default targets -> Default (add_target target targets)
| Opam o -> Opam { o with targets = add_target target o.targets }
in
let name = Context.name ctx in let name = Context.name ctx in
if name = "" || if name = "" ||
String.is_prefix name ~prefix:"." || String.is_prefix name ~prefix:"." ||
@ -55,8 +104,9 @@ let t sexps =
String.contains name '/' || String.contains name '/' ||
String.contains name '\\' then String.contains name '\\' then
of_sexp_errorf sexp "%S is not allowed as a build context name" name; of_sexp_errorf sexp "%S is not allowed as a build context name" name;
if List.exists ctxs ~f:(fun c -> Context.name c = name) then if String_set.mem name !defined_names then
of_sexp_errorf sexp "second definition of build context %S" name; of_sexp_errorf sexp "second definition of build context %S" name;
defined_names := String_set.union !defined_names (String_set.of_list (Context.all_names ctx));
match ctx, merlin_ctx with match ctx, merlin_ctx with
| Opam { merlin = true; _ }, Some _ -> | Opam { merlin = true; _ }, Some _ ->
of_sexp_errorf sexp "you can only have one context for merlin" of_sexp_errorf sexp "you can only have one context for merlin"
@ -67,14 +117,14 @@ let t sexps =
in in
let contexts = let contexts =
match contexts with match contexts with
| [] -> [Context.Default] | [] -> [Context.Default [Native]]
| _ -> contexts | _ -> contexts
in in
let merlin_ctx = let merlin_ctx =
match merlin_ctx with match merlin_ctx with
| Some _ -> merlin_ctx | Some _ -> merlin_ctx
| None -> | None ->
if List.mem Context.Default ~set:contexts then if List.exists contexts ~f:(function Context.Default _ -> true | _ -> false) then
Some "default" Some "default"
else else
None None
@ -83,4 +133,4 @@ let t sexps =
; contexts = List.rev contexts ; contexts = List.rev contexts
} }
let load fname = t (Sexp.load ~fname ~mode:Many) let load ?x fname = t ?x (Sexp.load ~fname ~mode:Many)

View File

@ -3,16 +3,24 @@
open! Import open! Import
module Context : sig module Context : sig
module Target : sig
type t =
| Native
| Named of string
end
module Opam : sig module Opam : sig
type t = type t =
{ name : string { name : string
; switch : string ; switch : string
; root : string option ; root : string option
; merlin : bool ; merlin : bool
; targets : Target.t list
} }
end end
type t = Default | Opam of Opam.t type t = Default of Target.t list | Opam of Opam.t
val name : t -> string
end end
type t = type t =
@ -20,4 +28,4 @@ type t =
; contexts : Context.t list ; contexts : Context.t list
} }
val load : string -> t val load : ?x:string -> string -> t