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,195 +190,258 @@ 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 ocamlc = let findlib_config_path = lazy (
match which "ocamlc" with match which "ocamlfind" with
| None -> prog_not_found_in_path "ocamlc" | None -> prog_not_found_in_path "ocamlfind"
| Some x -> x | 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 in
let dir = Path.parent ocamlc in
let prog_not_found prog = let create_one ~name ~implicit ?findlib_toolchain ?host ~merlin () =
die "ocamlc found in %s, but %s/%s doesn't exist (context: %s)" (match findlib_toolchain with
(Path.to_string dir) (Path.to_string dir) prog name | None -> Future.return None
in | Some toolchain ->
let best_prog prog = Bin.best_prog dir prog in Lazy.force findlib_config_path >>| fun path ->
let get_prog prog = Some (Findlib.Config.load path ~toolchain ~context:name))
match best_prog prog with >>= fun findlib_config ->
| None -> prog_not_found prog
| Some fn -> fn let get_tool_using_findlib_config prog =
in match findlib_config with
let build_dir = | None -> None
Path.of_string (sprintf "_build/%s" name) | Some conf ->
in match Findlib.Config.get conf prog with
let ocamlc_config_cmd = sprintf "%s -config" (Path.to_string ocamlc) in | "" -> None
let findlib_path = | s ->
if use_findlib then match Filename.analyze_program_name s with
(* If ocamlfind is present, it has precedence over everything else. *) | In_path | Relative_to_current_dir -> which s
match which "ocamlfind" with | Absolute -> Some (Path.absolute s)
| Some fn -> in
(Future.run_capture_lines ~env Strict
(Path.to_string fn) ["printconf"; "path"] let ocamlc =
>>| List.map ~f:Path.absolute) match get_tool_using_findlib_config "ocamlc" with
| None ->
(* If there no ocamlfind in the PATH, check if we have opam and assume a stan opam
setup *)
opam_config_var ~env ~cache:opam_var_cache "lib"
>>| function
| Some s -> [Path.absolute s]
| None ->
(* If neither opam neither ocamlfind are present, assume that libraries are
[dir ^ "/../lib"] *)
[Path.relative (Path.parent dir) "lib"]
else
return []
in
both
findlib_path
(Future.run_capture_lines ~env Strict (Path.to_string ocamlc) ["-config"])
>>= fun (findlib_path, ocamlc_config) ->
let ocamlc_config =
List.map ocamlc_config ~f:(fun line ->
match String.index line ':' with
| Some i ->
(String.sub line ~pos:0 ~len:i,
String.sub line ~pos:(i + 2) ~len:(String.length line - i - 2))
| None ->
die "unrecognized line in the output of `%s`: %s" ocamlc_config_cmd
line)
|> String_map.of_alist
|> function
| Ok x -> x
| Error (key, _, _) ->
die "variable %S present twice in the output of `%s`" key ocamlc_config_cmd
in
let get_opt var = String_map.find var ocamlc_config in
let get ?default var =
match get_opt var with
| Some s -> s
| None ->
match default with
| Some x -> x | Some x -> x
| None -> | None ->
die "variable %S not found in the output of `%s`" var ocamlc_config_cmd match which "ocamlc" with
in | Some x -> x
let get_bool ?default var = | None -> prog_not_found_in_path "ocamlc"
match get ?default:(Option.map default ~f:string_of_bool) var with in
| "true" -> true let dir = Path.parent ocamlc in
| "false" -> false let ocaml_tool_not_found prog =
| _ -> die "variable %S is neither 'true' neither 'false' in the output of `%s`" die "ocamlc found in %s, but %s/%s doesn't exist (context: %s)"
var ocamlc_config_cmd (Path.to_string dir) (Path.to_string dir) prog name
in in
let get_path var = Path.absolute (get var) in let get_ocaml_tool prog =
let stdlib_dir = get_path "standard_library" in match get_tool_using_findlib_config prog with
let natdynlink_supported = Path.exists (Path.relative stdlib_dir "dynlink.cmxa") in | None -> Bin.best_prog dir prog
let version = get "version" in | Some _ as x -> x
let env,env_extra = in
(* See comment in ansi_color.ml for setup_env_for_colors. For OCaml < 4.05, let get_ocaml_tool_exn prog =
OCAML_COLOR is not supported so we use OCAMLPARAM. OCaml 4.02 doesn't support match get_ocaml_tool prog with
'color' in OCAMLPARAM, so we just don't force colors with 4.02. *) | None -> ocaml_tool_not_found prog
let ocaml_version = Scanf.sscanf version "%u.%u" (fun a b -> a, b) in | Some fn -> fn
if !Clflags.capture_outputs in
&& Lazy.force Ansi_color.stderr_supports_colors
&& ocaml_version > (4, 02) let build_dir = Path.of_string (sprintf "_build/%s" name) in
&& ocaml_version < (4, 05) then let ocamlc_config_cmd = sprintf "%s -config" (Path.to_string ocamlc) in
let value = let findlib_path =
match get_env env "OCAMLPARAM" with if use_findlib then
| None -> "color=always,_" (* If ocamlfind is present, it has precedence over everything else. *)
| Some s -> "color=always," ^ s match which "ocamlfind" with
in | Some fn ->
extend_env ~env ~vars:((Env_var_map.singleton "OCAMLPARAM" value)), let args =
(Env_var_map.add ~key:"OCAMLPARAM" ~data:value env_extra) let args = ["printconf"; "path"] in
else match findlib_toolchain with
env,env_extra | None -> args
in | Some s -> "-toolchain" :: s :: args
let c_compiler, ocamlc_cflags, ocamlopt_cflags = in
match get_opt "c_compiler" with Future.run_capture_lines ~env Strict (Path.to_string fn) args
| Some c_compiler -> (* >= 4.06 *) >>| List.map ~f:Path.absolute
(c_compiler, get "ocamlc_cflags", get "ocamlopt_cflags") | None ->
| None -> (* If there no ocamlfind in the PATH, check if we have opam
let split_prog s = and assume a standard opam setup *)
let len = String.length s in opam_config_var ~env ~cache:opam_var_cache "lib"
let rec loop i = >>| function
if i = len then | Some s -> [Path.absolute s]
(s, "") | None ->
else (* If neither opam neither ocamlfind are present, assume that libraries are
match s.[i] with [dir ^ "/../lib"] *)
| ' ' | '\t' -> [Path.relative (Path.parent dir) "lib"]
(String.sub s ~pos:0 ~len:i, else
String.sub s ~pos:i ~len:(len - i)) return []
| _ -> loop (i + 1) in
both
findlib_path
(Future.run_capture_lines ~env Strict (Path.to_string ocamlc) ["-config"])
>>= fun (findlib_path, ocamlc_config) ->
let ocamlc_config =
List.map ocamlc_config ~f:(fun line ->
match String.index line ':' with
| Some i ->
(String.sub line ~pos:0 ~len:i,
String.sub line ~pos:(i + 2) ~len:(String.length line - i - 2))
| None ->
die "unrecognized line in the output of `%s`: %s" ocamlc_config_cmd
line)
|> String_map.of_alist
|> function
| Ok x -> x
| Error (key, _, _) ->
die "variable %S present twice in the output of `%s`" key ocamlc_config_cmd
in
let get_opt var = String_map.find var ocamlc_config in
let get ?default var =
match get_opt var with
| Some s -> s
| None ->
match default with
| Some x -> x
| None ->
die "variable %S not found in the output of `%s`" var ocamlc_config_cmd
in
let get_bool ?default var =
match get ?default:(Option.map default ~f:string_of_bool) var with
| "true" -> true
| "false" -> false
| _ -> die "variable %S is neither 'true' neither 'false' in the output of `%s`"
var ocamlc_config_cmd
in
let get_path var = Path.absolute (get var) in
let stdlib_dir = get_path "standard_library" in
let natdynlink_supported = Path.exists (Path.relative stdlib_dir "dynlink.cmxa") in
let version = get "version" in
let env, env_extra =
(* 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
'color' in OCAMLPARAM, so we just don't force colors with 4.02. *)
let ocaml_version = Scanf.sscanf version "%u.%u" (fun a b -> a, b) in
if !Clflags.capture_outputs
&& Lazy.force Ansi_color.stderr_supports_colors
&& ocaml_version > (4, 02)
&& ocaml_version < (4, 05) then
let value =
match get_env env "OCAMLPARAM" with
| None -> "color=always,_"
| Some s -> "color=always," ^ s
in in
loop 0 extend_env ~env ~vars:((Env_var_map.singleton "OCAMLPARAM" value)),
in (Env_var_map.add ~key:"OCAMLPARAM" ~data:value env_extra)
let c_compiler, ocamlc_cflags = split_prog (get "bytecomp_c_compiler") in else
let _, ocamlopt_cflags = split_prog (get "native_c_compiler") in env,env_extra
(c_compiler, ocamlc_cflags, ocamlopt_cflags) in
let c_compiler, ocamlc_cflags, ocamlopt_cflags =
match get_opt "c_compiler" with
| Some c_compiler -> (* >= 4.06 *)
(c_compiler, get "ocamlc_cflags", get "ocamlopt_cflags")
| None ->
let split_prog s =
let len = String.length s in
let rec loop i =
if i = len then
(s, "")
else
match s.[i] with
| ' ' | '\t' ->
(String.sub s ~pos:0 ~len:i,
String.sub s ~pos:i ~len:(len - i))
| _ -> loop (i + 1)
in
loop 0
in
let c_compiler, ocamlc_cflags = split_prog (get "bytecomp_c_compiler") in
let _, ocamlopt_cflags = split_prog (get "native_c_compiler") in
(c_compiler, ocamlc_cflags, ocamlopt_cflags)
in
let arch_sixtyfour =
match get_opt "word_size" with
| Some ws -> ws = "64"
| None -> get_arch_sixtyfour stdlib_dir
in
return
{ name
; implicit
; kind
; merlin
; for_host = host
; build_dir
; path
; toplevel_path = Option.map (get_env env "OCAML_TOPLEVEL_PATH") ~f:Path.absolute
; ocaml_bin = dir
; ocaml = (match which "ocaml" with Some p -> p | None -> prog_not_found_in_path "ocaml")
; ocamlc
; ocamlopt = get_ocaml_tool "ocamlopt"
; ocamldep = get_ocaml_tool_exn "ocamldep"
; ocamlmklib = get_ocaml_tool_exn "ocamlmklib"
; env
; env_extra
; findlib = Findlib.create ~stdlib_dir ~path:findlib_path
; findlib_toolchain
; arch_sixtyfour
; opam_var_cache
; natdynlink_supported
; stdlib_dir
; ocamlc_config = String_map.bindings ocamlc_config
; version
; ccomp_type = get "ccomp_type"
; c_compiler
; ocamlc_cflags
; ocamlopt_cflags
; bytecomp_c_libraries = get "bytecomp_c_libraries"
; native_c_libraries = get "native_c_libraries"
; native_pack_linker = get "native_pack_linker"
; ranlib = get "ranlib"
; cc_profile = get "cc_profile"
; architecture = get "architecture"
; system = get "system"
; ext_obj = get "ext_obj"
; ext_asm = get "ext_asm"
; ext_lib = get "ext_lib"
; ext_dll = get "ext_dll"
; os_type = get "os_type"
; default_executable_name = get "default_executable_name"
; host = get "host"
; target = get "target"
; flambda = get_bool "flambda" ~default:false
; exec_magic_number = get "exec_magic_number"
; cmi_magic_number = get "cmi_magic_number"
; cmo_magic_number = get "cmo_magic_number"
; cma_magic_number = get "cma_magic_number"
; cmx_magic_number = get "cmx_magic_number"
; cmxa_magic_number = get "cmxa_magic_number"
; ast_impl_magic_number = get "ast_impl_magic_number"
; ast_intf_magic_number = get "ast_intf_magic_number"
; cmxs_magic_number = get "cmxs_magic_number"
; cmt_magic_number = get "cmt_magic_number"
; which_cache
}
in in
let arch_sixtyfour =
match get_opt "word_size" with
| Some ws -> ws = "64"
| None -> get_arch_sixtyfour stdlib_dir
in
return
{ name
; kind
; merlin
; for_host = None
; build_dir
; path
; toplevel_path = Option.map (get_env env "OCAML_TOPLEVEL_PATH") ~f:Path.absolute
; ocaml_bin = dir let implicit = not (List.mem ~set:targets Workspace.Context.Target.Native) in
; ocaml = Path.relative dir ("ocaml" ^ Bin.exe) create_one () ~implicit ~name ~merlin >>= fun native ->
; ocamlc Future.all (
; ocamlopt = best_prog "ocamlopt" List.filter_map targets ~f:(function
; ocamldep = get_prog "ocamldep" | Native -> None
; ocamlmklib = get_prog "ocamlmklib" | Named findlib_toolchain ->
let name = sprintf "%s.%s" name findlib_toolchain in
; env Some (create_one () ~implicit:false ~name ~findlib_toolchain ~host:native
; env_extra ~merlin:false)
; findlib = Findlib.create ~stdlib_dir ~path:findlib_path )
; arch_sixtyfour ) >>| fun others ->
native :: others
; opam_var_cache
; natdynlink_supported
; stdlib_dir
; ocamlc_config = String_map.bindings ocamlc_config
; version
; ccomp_type = get "ccomp_type"
; c_compiler
; ocamlc_cflags
; ocamlopt_cflags
; bytecomp_c_libraries = get "bytecomp_c_libraries"
; native_c_libraries = get "native_c_libraries"
; native_pack_linker = get "native_pack_linker"
; ranlib = get "ranlib"
; cc_profile = get "cc_profile"
; architecture = get "architecture"
; system = get "system"
; ext_obj = get "ext_obj"
; ext_asm = get "ext_asm"
; ext_lib = get "ext_lib"
; ext_dll = get "ext_dll"
; os_type = get "os_type"
; default_executable_name = get "default_executable_name"
; host = get "host"
; target = get "target"
; flambda = get_bool "flambda" ~default:false
; exec_magic_number = get "exec_magic_number"
; cmi_magic_number = get "cmi_magic_number"
; cmo_magic_number = get "cmo_magic_number"
; cma_magic_number = get "cma_magic_number"
; cmx_magic_number = get "cmx_magic_number"
; cmxa_magic_number = get "cmxa_magic_number"
; ast_impl_magic_number = get "ast_impl_magic_number"
; ast_intf_magic_number = get "ast_intf_magic_number"
; cmxs_magic_number = get "cmxs_magic_number"
; cmt_magic_number = get "cmt_magic_number"
; which_cache
}
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