diff --git a/bin/main.ml b/bin/main.ml index 02d7d7c1..df1433f9 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -574,6 +574,7 @@ let installed_libraries = (Default { loc = Loc.of_pos __POS__ ; targets = [Native] ; profile = Config.default_build_profile + ; env = None }) ~env >>= fun ctxs -> diff --git a/src/context.ml b/src/context.ml index 677c3685..d005a9a6 100644 --- a/src/context.ml +++ b/src/context.ml @@ -26,6 +26,7 @@ type t = ; for_host : t option ; implicit : bool ; build_dir : Path.t + ; env_node : Dune_env.Stanza.t option ; path : Path.t list ; toplevel_path : Path.t option ; ocaml_bin : Path.t @@ -130,7 +131,8 @@ let ocamlpath_sep = else Bin.path_sep -let create ~(kind : Kind.t) ~path ~env ~name ~merlin ~targets ~profile () = +let create ~(kind : Kind.t) ~path ~env ~env_node ~name ~merlin ~targets + ~profile () = let opam_var_cache = Hashtbl.create 128 in (match kind with | Opam { root; _ } -> @@ -332,6 +334,7 @@ let create ~(kind : Kind.t) ~path ~env ~name ~merlin ~targets ~profile () = ; kind ; profile ; merlin + ; env_node ; for_host = host ; build_dir ; path @@ -407,10 +410,11 @@ let create ~(kind : Kind.t) ~path ~env ~name ~merlin ~targets ~profile () = let opam_config_var t var = opam_config_var ~env:t.env ~cache:t.opam_var_cache var -let default ?(merlin=true) ~env ~targets () = - create ~kind:Default ~path:Bin.path ~env ~name:"default" ~merlin ~targets () +let default ?(merlin=true) ~env_node ~env ~targets () = + create ~kind:Default ~path:Bin.path ~env ~env_node ~name:"default" + ~merlin ~targets () -let create_for_opam ?root ~env ~targets ~profile ~switch ~name +let create_for_opam ?root ~env ~env_node ~targets ~profile ~switch ~name ?(merlin=false) () = match Bin.opam with | None -> Utils.program_not_found "opam" @@ -448,14 +452,16 @@ let create_for_opam ?root ~env ~targets ~profile ~switch ~name | Some s -> Bin.parse_path s in let env = Env.extend env ~vars in - create ~kind:(Opam { root; switch }) ~profile ~targets ~path ~env ~name - ~merlin () + create ~kind:(Opam { root; switch }) ~profile ~targets ~path ~env ~env_node + ~name ~merlin () let create ?merlin ~env def = match (def : Workspace.Context.t) with - | Default { targets; profile; _ } -> default ~env ~profile ~targets ?merlin () - | Opam { name; switch; root; targets; profile; _ } -> - create_for_opam ?root ~env ~profile ~switch ~name ?merlin ~targets () + | Default { targets; profile; env = env_node ; loc = _ } -> + default ~env ~env_node ~profile ~targets ?merlin () + | Opam { base = { targets ; profile ; env = env_node ; loc = _ } + ; name; switch; root; merlin = _ } -> + create_for_opam ?root ~env_node ~env ~profile ~switch ~name ?merlin ~targets () let which t s = which ~cache:t.which_cache ~path:t.path s diff --git a/src/context.mli b/src/context.mli index 733bd9d0..7cf4fe37 100644 --- a/src/context.mli +++ b/src/context.mli @@ -50,6 +50,9 @@ type t = ; (** Directory where artifact are stored, for instance "_build/default" *) build_dir : Path.t + ; (** env node that this context was initialized with *) + env_node : Dune_env.Stanza.t option + ; (** [PATH] *) path : Path.t list diff --git a/src/dune_env.ml b/src/dune_env.ml new file mode 100644 index 00000000..7f88ac71 --- /dev/null +++ b/src/dune_env.ml @@ -0,0 +1,49 @@ +type stanza = Stanza.t = .. + +module Stanza = struct + open Stanza.Of_sexp + + let field_oslu name = Ordered_set_lang.Unexpanded.field name + + type config = + { flags : Ordered_set_lang.Unexpanded.t + ; ocamlc_flags : Ordered_set_lang.Unexpanded.t + ; ocamlopt_flags : Ordered_set_lang.Unexpanded.t + } + + type pattern = + | Profile of string + | Any + + type t = + { loc : Loc.t + ; rules : (pattern * config) list + } + + let config = + let%map flags = field_oslu "flags" + and ocamlc_flags = field_oslu "ocamlc_flags" + and ocamlopt_flags = field_oslu "ocamlopt_flags" + in + { flags; ocamlc_flags; ocamlopt_flags } + + let rule = + enter + (let%map pat = + match_keyword [("_", return Any)] + ~fallback:(string >>| fun s -> Profile s) + and configs = fields config + in + (pat, configs)) + + let t = + let%map () = Syntax.since Stanza.syntax (1, 0) + and loc = loc + and rules = repeat rule + in + { loc; rules } + +end + +type stanza += + | T of Stanza.t diff --git a/src/dune_env.mli b/src/dune_env.mli new file mode 100644 index 00000000..afe45c3a --- /dev/null +++ b/src/dune_env.mli @@ -0,0 +1,25 @@ +open Import + +type stanza = Stanza.t = .. + +module Stanza : sig + type config = + { flags : Ordered_set_lang.Unexpanded.t + ; ocamlc_flags : Ordered_set_lang.Unexpanded.t + ; ocamlopt_flags : Ordered_set_lang.Unexpanded.t + } + + type pattern = + | Profile of string + | Any + + type t = + { loc : Loc.t + ; rules : (pattern * config) list + } + + val t : t Sexp.Of_sexp.t +end + +type stanza += + | T of Stanza.t diff --git a/src/jbuild.ml b/src/jbuild.ml index 38c6eb67..2f793065 100644 --- a/src/jbuild.ml +++ b/src/jbuild.ml @@ -1517,39 +1517,6 @@ module Documentation = struct ) end -module Env = struct - type config = - { flags : Ordered_set_lang.Unexpanded.t - ; ocamlc_flags : Ordered_set_lang.Unexpanded.t - ; ocamlopt_flags : Ordered_set_lang.Unexpanded.t - } - - type pattern = - | Profile of string - | Any - - type t = - { loc : Loc.t - ; rules : (pattern * config) list - } - - let config = - let%map flags = field_oslu "flags" - and ocamlc_flags = field_oslu "ocamlc_flags" - and ocamlopt_flags = field_oslu "ocamlopt_flags" - in - { flags; ocamlc_flags; ocamlopt_flags } - - let rule = - enter - (let%map pat = - match_keyword [("_", return Any)] - ~fallback:(string >>| fun s -> Profile s) - and configs = fields config - in - (pat, configs)) -end - type Stanza.t += | Library of Library.t | Executables of Executables.t @@ -1558,7 +1525,6 @@ type Stanza.t += | Alias of Alias_conf.t | Copy_files of Copy_files.t | Documentation of Documentation.t - | Env of Env.t | Tests of Tests.t module Stanzas = struct @@ -1627,10 +1593,8 @@ module Stanzas = struct and t = Tests.single in [Tests t]) ; "env", - (let%map () = Syntax.since Stanza.syntax (1, 0) - and loc = loc - and rules = repeat Env.rule in - [Env { loc; rules }]) + (let%map x = Dune_env.Stanza.t in + [Dune_env.T x]) ] let jbuild_parser = @@ -1700,7 +1664,10 @@ module Stanzas = struct "\n--> included from %s" (line_loc x)))) in - match List.filter_map stanzas ~f:(function Env e -> Some e | _ -> None) with + match + List.filter_map stanzas + ~f:(function Dune_env.T e -> Some e | _ -> None) + with | _ :: e :: _ -> Loc.fail e.loc "The 'env' stanza cannot appear more than once" | _ -> stanzas diff --git a/src/jbuild.mli b/src/jbuild.mli index 840d6ff9..2c432ff8 100644 --- a/src/jbuild.mli +++ b/src/jbuild.mli @@ -351,23 +351,6 @@ module Documentation : sig } end -module Env : sig - type config = - { flags : Ordered_set_lang.Unexpanded.t - ; ocamlc_flags : Ordered_set_lang.Unexpanded.t - ; ocamlopt_flags : Ordered_set_lang.Unexpanded.t - } - - type pattern = - | Profile of string - | Any - - type t = - { loc : Loc.t - ; rules : (pattern * config) list - } -end - module Tests : sig type t = { exes : Executables.t @@ -385,7 +368,6 @@ type Stanza.t += | Alias of Alias_conf.t | Copy_files of Copy_files.t | Documentation of Documentation.t - | Env of Env.t | Tests of Tests.t module Stanzas : sig diff --git a/src/super_context.ml b/src/super_context.ml index 67424618..7dc19eff 100644 --- a/src/super_context.ml +++ b/src/super_context.ml @@ -28,7 +28,7 @@ module Env_node = struct { dir : Path.t ; inherit_from : t Lazy.t option ; scope : Scope.t - ; config : Env.t + ; config : Dune_env.Stanza.t ; mutable ocaml_flags : Ocaml_flags.t option } end @@ -419,6 +419,7 @@ end = struct let rec get t ~dir = match Hashtbl.find t.env dir with + | Some node -> node | None -> begin match Path.parent dir with | None -> raise_notrace Exit @@ -427,7 +428,6 @@ end = struct Hashtbl.add t.env dir node; node end - | Some node -> node let get t ~dir = match get t ~dir with @@ -448,7 +448,7 @@ end = struct in let flags = match List.find_map node.config.rules ~f:(fun (pat, cfg) -> - match (pat : Env.pattern), profile t with + match (pat : Dune_env.Stanza.pattern), profile t with | Any, _ -> Some cfg | Profile a, b -> Option.some_if (a = b) cfg) with @@ -611,33 +611,40 @@ let create ; env = Hashtbl.create 128 } in + let context_env_node = lazy ( + let config = + match context.env_node with + | Some s -> s + | None -> { loc = Loc.none; rules = [] } + in + { Env_node. + dir = context.build_dir + ; inherit_from = None + ; scope = Scope.DB.find_by_dir scopes context.build_dir + ; config + ; ocaml_flags = None + } + ) in List.iter stanzas ~f:(fun { Dir_with_jbuild. ctx_dir; scope; stanzas; _ } -> List.iter stanzas ~f:(function - | Env config -> + | Dune_env.T config -> let inherit_from = if ctx_dir = Scope.root scope then - None + context_env_node else - Some (lazy (Env.get t ~dir:(Path.parent_exn ctx_dir))) + lazy (Env.get t ~dir:(Path.parent_exn ctx_dir)) in Hashtbl.add t.env ctx_dir { dir = ctx_dir - ; inherit_from = inherit_from + ; inherit_from = Some inherit_from ; scope = scope ; config = config ; ocaml_flags = None } | _ -> ())); if not (Hashtbl.mem t.env context.build_dir) then - Hashtbl.add t.env context.build_dir - { Env_node. - dir = context.build_dir - ; inherit_from = None - ; scope = Scope.DB.find_by_dir scopes context.build_dir - ; config = { loc = Loc.none; rules = [] } - ; ocaml_flags = None - }; + Hashtbl.add t.env context.build_dir (Lazy.force context_env_node); t module Libs = struct open Build.O diff --git a/src/workspace.ml b/src/workspace.ml index 65999fa1..f4780297 100644 --- a/src/workspace.ml +++ b/src/workspace.ml @@ -40,60 +40,66 @@ module Context = struct name) end - module Opam = struct - type t = - { loc : Loc.t - ; name : string - ; profile : string - ; switch : string - ; root : string option - ; merlin : bool - ; targets : Target.t list - } - - let t ~profile ~x = - field "switch" string >>= fun switch -> - field "name" Name.t ~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 -> - field "profile" string ~default:profile >>= fun profile -> - loc >>= fun loc -> - return { loc - ; switch - ; name - ; root - ; merlin - ; targets = Target.add targets x - ; profile - } - end - - module Default = struct + module Common = struct type t = { loc : Loc.t ; profile : string ; targets : Target.t list + ; env : Dune_env.Stanza.t option } - let t ~profile ~x = + let t ~profile = + field_o "env" Dune_env.Stanza.t >>= fun env -> field "targets" (list Target.t) ~default:[Target.Native] >>= fun targets -> field "profile" string ~default:profile >>= fun profile -> - loc - >>= fun loc -> - return { loc - ; targets = Target.add targets x - ; profile + loc >>= fun loc -> + return + { targets + ; profile + ; loc + ; env + } + end + + module Opam = struct + type t = + { base : Common.t + ; name : string + ; switch : string + ; root : string option + ; merlin : bool + } + + let t ~profile ~x = + Common.t ~profile >>= fun base -> + field "switch" string >>= fun switch -> + field "name" Name.t ~default:switch >>= fun name -> + field_o "root" string >>= fun root -> + field_b "merlin" >>= fun merlin -> + let base = { base with targets = Target.add base.targets x } in + return { base + ; switch + ; name + ; root + ; merlin } end + module Default = struct + type t = Common.t + + let t ~profile ~x = + Common.t ~profile >>= fun t -> + return { t with targets = Target.add t.targets x } + end + type t = Default of Default.t | Opam of Opam.t let loc = function | Default x -> x.loc - | Opam x -> x.loc + | Opam x -> x.base.loc let t ~profile ~x = sum @@ -121,7 +127,7 @@ module Context = struct let targets = function | Default x -> x.targets - | Opam x -> x.targets + | Opam x -> x.base.targets let all_names t = let n = name t in @@ -135,6 +141,7 @@ module Context = struct ; targets = [Option.value x ~default:Target.Native] ; profile = Option.value profile ~default:Config.default_build_profile + ; env = None } end diff --git a/src/workspace.mli b/src/workspace.mli index 19c04bdc..fa5fd6a4 100644 --- a/src/workspace.mli +++ b/src/workspace.mli @@ -8,24 +8,26 @@ module Context : sig | Native | Named of string end - module Opam : sig + module Common : sig type t = { loc : Loc.t - ; name : string ; profile : string + ; targets : Target.t list + ; env : Dune_env.Stanza.t option + } + end + module Opam : sig + type t = + { base : Common.t + ; name : string ; switch : string ; root : string option ; merlin : bool - ; targets : Target.t list } end module Default : sig - type t = - { loc : Loc.t - ; profile : string - ; targets : Target.t list - } + type t = Common.t end type t = Default of Default.t | Opam of Opam.t diff --git a/test/blackbox-tests/test-cases/workspaces/run.t b/test/blackbox-tests/test-cases/workspaces/run.t index e33d288a..68895ba7 100644 --- a/test/blackbox-tests/test-cases/workspaces/run.t +++ b/test/blackbox-tests/test-cases/workspaces/run.t @@ -47,3 +47,13 @@ see how we can set a "native" target. Which is the default. Entering directory 'targets-native' Entering directory 'targets-native' message from targets-native test + +Workspaces also allow you to set the env for a context: + + $ dune printenv --root workspace-env --profile default + Entering directory 'workspace-env' + ( + (flags (-w -40 -machin)) + (ocamlc_flags (-g)) + (ocamlopt_flags (-g)) + ) diff --git a/test/blackbox-tests/test-cases/workspaces/workspace-env/dune b/test/blackbox-tests/test-cases/workspaces/workspace-env/dune new file mode 100644 index 00000000..e69de29b diff --git a/test/blackbox-tests/test-cases/workspaces/workspace-env/dune-project b/test/blackbox-tests/test-cases/workspaces/workspace-env/dune-project new file mode 100644 index 00000000..b2559fa0 --- /dev/null +++ b/test/blackbox-tests/test-cases/workspaces/workspace-env/dune-project @@ -0,0 +1 @@ +(lang dune 1.0) \ No newline at end of file diff --git a/test/blackbox-tests/test-cases/workspaces/workspace-env/dune-workspace b/test/blackbox-tests/test-cases/workspaces/workspace-env/dune-workspace new file mode 100644 index 00000000..30a26e35 --- /dev/null +++ b/test/blackbox-tests/test-cases/workspaces/workspace-env/dune-workspace @@ -0,0 +1,7 @@ +(lang dune 1.0) + +(context + (default + (env + (default + (flags (:standard -machin)))))) \ No newline at end of file