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:
parent
afb602d7ef
commit
6e64156913
17
bin/main.ml
17
bin/main.ml
|
@ -21,6 +21,7 @@ type common =
|
|||
; target_prefix : string
|
||||
; only_packages : String_set.t option
|
||||
; capture_outputs : bool
|
||||
; x : string option
|
||||
; (* Original arguments for the external-lib-deps hint *)
|
||||
orig_args : string list
|
||||
}
|
||||
|
@ -74,7 +75,9 @@ module Main = struct
|
|||
?unlink_aliases
|
||||
?workspace_file:common.workspace_file
|
||||
?only_packages:common.only_packages
|
||||
?filter_out_optional_stanzas_with_missing_deps ()
|
||||
?filter_out_optional_stanzas_with_missing_deps
|
||||
?x:common.x
|
||||
()
|
||||
end
|
||||
|
||||
type target =
|
||||
|
@ -154,6 +157,7 @@ let common =
|
|||
no_buffer
|
||||
workspace_file
|
||||
(root, only_packages, orig)
|
||||
x
|
||||
=
|
||||
let root, to_cwd =
|
||||
match root with
|
||||
|
@ -181,6 +185,7 @@ let common =
|
|||
; only_packages =
|
||||
Option.map only_packages
|
||||
~f:(fun s -> String_set.of_list (String.split s ~on:','))
|
||||
; x
|
||||
}
|
||||
in
|
||||
let docs = copts_sect in
|
||||
|
@ -304,6 +309,12 @@ let common =
|
|||
$ only_packages
|
||||
$ frop))
|
||||
in
|
||||
let x =
|
||||
Arg.(value
|
||||
& opt (some string) None
|
||||
& info ["x"] ~docs
|
||||
~doc:{|Cross-compile using this toolchain.|})
|
||||
in
|
||||
Term.(const make
|
||||
$ concurrency
|
||||
$ ddep_path
|
||||
|
@ -314,6 +325,7 @@ let common =
|
|||
$ no_buffer
|
||||
$ workspace_file
|
||||
$ root_and_only_packages
|
||||
$ x
|
||||
)
|
||||
|
||||
let installed_libraries =
|
||||
|
@ -321,7 +333,8 @@ let installed_libraries =
|
|||
let go common na =
|
||||
set_common common ~targets:[];
|
||||
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
|
||||
if na then begin
|
||||
let pkgs = Findlib.all_unavailable_packages findlib in
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
;; This file is used by `make all-supported-ocaml-versions`
|
||||
(context ((switch 4.02.3)))
|
||||
(context ((switch 4.03.0)))
|
||||
(context ((switch 4.04.2)))
|
||||
(context ((switch 4.05.0)))
|
||||
(context ((switch 4.06.0)))
|
||||
(context ((switch 4.07.0+trunk)))
|
||||
(context (opam (switch 4.02.3)))
|
||||
(context (opam (switch 4.03.0)))
|
||||
(context (opam (switch 4.04.2)))
|
||||
(context (opam (switch 4.05.0)))
|
||||
(context (opam (switch 4.06.0)))
|
||||
(context (opam (switch 4.07.0+trunk)))
|
||||
|
|
450
src/context.ml
450
src/context.ml
|
@ -34,6 +34,7 @@ type t =
|
|||
; kind : Kind.t
|
||||
; merlin : bool
|
||||
; for_host : t option
|
||||
; implicit : bool
|
||||
; build_dir : Path.t
|
||||
; path : Path.t list
|
||||
; toplevel_path : Path.t option
|
||||
|
@ -46,6 +47,7 @@ type t =
|
|||
; env : string array
|
||||
; env_extra : string Env_var_map.t
|
||||
; findlib : Findlib.t
|
||||
; findlib_toolchain : string option
|
||||
; arch_sixtyfour : bool
|
||||
; opam_var_cache : (string, string) Hashtbl.t
|
||||
; natdynlink_supported : bool
|
||||
|
@ -175,7 +177,8 @@ let extend_env ~vars ~env =
|
|||
imported
|
||||
|> 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 opam_var_cache = Hashtbl.create 128 in
|
||||
(match kind with
|
||||
|
@ -187,195 +190,258 @@ let create ~(kind : Kind.t) ~path ~base_env ~env_extra ~name ~merlin ~use_findli
|
|||
in
|
||||
let which_cache = Hashtbl.create 128 in
|
||||
let which x = which ~cache:which_cache ~path x in
|
||||
let ocamlc =
|
||||
match which "ocamlc" with
|
||||
| None -> prog_not_found_in_path "ocamlc"
|
||||
| Some x -> x
|
||||
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 dir = Path.parent ocamlc in
|
||||
let prog_not_found prog =
|
||||
die "ocamlc found in %s, but %s/%s doesn't exist (context: %s)"
|
||||
(Path.to_string dir) (Path.to_string dir) prog name
|
||||
in
|
||||
let best_prog prog = Bin.best_prog dir prog in
|
||||
let get_prog prog =
|
||||
match best_prog prog with
|
||||
| None -> prog_not_found prog
|
||||
| Some fn -> fn
|
||||
in
|
||||
let build_dir =
|
||||
Path.of_string (sprintf "_build/%s" name)
|
||||
in
|
||||
let ocamlc_config_cmd = sprintf "%s -config" (Path.to_string ocamlc) in
|
||||
let findlib_path =
|
||||
if use_findlib then
|
||||
(* If ocamlfind is present, it has precedence over everything else. *)
|
||||
match which "ocamlfind" with
|
||||
| Some fn ->
|
||||
(Future.run_capture_lines ~env Strict
|
||||
(Path.to_string fn) ["printconf"; "path"]
|
||||
>>| List.map ~f:Path.absolute)
|
||||
| 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
|
||||
|
||||
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 =
|
||||
match get_tool_using_findlib_config "ocamlc" 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
|
||||
extend_env ~env ~vars:((Env_var_map.singleton "OCAMLPARAM" value)),
|
||||
(Env_var_map.add ~key:"OCAMLPARAM" ~data:value env_extra)
|
||||
else
|
||||
env,env_extra
|
||||
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)
|
||||
match which "ocamlc" with
|
||||
| Some x -> x
|
||||
| None -> prog_not_found_in_path "ocamlc"
|
||||
in
|
||||
let dir = Path.parent ocamlc in
|
||||
let ocaml_tool_not_found prog =
|
||||
die "ocamlc found in %s, but %s/%s doesn't exist (context: %s)"
|
||||
(Path.to_string dir) (Path.to_string dir) prog name
|
||||
in
|
||||
let get_ocaml_tool prog =
|
||||
match get_tool_using_findlib_config prog with
|
||||
| None -> Bin.best_prog dir 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
|
||||
in
|
||||
|
||||
let build_dir = Path.of_string (sprintf "_build/%s" name) in
|
||||
let ocamlc_config_cmd = sprintf "%s -config" (Path.to_string ocamlc) in
|
||||
let findlib_path =
|
||||
if use_findlib then
|
||||
(* If ocamlfind is present, it has precedence over everything else. *)
|
||||
match which "ocamlfind" with
|
||||
| Some fn ->
|
||||
let args =
|
||||
let args = ["printconf"; "path"] in
|
||||
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 ->
|
||||
(* If there no ocamlfind in the PATH, check if we have opam
|
||||
and assume a standard 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
|
||||
| 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
|
||||
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)
|
||||
extend_env ~env ~vars:((Env_var_map.singleton "OCAMLPARAM" value)),
|
||||
(Env_var_map.add ~key:"OCAMLPARAM" ~data:value env_extra)
|
||||
else
|
||||
env,env_extra
|
||||
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
|
||||
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
|
||||
; ocaml = Path.relative dir ("ocaml" ^ Bin.exe)
|
||||
; ocamlc
|
||||
; ocamlopt = best_prog "ocamlopt"
|
||||
; ocamldep = get_prog "ocamldep"
|
||||
; ocamlmklib = get_prog "ocamlmklib"
|
||||
|
||||
; env
|
||||
; env_extra
|
||||
; findlib = Findlib.create ~stdlib_dir ~path:findlib_path
|
||||
; 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
|
||||
}
|
||||
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
|
||||
|
||||
|
@ -383,7 +449,7 @@ let initial_env = lazy (
|
|||
Lazy.force Ansi_color.setup_env_for_colors;
|
||||
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 path =
|
||||
match get_env env "PATH" with
|
||||
|
@ -391,9 +457,9 @@ let default ?(merlin=true) ?(use_findlib=true) () =
|
|||
| None -> []
|
||||
in
|
||||
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
|
||||
| None -> Utils.program_not_found "opam"
|
||||
| Some fn ->
|
||||
|
@ -430,8 +496,14 @@ let create_for_opam ?root ~switch ~name ?(merlin=false) () =
|
|||
| Some s -> Bin.parse_path s
|
||||
in
|
||||
let env = Lazy.force initial_env in
|
||||
create ~kind:(Opam { root; switch }) ~path ~base_env:env ~env_extra:vars
|
||||
~name ~merlin ~use_findlib:true
|
||||
create ~kind:(Opam { root; switch }) ~targets
|
||||
~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
|
||||
|
||||
|
|
|
@ -48,6 +48,10 @@ type t =
|
|||
building tools used for the compilation that run on the host. *)
|
||||
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" *)
|
||||
build_dir : Path.t
|
||||
|
||||
|
@ -72,6 +76,7 @@ type t =
|
|||
env_extra : string Env_var_map.t
|
||||
|
||||
; findlib : Findlib.t
|
||||
; findlib_toolchain : string option
|
||||
|
||||
; (** Misc *)
|
||||
arch_sixtyfour : bool
|
||||
|
@ -124,18 +129,14 @@ val sexp_of_t : t -> Sexp.t
|
|||
(** Compare the context names *)
|
||||
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
|
||||
ocamlfind. This is only for building jbuilder itself, so that its build is completely
|
||||
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
|
||||
|
||||
|
|
38
src/main.ml
38
src/main.ml
|
@ -12,7 +12,8 @@ type setup =
|
|||
let package_install_file { packages; _ } pkg =
|
||||
match String_map.find pkg packages with
|
||||
| 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
|
||||
?filter_out_optional_stanzas_with_missing_deps
|
||||
|
@ -20,6 +21,7 @@ let setup ?(log=Log.no_log) ?unlink_aliases
|
|||
?(use_findlib=true)
|
||||
?only_packages
|
||||
?extra_ignored_subtrees
|
||||
?x
|
||||
() =
|
||||
let conf = Jbuild_load.load ?extra_ignored_subtrees () in
|
||||
Option.iter only_packages ~f:(fun set ->
|
||||
|
@ -33,26 +35,34 @@ let setup ?(log=Log.no_log) ?unlink_aliases
|
|||
| Some w -> w
|
||||
| None ->
|
||||
if Sys.file_exists workspace_file then
|
||||
Workspace.load workspace_file
|
||||
Workspace.load ?x workspace_file
|
||||
else
|
||||
{ merlin_context = Some "default"; contexts = [Default] }
|
||||
{ merlin_context = Some "default"
|
||||
; contexts = [Default [
|
||||
match x with
|
||||
| None -> Native
|
||||
| Some x -> Named x
|
||||
]]
|
||||
}
|
||||
in
|
||||
Future.all
|
||||
(List.map workspace.contexts ~f:(function
|
||||
| Workspace.Context.Default ->
|
||||
Context.default ~merlin:(workspace.merlin_context = Some "default")
|
||||
~use_findlib ()
|
||||
| Opam { name; switch; root; merlin } ->
|
||||
Context.create_for_opam ~name ~switch ?root ~merlin ()))
|
||||
|
||||
Future.all (
|
||||
List.map workspace.contexts ~f:(fun ctx_def ->
|
||||
let name = Workspace.Context.name ctx_def in
|
||||
Context.create ctx_def ~merlin:(workspace.merlin_context = Some name) ~use_findlib)
|
||||
)
|
||||
>>= 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));
|
||||
Gen_rules.gen conf ~contexts
|
||||
Gen_rules.gen conf
|
||||
~contexts
|
||||
?unlink_aliases
|
||||
?only_packages
|
||||
?filter_out_optional_stanzas_with_missing_deps
|
||||
>>= 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
|
||||
; stanzas
|
||||
; contexts
|
||||
|
@ -211,7 +221,7 @@ let bootstrap () =
|
|||
Clflags.debug_dep_path := true;
|
||||
let log = Log.create () in
|
||||
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
|
||||
~extra_ignored_subtrees:ignored_during_bootstrap
|
||||
()
|
||||
|
|
|
@ -22,6 +22,7 @@ val setup
|
|||
-> ?workspace:Workspace.t
|
||||
-> ?workspace_file:string
|
||||
-> ?only_packages:String_set.t
|
||||
-> ?x:string
|
||||
-> unit
|
||||
-> setup Future.t
|
||||
val external_lib_deps
|
||||
|
|
|
@ -2,36 +2,69 @@ open Import
|
|||
open Sexp.Of_sexp
|
||||
|
||||
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
|
||||
type t =
|
||||
{ name : string
|
||||
; switch : string
|
||||
; root : string option
|
||||
; merlin : bool
|
||||
{ name : string
|
||||
; switch : string
|
||||
; root : string option
|
||||
; merlin : bool
|
||||
; targets : Target.t list
|
||||
}
|
||||
|
||||
let t =
|
||||
record
|
||||
(field "switch" string >>= fun switch ->
|
||||
field "name" string ~default:switch >>= fun name ->
|
||||
field_o "root" string >>= fun root ->
|
||||
field_b "merlin" >>= fun merlin ->
|
||||
return { switch
|
||||
; name
|
||||
; root
|
||||
; merlin
|
||||
})
|
||||
field "switch" string >>= fun switch ->
|
||||
field "name" string ~default:switch >>= fun name ->
|
||||
field "targets" (list Target.t) ~default:[Target.Native] >>= fun targets ->
|
||||
field_o "root" string >>= fun root ->
|
||||
field_b "merlin" >>= fun merlin ->
|
||||
return { switch
|
||||
; name
|
||||
; root
|
||||
; merlin
|
||||
; targets
|
||||
}
|
||||
end
|
||||
|
||||
type t = Default | Opam of Opam.t
|
||||
type t = Default of Target.t list | Opam of Opam.t
|
||||
|
||||
let t = function
|
||||
| Atom (_, "default") -> Default
|
||||
| sexp -> Opam (Opam.t sexp)
|
||||
| Atom (_, "default") -> Default [Native]
|
||||
| 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
|
||||
| Default -> "default"
|
||||
| Opam o -> o.name
|
||||
| Default _ -> "default"
|
||||
| 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
|
||||
|
||||
type t =
|
||||
|
@ -39,7 +72,8 @@ type t =
|
|||
; contexts : Context.t list
|
||||
}
|
||||
|
||||
let t sexps =
|
||||
let t ?x sexps =
|
||||
let defined_names = ref String_set.empty in
|
||||
let merlin_ctx, contexts =
|
||||
List.fold_left sexps ~init:(None, []) ~f:(fun (merlin_ctx, ctxs) sexp ->
|
||||
let ctx =
|
||||
|
@ -47,6 +81,21 @@ let t sexps =
|
|||
[ cstr "context" (Context.t @> nil) (fun x -> x) ]
|
||||
sexp
|
||||
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
|
||||
if name = "" ||
|
||||
String.is_prefix name ~prefix:"." ||
|
||||
|
@ -55,8 +104,9 @@ let t sexps =
|
|||
String.contains name '/' ||
|
||||
String.contains name '\\' then
|
||||
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;
|
||||
defined_names := String_set.union !defined_names (String_set.of_list (Context.all_names ctx));
|
||||
match ctx, merlin_ctx with
|
||||
| Opam { merlin = true; _ }, Some _ ->
|
||||
of_sexp_errorf sexp "you can only have one context for merlin"
|
||||
|
@ -67,14 +117,14 @@ let t sexps =
|
|||
in
|
||||
let contexts =
|
||||
match contexts with
|
||||
| [] -> [Context.Default]
|
||||
| [] -> [Context.Default [Native]]
|
||||
| _ -> contexts
|
||||
in
|
||||
let merlin_ctx =
|
||||
match merlin_ctx with
|
||||
| Some _ -> merlin_ctx
|
||||
| None ->
|
||||
if List.mem Context.Default ~set:contexts then
|
||||
if List.exists contexts ~f:(function Context.Default _ -> true | _ -> false) then
|
||||
Some "default"
|
||||
else
|
||||
None
|
||||
|
@ -83,4 +133,4 @@ let t sexps =
|
|||
; contexts = List.rev contexts
|
||||
}
|
||||
|
||||
let load fname = t (Sexp.load ~fname ~mode:Many)
|
||||
let load ?x fname = t ?x (Sexp.load ~fname ~mode:Many)
|
||||
|
|
|
@ -3,16 +3,24 @@
|
|||
open! Import
|
||||
|
||||
module Context : sig
|
||||
module Target : sig
|
||||
type t =
|
||||
| Native
|
||||
| Named of string
|
||||
end
|
||||
module Opam : sig
|
||||
type t =
|
||||
{ name : string
|
||||
; switch : string
|
||||
; root : string option
|
||||
; merlin : bool
|
||||
; targets : Target.t list
|
||||
}
|
||||
end
|
||||
|
||||
type t = Default | Opam of Opam.t
|
||||
type t = Default of Target.t list | Opam of Opam.t
|
||||
|
||||
val name : t -> string
|
||||
end
|
||||
|
||||
type t =
|
||||
|
@ -20,4 +28,4 @@ type t =
|
|||
; contexts : Context.t list
|
||||
}
|
||||
|
||||
val load : string -> t
|
||||
val load : ?x:string -> string -> t
|
||||
|
|
Loading…
Reference in New Issue