diff --git a/doc/changes/changed/14432.md b/doc/changes/changed/14432.md new file mode 100644 index 00000000000..20869a2e057 --- /dev/null +++ b/doc/changes/changed/14432.md @@ -0,0 +1,5 @@ +- `%{bin:NAME}` now resolves to the build artifact path rather than + the install staging path. Rules with `%{bin:NAME}` deps additionally + get a per-rule bin-layout directory prepended to the action's + `PATH`, containing correctly-named symlinks for each declared bin + pform dep. (#14432, fixes #3324, @Alizter) diff --git a/doc/changes/fixed/14373-named-binding-package.md b/doc/changes/fixed/14373-named-binding-package.md new file mode 100644 index 00000000000..0ab886dbe69 --- /dev/null +++ b/doc/changes/fixed/14373-named-binding-package.md @@ -0,0 +1,3 @@ +- Reject `(package ...)` inside a named dependency binding + (`(deps (:name (package foo)))`). Previously this was silently + accepted but `%{name}` would resolve to an empty path list. (@Alizter) diff --git a/src/dune_rules/action_unexpanded.ml b/src/dune_rules/action_unexpanded.ml index b69c458f4cb..73a414cbff0 100644 --- a/src/dune_rules/action_unexpanded.ml +++ b/src/dune_rules/action_unexpanded.ml @@ -629,7 +629,7 @@ let rec expand (t : Dune_lang.Action.t) : Action.t Action_expander.t = let expand_no_targets t sandbox ~loc ~chdir ~deps:deps_written_by_user ~expander ~what = let open Action_builder.O in - let deps_builder, expander, sandbox = + let action_env, expander, sandbox = Dep_conf_eval.named ~expander sandbox deps_written_by_user in let expander = @@ -650,11 +650,11 @@ let expand_no_targets t sandbox ~loc ~chdir ~deps:deps_written_by_user ~expander (String.capitalize what) ; pp_targets targets ]; - let+ () = deps_builder - and+ sandbox = sandbox + let+ sandbox = sandbox + and+ env = action_env and+ action = build in let action = Action.Chdir (Path.build chdir, action) in - Action.Full.make action ~sandbox + Action.Full.make action ~sandbox |> Action.Full.add_env env ;; let expand @@ -668,7 +668,7 @@ let expand ~expander = let open Action_builder.O in - let deps_builder, expander, sandbox = + let action_env, expander, sandbox = Dep_conf_eval.named sandbox ~expander deps_written_by_user in let expander = @@ -711,10 +711,11 @@ let expand Targets.combine targets (Targets.create ~files ~dirs) in let build = - let+ () = deps_builder - and+ sandbox = sandbox + let+ sandbox = sandbox + and+ env = action_env and+ action = build in Action.Full.make (Action.Chdir (Path.build chdir, action)) ~sandbox + |> Action.Full.add_env env in Action_builder.with_targets ~targets build ;; diff --git a/src/dune_rules/artifacts.ml b/src/dune_rules/artifacts.ml index aabf43aaf63..7a1249f4c70 100644 --- a/src/dune_rules/artifacts.ml +++ b/src/dune_rules/artifacts.ml @@ -9,6 +9,7 @@ type origin = ; dir : Path.Build.t ; dst : Path.Local.t ; enabled_if : bool Memo.t + ; package : Package.Name.t option } type where = @@ -87,7 +88,7 @@ let analyze_binary t ~dir name = ])) ;; -let binary t ?hint ?(where = Install_dir) ~dir ~loc name = +let binary t ?hint ?(where = Original_path) ~dir ~loc name = analyze_binary t ~dir name >>= function | `Resolved path -> Memo.return @@ Ok path @@ -95,7 +96,7 @@ let binary t ?hint ?(where = Install_dir) ~dir ~loc name = let context = Context.name t.context in Memo.return @@ Error (Action.Prog.Not_found.create ~program:name ?hint ~context ~loc ()) - | `Origin { dir; binding; dst; enabled_if = _ } -> + | `Origin { dir; binding; dst; enabled_if = _; package = _ } -> (match where with | Install_dir -> let install_dir = Install.Context.bin_dir ~context:(Context.name t.context) in @@ -112,6 +113,13 @@ let binary t ?hint ?(where = Install_dir) ~dir ~loc name = Ok (Path.build src)) ;; +let binary_package t ~dir name = + analyze_binary t ~dir name + >>| function + | `Origin { package; _ } -> package + | `Resolved _ | `None -> None +;; + let binary_available t ~dir name = analyze_binary t ~dir name >>| function diff --git a/src/dune_rules/artifacts.mli b/src/dune_rules/artifacts.mli index 5ca6d6e16ac..7a9ab7adc32 100644 --- a/src/dune_rules/artifacts.mli +++ b/src/dune_rules/artifacts.mli @@ -7,6 +7,7 @@ type origin = ; dir : Path.Build.t ; dst : Path.Local.t ; enabled_if : bool Memo.t + ; package : Package.Name.t option } type where = @@ -38,6 +39,7 @@ val binary -> Filename.t -> Action.Prog.t Memo.t +val binary_package : t -> dir:Path.Build.t -> string -> Package.Name.t option Memo.t val binary_available : t -> dir:Path.Build.t -> string -> bool Memo.t val add_binaries : t -> dir:Path.Build.t -> File_binding.Expanded.t list -> t diff --git a/src/dune_rules/artifacts_db.ml b/src/dune_rules/artifacts_db.ml index 651939bf13e..4f058d446e3 100644 --- a/src/dune_rules/artifacts_db.ml +++ b/src/dune_rules/artifacts_db.ml @@ -55,7 +55,7 @@ let get_installed_binaries ~(context : Context.t) stanzas = >>| fst in let eval_blang = Expander0.eval_blang expander in - let binaries_from_install ~enabled_if files = + let binaries_from_install ~enabled_if ~package files = let* unexpanded_file_bindings = Install_entry.File.to_file_bindings_unexpanded files ~expand:expand_value ~dir in @@ -70,7 +70,7 @@ let get_installed_binaries ~(context : Context.t) stanzas = let dst = Install.Entry.Dst.local p in if Path.Local.is_root (Path.Local.parent_exn dst) then ( - let origin = { Artifacts.binding = fb; dir; dst; enabled_if } in + let origin = { Artifacts.binding = fb; dir; dst; enabled_if; package } in Some (Path.Local.basename dst, origin)) else None) >>| List.filter_opt @@ -83,12 +83,13 @@ let get_installed_binaries ~(context : Context.t) stanzas = Dune_file.static_stanzas d |> Memo.List.map ~f:(fun stanza -> match Stanza.repr stanza with - | Install_conf.T { section = _loc, Section Bin; files; enabled_if; _ } -> + | Install_conf.T { section = _loc, Section Bin; files; enabled_if; package; _ } -> let enabled_if = eval_blang enabled_if in - binaries_from_install ~enabled_if files + let package = Some (Package.name package) in + binaries_from_install ~enabled_if ~package files | Executables.T - ({ install_conf = Some { section = _loc, Section Bin; files; _ }; _ } as exes) - -> + ({ install_conf = Some { section = _loc, Section Bin; files; package; _ }; _ } + as exes) -> let enabled_if = let enabled_if = eval_blang exes.enabled_if in match exes.optional with @@ -99,7 +100,8 @@ let get_installed_binaries ~(context : Context.t) stanzas = | false -> Memo.return false | true -> available_exes ~dir exes) in - binaries_from_install ~enabled_if files + let package = Some (Package.name package) in + binaries_from_install ~enabled_if ~package files | _ -> Memo.return Filename.Map.empty) >>| Filename.Map.union_all ~f:merge) >>| Filename.Map.union_all ~f:merge diff --git a/src/dune_rules/bin_layout.ml b/src/dune_rules/bin_layout.ml new file mode 100644 index 00000000000..9796c6cd68c --- /dev/null +++ b/src/dune_rules/bin_layout.ml @@ -0,0 +1,100 @@ +open Import + +module Key : sig + type encoded = Digest.t + + module Decoded : sig + type t = private { bins : string list } + + val of_bins : string list -> t + end + + val encode : Decoded.t -> encoded + val decode : encoded -> Decoded.t +end = struct + type encoded = Digest.t + + module Decoded = struct + type t = { bins : string list } + + let equal x y = List.equal String.equal x.bins y.bins + let to_string { bins } = String.enumerate_and bins + + let of_bins bins = + let bins = List.sort_uniq bins ~compare:String.compare in + { bins } + ;; + end + + (* This mutable table is safe. [decode] is only called on digests produced + by [encode] in the same process (deps are evaluated before paths under + the layout dir are resolved), so the entry will always be present. An + unknown digest indicates an invariant violation. Same pattern as + [Ppx_driver.Key]. *) + let reverse_table : (Digest.t, Decoded.t) Table.t = Table.create (module Digest) 128 + + let encode ({ Decoded.bins } as x) = + let y = Digest.repr Repr.(list string) bins in + match Table.find reverse_table y with + | None -> + Table.set reverse_table y x; + y + | Some x' -> + if Decoded.equal x x' + then y + else + Code_error.raise + "Hash collision between sets of binaries" + [ "cached", Dyn.string (Decoded.to_string x') + ; "new", Dyn.string (Decoded.to_string x) + ] + ;; + + let decode y = + match Table.find reverse_table y with + | Some x -> x + | None -> + Code_error.raise + "unknown bin-layout digest (encode was not called first)" + [ "digest", Dyn.string (Digest.to_string y) ] + ;; +end + +let layout_dir ~context ~key = + Path.Build.relative (Install.Context.dir ~context) (".binaries/" ^ key) +;; + +let create context bins = + let decoded = Key.Decoded.of_bins bins in + let digest = Key.encode decoded in + let key = Digest.to_string digest in + let dir = layout_dir ~context ~key in + let { Key.Decoded.bins } = decoded in + let files = List.map bins ~f:(fun name -> Path.build (Path.Build.relative dir name)) in + Memo.return (dir, files) +;; + +let gen_rules context_name ~dir key = + match Digest.from_hex key with + | None -> User_error.raise [ Pp.textf "invalid bin-layout key %S" key ] + | Some digest -> + let { Key.Decoded.bins } = Key.decode digest in + let open Memo.O in + let* artifacts = + let* sctx = Super_context.find_exn context_name in + Artifacts_db.get (Super_context.context sctx) + in + Memo.parallel_iter bins ~f:(fun name -> + let* prog = Artifacts.binary artifacts ~where:Original_path ~dir ~loc:None name in + match prog with + | Error _ -> + Code_error.raise + "Bin_layout.gen_rules: binary not found" + [ "name", Dyn.string name; "context", Context_name.to_dyn context_name ] + | Ok src -> + let dst = Path.Build.relative dir name in + let { Action_builder.With_targets.build; targets } = + Action_builder.symlink ~src ~dst + in + Rules.Produce.rule (Rule.make ~targets build)) +;; diff --git a/src/dune_rules/bin_layout.mli b/src/dune_rules/bin_layout.mli new file mode 100644 index 00000000000..60abd3013c5 --- /dev/null +++ b/src/dune_rules/bin_layout.mli @@ -0,0 +1,12 @@ +open Import + +(** Create a bin-layout directory for the given binary names. Returns the + layout directory and the list of symlink paths for dependency tracking. + The symlinks are created as build rules keyed by a digest of the sorted + binary names. *) +val create : Context_name.t -> string list -> (Path.Build.t * Path.t list) Memo.t + +(** Generate symlink rules for the bin-layout directory identified by [key]. + Called from [gen_rules] when the build system visits + [_build/install//.bin-layout//]. *) +val gen_rules : Context_name.t -> dir:Path.Build.t -> string -> unit Memo.t diff --git a/src/dune_rules/cinaps.ml b/src/dune_rules/cinaps.ml index 1edb5b7dcf4..44ac554779c 100644 --- a/src/dune_rules/cinaps.ml +++ b/src/dune_rules/cinaps.ml @@ -247,7 +247,7 @@ let gen_rules sctx t ~dir ~scope = let cinaps_exe = Path.Build.relative cinaps_dir (name ^ ".exe") in Path.build cinaps_exe in - let runtime_deps, sandbox = + let action_env, sandbox = let sandbox = if t.cinaps_version >= (1, 1) then Sandbox_config.needs_sandboxing @@ -255,14 +255,14 @@ let gen_rules sctx t ~dir ~scope = in Dep_conf_eval.unnamed sandbox ~expander t.runtime_deps in - let* () = runtime_deps in let+ () = cinaps_exe :: List.rev_map cinapsed_files ~f:Path.build |> Dep.Set.of_files |> Action_builder.deps - in - Action.Full.make ~sandbox - @@ Action.chdir + and+ env = action_env in + Action.Full.make + ~sandbox + (Action.chdir (Path.build dir) (Action.progn [ Action.run (Ok cinaps_exe) [ "-diff-cmd"; "-" ] @@ -272,7 +272,8 @@ let gen_rules sctx t ~dir ~scope = ~optional:true (Path.build fn) (Path.Build.extend_basename fn ~suffix:".cinaps-corrected")) - ]) + ])) + |> Action.Full.add_env env in Super_context.add_alias_action sctx ~dir ~loc cinaps_alias action in diff --git a/src/dune_rules/compile_commands.ml b/src/dune_rules/compile_commands.ml index 6a79884bf7d..a73c9473798 100644 --- a/src/dune_rules/compile_commands.ml +++ b/src/dune_rules/compile_commands.ml @@ -67,7 +67,7 @@ let collect_from_foreign_sources ocaml.lib_config.ext_obj in Foreign.Sources.to_list_map foreign_sources ~f:(fun _ (_, src) -> - let include_flags = + let include_flags, _action_env = Foreign_rules.build_include_flags ~sctx ~dir ~expander ~dir_contents ~requires ~src in build_c_command ~sctx ~dir ~expander ~include_flags src ~ext_obj) diff --git a/src/dune_rules/cram/cram_rules.ml b/src/dune_rules/cram/cram_rules.ml index 7fc58aa5be9..b5f27bca58c 100644 --- a/src/dune_rules/cram/cram_rules.ml +++ b/src/dune_rules/cram/cram_rules.ml @@ -8,6 +8,7 @@ module Spec = struct ; extra_aliases : Alias.Name.Set.t ; deps : unit Action_builder.t list ; sandbox : Sandbox_config.t Action_builder.t + ; bin_env : Env.t Action_builder.t ; enabled_if : (Expander.t * Blang.t) list ; locks : Path.Set.t Action_builder.t ; packages : Package.Name.Set.t @@ -25,6 +26,7 @@ module Spec = struct ; locks = Action_builder.return Path.Set.empty ; deps = [] ; sandbox = Action_builder.return Sandbox_config.needs_sandboxing + ; bin_env = Action_builder.return Env.empty ; packages = Package.Name.Set.empty ; timeout = None ; conflict_markers = Ignore @@ -62,6 +64,7 @@ let test_rule ; deps ; locks ; sandbox + ; bin_env ; packages = _ ; timeout ; conflict_markers @@ -138,6 +141,7 @@ let test_rule () and+ () = Action_builder.paths setup_scripts and+ sandbox = sandbox + and+ bin_env = bin_env and+ locks = locks >>| Path.Set.to_list in Cram_exec.run ~src:(Path.build script) @@ -151,7 +155,8 @@ let test_rule ~timeout ~setup_scripts shell - |> Action.Full.make ~locks ~sandbox) + |> Action.Full.make ~locks ~sandbox + |> Action.Full.add_env bin_env) |> Action_builder.with_file_targets ~file_targets:[ output ] |> Super_context.add_rule sctx ~dir ~loc in @@ -256,23 +261,30 @@ let rules ~sctx ~dir tests project = | false -> Memo.return (runtest_alias, acc) | true -> let+ expander = Super_context.expander sctx ~dir in - let deps, sandbox = + let deps, sandbox, bin_env = match stanza.deps with - | None -> acc.deps, acc.sandbox + | None -> acc.deps, acc.sandbox, acc.bin_env | Some deps -> - let (deps : unit Action_builder.t), _, sandbox = + let action_env, _, sandbox = Dep_conf_eval.named ~expander Sandbox_config.no_special_requirements deps in + let action_env = Action_builder.memoize "cram action_env" action_env in let sandbox = let open Action_builder.O in let+ acc = acc.sandbox and+ sandbox = sandbox in Sandbox_config.inter acc sandbox in - deps :: acc.deps, sandbox + let bin_env = + let open Action_builder.O in + let+ acc = acc.bin_env + and+ env = action_env in + Env_path.extend_env_concat_path acc env + in + Action_builder.ignore action_env :: acc.deps, sandbox, bin_env in let locks = let open Action_builder.O in @@ -355,6 +367,7 @@ let rules ~sctx ~dir tests project = ; extra_aliases ; packages ; sandbox + ; bin_env ; timeout ; conflict_markers ; setup_scripts diff --git a/src/dune_rules/ctypes/ctypes_rules.ml b/src/dune_rules/ctypes/ctypes_rules.ml index d3aafbe0b3c..4cba61829c4 100644 --- a/src/dune_rules/ctypes/ctypes_rules.ml +++ b/src/dune_rules/ctypes/ctypes_rules.ml @@ -334,9 +334,18 @@ let gen_rules ~cctx ~(buildable : Buildable.t) ~loc ~scope ~dir ~sctx = let headers = gen_headers ~expander ctypes.headers |> Action_builder.memoize "ctypes-gen-headers" in - let deps, sandbox = + let action_env, sandbox = Dep_conf_eval.unnamed Sandbox_config.no_special_requirements ~expander ctypes.deps in + let action_env = Action_builder.memoize "ctypes action_env" action_env in + let deps = Action_builder.ignore action_env in + let with_action_env build = + Action_builder.With_targets.map_build build ~f:(fun build -> + let open Action_builder.O in + let+ action = build + and+ env = action_env in + Action.Full.add_env env action) + in let exe_link_only = exe_link_only ~deps ~dir ~shared_cctx:cctx ~sandbox in (* Type_gen produces a .c file, taking your type description module above as an input. The .c file is compiled into an .exe. The .exe, when run produces @@ -374,7 +383,7 @@ let gen_rules ~cctx ~(buildable : Buildable.t) ~loc ~scope ~dir ~sctx = ~loc:Loc.none (let exe = Ok (Path.build (Path.Build.relative dir (type_gen_script ^ ".exe"))) in let stdout_to = Path.Build.relative dir c_generated_types_cout_c in - Command.run ~stdout_to ~dir:(Path.build dir) exe []) + Command.run ~stdout_to ~dir:(Path.build dir) exe [] |> with_action_env) in let* () = let foreign_archives_deps = @@ -407,7 +416,7 @@ let gen_rules ~cctx ~(buildable : Buildable.t) ~loc ~scope ~dir ~sctx = |> Path.Build.relative dir in let exe = Ok (Path.build (Path.Build.relative dir c_generated_types_cout_exe)) in - Command.run ~stdout_to ~dir:(Path.build dir) exe []) + Command.run ~stdout_to ~dir:(Path.build dir) exe [] |> with_action_env) in (* Function_gen is similar to type_gen above, though it produces both an .ml file and a .c file. These files correspond to the files you would have to @@ -443,6 +452,7 @@ let gen_rules ~cctx ~(buildable : Buildable.t) ~loc ~scope ~dir ~sctx = in fun ~stdout_to ~what -> Command.run ~stdout_to ~dir:(Path.build dir) exe [ A what; A stubs_prefix ] + |> with_action_env in let* () = Super_context.add_rule diff --git a/src/dune_rules/dep_conf_eval.ml b/src/dune_rules/dep_conf_eval.ml index 3087182c66e..b69375836a9 100644 --- a/src/dune_rules/dep_conf_eval.ml +++ b/src/dune_rules/dep_conf_eval.ml @@ -34,6 +34,7 @@ let package_install ~(context : Build_context.t) ~(pkg : Package.t) = type dep_evaluation_result = | Simple of Path.t list Memo.t | Other of Path.t list Action_builder.t + | Include_result of (Path.t list * Env.t) Action_builder.t let to_action_builder = function | Simple paths -> @@ -41,6 +42,12 @@ let to_action_builder = function let+ () = Action_builder.all_unit (List.map ~f:Action_builder.path paths) in paths | Other x -> x + | Include_result pair -> Action_builder.map pair ~f:fst +;; + +let include_bin_env = function + | Simple _ | Other _ -> None + | Include_result pair -> Some (Action_builder.map pair ~f:snd) ;; let dep_on_alias_rec alias ~loc = @@ -105,6 +112,78 @@ let expand_include = let prepare_expander expander = Expander.set_expanding_what expander Deps_like_field +let bin_dep_name (dep : Dep_conf.t) = + match dep with + | File s -> + (match String_with_vars.pform_only s with + | Some (Macro ({ macro = Bin; _ } as m)) -> + Some (Pform.Macro_invocation.Args.whole m) + | _ -> None) + | _ -> None +;; + +(* The returned [Env.t] is a partial env containing only a PATH-prepend hint + for the bin-layout dir. Callers attach it via [Action.Full.add_env]; the + final env is assembled by [Super_context.extend_action], which calls + [Env_path.extend_env_concat_path] to splice the layout dir in front of + the external [PATH]. The [Env.t] should not be used as a standalone env. *) +let make_bin_env expander bin_names = + match bin_names with + | [] -> Action_builder.return Env.empty + | _ -> + let dir = Expander.dir expander in + let open Action_builder.O in + (* Use the host context for artifacts lookup and for the layout dir + path, matching %{bin:NAME} expansion (which uses [t.artifacts_host]) + and the install bin dir prepended to PATH by [Super_context]. Same + [Context.for_host] idiom as [super_context.ml:make_root_env]. + + CR-someday Alizter: factor this Context.for_host fallback shared + with super_context.ml into a single helper. *) + let* context = + Action_builder.of_memo + (let open Memo.O in + let* context = Context.DB.get (Expander.context expander) in + match Context.for_host context with + | None -> Memo.return (Context.name context) + | Some host -> + let+ host = host in + Context.name host) + in + let* origin_bin_names = + Action_builder.of_memo + (let open Memo.O in + let* artifacts = + let* sctx = Super_context.find_exn context in + Artifacts_db.get (Super_context.context sctx) + in + Memo.parallel_map bin_names ~f:(fun name -> + Artifacts.binary_package artifacts ~dir name + >>| function + | Some _ -> Some name + | None -> None) + >>| List.filter_opt) + in + (match origin_bin_names with + | [] -> Action_builder.return Env.empty + | _ -> + let* layout_dir, files = + Action_builder.of_memo (Bin_layout.create context origin_bin_names) + in + let+ () = Action_builder.paths files in + (* The layout dir is added to PATH as an absolute build-tree path. + dune's sandbox does not relocate PATH (it never has), so under + --sandbox copy/symlink the action's PATH entries still point at + the original _build/install//.bin-layout// outside + the sandbox. This is fine in practice because the bin-layout dir + itself is per-rule and acts as a kind of sandbox, but it would + break under remote action execution (where the action runs on a + different machine and cannot see absolute paths from the + driver). *) + Env.update Env.empty ~var:Env_path.var ~f:(fun _PATH -> + Some (Bin.cons_path (Path.build layout_dir) ~_PATH))) +;; + let add_sandbox_config acc (dep : Dep_conf.t) = match dep with | Sandbox_config cfg -> Sandbox_config.inter acc (make_sandboxing_config cfg) @@ -182,13 +261,15 @@ let rec dep expander : Dep_conf.t -> _ = function (* TODO this is wrong. we shouldn't allow bindings here if we are in an unnamed expansion *) let dir = Expander.dir expander in - Other - (let* deps = - let* project = Action_builder.of_memo @@ Dune_load.find_project ~dir in - expand_include ~dir ~project s - in - let builder, _bindings = named_paths_builder ~expander deps in - builder) + let pair = + let* project = Action_builder.of_memo @@ Dune_load.find_project ~dir in + let* deps = expand_include ~dir ~project s in + let builder, _bindings, bin_env = named_paths_builder ~expander deps in + let+ paths = builder + and+ env = bin_env in + paths, env + in + Include_result (Action_builder.memoize "include-eval" pair) | File s -> (match Expander.With_deps_if_necessary.expand_path expander s with | Without paths -> @@ -264,56 +345,102 @@ let rec dep expander : Dep_conf.t -> _ = function | Sandbox_config _ -> Other (Action_builder.return []) and named_paths_builder ~expander l = - let builders, bindings = + let builders, bindings, bin_names, include_envs = let expander = prepare_expander expander in - List.fold_left l ~init:([], Pform.Map.empty) ~f:(fun (builders, bindings) x -> - match x with - | Bindings.Unnamed x -> to_action_builder (dep expander x) :: builders, bindings - | Named (name, x) -> - let x = List.map x ~f:(dep expander) in - (match - Option.List.all - (List.map x ~f:(function - | Simple x -> Some x - | Other _ -> None)) - with - | Some x -> - let open Memo.O in - let x = Memo.lazy_ (fun () -> Memo.all_concurrently x >>| List.concat) in - let bindings = - Pform.Map.set - bindings - (Var (User_var name)) - (Expander.Deps.Without (Memo.Lazy.force x >>| Value.L.paths)) - in - let x = - let open Action_builder.O in - let* x = Action_builder.of_memo (Memo.Lazy.force x) in - let+ () = Action_builder.paths x in - x - in - x :: builders, bindings - | None -> - let x = - Action_builder.memoize - ~cutoff:(List.equal Path.equal) - ("dep " ^ name) - (Action_builder.List.concat_map x ~f:to_action_builder) - in - let bindings = - Pform.Map.set - bindings - (Var (User_var name)) - (Expander.Deps.With (x >>| Value.L.paths)) - in - x :: builders, bindings)) + let bin_names = + List.concat_map l ~f:(function + | Bindings.Unnamed dep -> Option.to_list (bin_dep_name dep) + | Bindings.Named (_, deps) -> List.filter_map deps ~f:bin_dep_name) + in + let builders, bindings, include_envs = + List.fold_left + l + ~init:([], Pform.Map.empty, []) + ~f:(fun (builders, bindings, envs) x -> + match x with + | Bindings.Unnamed x -> + let r = dep expander x in + let envs = + match include_bin_env r with + | Some e -> e :: envs + | None -> envs + in + to_action_builder r :: builders, bindings, envs + | Named (name, x) -> + let x = + List.map x ~f:(function + | Dep_conf.Package p -> + User_error.raise + ~loc:(String_with_vars.loc p) + ~hints: + [ Pp.text "Place the (package ...) entry in the deps list directly." + ] + [ Pp.textf + "(package ...) is not supported inside a named dependency \ + binding (:%s)." + name + ] + | d -> dep expander d) + in + let envs = + List.fold_left x ~init:envs ~f:(fun envs r -> + match include_bin_env r with + | Some e -> e :: envs + | None -> envs) + in + (match + Option.List.all + (List.map x ~f:(function + | Simple x -> Some x + | Other _ | Include_result _ -> None)) + with + | Some x -> + let open Memo.O in + let x = Memo.lazy_ (fun () -> Memo.all_concurrently x >>| List.concat) in + let bindings = + Pform.Map.set + bindings + (Var (User_var name)) + (Expander.Deps.Without (Memo.Lazy.force x >>| Value.L.paths)) + in + let x = + let open Action_builder.O in + let* x = Action_builder.of_memo (Memo.Lazy.force x) in + let+ () = Action_builder.paths x in + x + in + x :: builders, bindings, envs + | None -> + let x = + Action_builder.memoize + ~cutoff:(List.equal Path.equal) + ("dep " ^ name) + (Action_builder.List.concat_map x ~f:to_action_builder) + in + let bindings = + Pform.Map.set + bindings + (Var (User_var name)) + (Expander.Deps.With (x >>| Value.L.paths)) + in + x :: builders, bindings, envs)) + in + builders, bindings, bin_names, include_envs + in + let bin_env = + let outer = make_bin_env expander bin_names in + List.fold_left include_envs ~init:outer ~f:(fun acc env -> + let open Action_builder.O in + let+ acc = acc + and+ env = env in + Env_path.extend_env_concat_path acc env) in let builder = List.rev builders |> Action_builder.all >>| List.concat in - builder, bindings + builder, bindings, bin_env ;; let named sandbox ~expander l = - let builder, bindings = named_paths_builder ~expander l in + let builder, bindings, bin_env = named_paths_builder ~expander l in let builder = Action_builder.memoize ~cutoff:(List.equal Value.equal) @@ -343,16 +470,28 @@ let named sandbox ~expander l = sandbox_bindings sandbox l |> Action_builder.memoize ~cutoff:Sandbox_config.equal "deps sandbox" in - Action_builder.ignore builder, expander, sandbox + let action_env = + let+ _paths = builder + and+ env = bin_env in + env + in + action_env, expander, sandbox ;; let unnamed sandbox ~expander l = let expander = prepare_expander expander in - ( List.fold_left l ~init:(Action_builder.return ()) ~f:(fun acc x -> - let+ () = acc - and+ _x = to_action_builder (dep expander x) in - ()) - , List.fold_left l ~init:sandbox ~f:add_sandbox_config ) + let bin_names = List.filter_map l ~f:bin_dep_name in + let bin_env = make_bin_env expander bin_names in + let action_env = + let+ () = + List.fold_left l ~init:(Action_builder.return ()) ~f:(fun acc x -> + let+ () = acc + and+ _x = to_action_builder (dep expander x) in + ()) + and+ env = bin_env in + env + in + action_env, List.fold_left l ~init:sandbox ~f:add_sandbox_config ;; let unnamed_get_paths ~expander l = diff --git a/src/dune_rules/dep_conf_eval.mli b/src/dune_rules/dep_conf_eval.mli index dbf236ddc2c..87782c14cce 100644 --- a/src/dune_rules/dep_conf_eval.mli +++ b/src/dune_rules/dep_conf_eval.mli @@ -5,12 +5,17 @@ open Import (** Alias for all the files in [_build/install] that belong to this package *) val package_install : context:Build_context.t -> pkg:Package.t -> Alias.t -(** Evaluates unnamed dependency specifications. *) +(** Evaluates unnamed dependency specifications. The returned builder both + registers the rule's dependencies (as a side effect of evaluation) and + produces an [Env.t] augmentation that callers should fold into the action + via [Action.Full.add_env]. For build-tracking-only call sites (no action + constructed), evaluate the builder and discard the env via + [Action_builder.ignore]. *) val unnamed : Sandbox_config.t -> expander:Expander.t -> Dep_conf.t list - -> unit Action_builder.t * Sandbox_config.t + -> Env.t Action_builder.t * Sandbox_config.t (** Evaluates unnamed dependency specifications. Returns the paths to the newly evaluated dependencies. *) @@ -19,11 +24,12 @@ val unnamed_get_paths -> Dep_conf.t list -> Path.Set.t Action_builder.t * Sandbox_config.t option -(** Evaluates named dependency specifications. Return the action build that - register dependencies as well as an expander that can be used to expand to - expand variables from the bindings. *) +(** Evaluates named dependency specifications. The returned builder both + registers the rule's dependencies and produces an [Env.t] augmentation, + same convention as [unnamed]. The expander has the named bindings added + so [%{name}] references resolve. *) val named : Sandbox_config.t -> expander:Expander.t -> Dep_conf.t Bindings.t - -> unit Action_builder.t * Expander.t * Sandbox_config.t Action_builder.t + -> Env.t Action_builder.t * Expander.t * Sandbox_config.t Action_builder.t diff --git a/src/dune_rules/exe.ml b/src/dune_rules/exe.ml index 07567687cf9..2303a1b9078 100644 --- a/src/dune_rules/exe.ml +++ b/src/dune_rules/exe.ml @@ -171,6 +171,7 @@ let link_exe ~link_args ~o_files ?(sandbox = Sandbox_config.default) + ?(action_env = Action_builder.return Env.empty) cctx = let sctx = Compilation_context.super_context cctx in @@ -235,7 +236,11 @@ let link_exe ; fdo_linker_script_flags ; Dyn link_args ] - >>| Action.Full.add_sandbox sandbox + |> Action_builder.With_targets.map_build ~f:(fun build -> + let open Action_builder.O in + let+ action = build + and+ env = action_env in + Action.Full.add_sandbox sandbox action |> Action.Full.add_env env) and* mode = let sctx = Compilation_context.super_context cctx in let* expander = Super_context.expander sctx ~dir in @@ -296,6 +301,7 @@ let link_many ?o_files ?(embed_in_plugin_libraries = []) ?sandbox + ?action_env ~programs ~linkages ~promote @@ -417,7 +423,8 @@ let link_many ~promote ~link_args ~o_files - ?sandbox) + ?sandbox + ?action_env) in top_sorted_modules) in @@ -429,6 +436,7 @@ let build_and_link_many ?o_files ?embed_in_plugin_libraries ?sandbox + ?action_env ~programs ~linkages ~promote @@ -444,6 +452,7 @@ let build_and_link_many ?o_files ?embed_in_plugin_libraries ?sandbox + ?action_env ~programs ~linkages ~promote @@ -455,6 +464,7 @@ let build_and_link ?o_files ?embed_in_plugin_libraries ?sandbox + ?action_env ~program ~linkages ~promote @@ -465,6 +475,7 @@ let build_and_link ?o_files ?embed_in_plugin_libraries ?sandbox + ?action_env ~programs:[ program ] ~linkages ~promote diff --git a/src/dune_rules/exe.mli b/src/dune_rules/exe.mli index daa2d9ccf08..569e2b415e2 100644 --- a/src/dune_rules/exe.mli +++ b/src/dune_rules/exe.mli @@ -61,6 +61,7 @@ val link_many -> ?o_files:Path.t Mode.Map.Multi.t -> ?embed_in_plugin_libraries:(Loc.t * Lib_name.t) list -> ?sandbox:Sandbox_config.t + -> ?action_env:Env.t Action_builder.t -> programs:Program.t list -> linkages:Linkage.t list -> promote:Rule_mode.Promote.t option @@ -72,6 +73,7 @@ val build_and_link -> ?o_files:Path.t Mode.Map.Multi.t -> ?embed_in_plugin_libraries:(Loc.t * Lib_name.t) list -> ?sandbox:Sandbox_config.t + -> ?action_env:Env.t Action_builder.t -> program:Program.t -> linkages:Linkage.t list -> promote:Rule_mode.Promote.t option @@ -83,6 +85,7 @@ val build_and_link_many -> ?o_files:Path.t Mode.Map.Multi.t -> ?embed_in_plugin_libraries:(Loc.t * Lib_name.t) list -> ?sandbox:Sandbox_config.t + -> ?action_env:Env.t Action_builder.t -> programs:Program.t list -> linkages:Linkage.t list -> promote:Rule_mode.Promote.t option diff --git a/src/dune_rules/exe_rules.ml b/src/dune_rules/exe_rules.ml index e032e212171..ea9a354192d 100644 --- a/src/dune_rules/exe_rules.ml +++ b/src/dune_rules/exe_rules.ml @@ -242,17 +242,18 @@ let executables_rules let* dep_graphs = (* Building an archive for foreign stubs, we link the corresponding object files directly to improve perf. *) - let link_deps, sandbox = + let action_env, sandbox = Dep_conf_eval.unnamed Sandbox_config.no_special_requirements ~expander exes.link_deps in + let action_env = Action_builder.memoize "exe link action_env" action_env in let link_args : Command.Args.without_targets Command.Args.t Action_builder.t = Command.Args.S [ Dyn (let open Action_builder.O in - let* () = link_deps in + let* _env = action_env in let use_standard_cxx_flags = match Dune_project.use_standard_c_and_cxx_flags project with | Some true -> Buildable.has_foreign_cxx exes.buildable @@ -304,6 +305,7 @@ let executables_rules ~promote:exes.promote ~embed_in_plugin_libraries ~sandbox + ~action_env | Some _ -> (* Ctypes stubgen builds utility .exe files that need to share modules with this compilation context. To support that, we extract the one-time @@ -324,6 +326,7 @@ let executables_rules ~embed_in_plugin_libraries cctx ~sandbox + ~action_env in link in diff --git a/src/dune_rules/expander.ml b/src/dune_rules/expander.ml index 31d7df3dae3..4c327b4f1c2 100644 --- a/src/dune_rules/expander.ml +++ b/src/dune_rules/expander.ml @@ -58,6 +58,7 @@ type t = ; scope : Scope.t Memo.t ; scope_host : Scope.t Memo.t ; context : Context.t + ; context_host : Context.t Memo.t ; expanding_what : Expanding_what.t ; project : Dune_project.t } @@ -66,6 +67,7 @@ let artifacts t = t.artifacts_host let dir t = t.dir let project t = t.project let context t = Context.name t.context +let host_context t = t.context_host let set_local_env_var t ~var ~value = { t with local_env = Env.Var.Map.set t.local_env var value } @@ -938,6 +940,7 @@ let make_root ~scope ~scope_host ~(context : Context.t) + ~context_host ~env ~public_libs ~public_libs_host @@ -953,6 +956,7 @@ let make_root ; public_libs_host ; artifacts_host ; context + ; context_host ; expanding_what = Nothing_special ; project } diff --git a/src/dune_rules/expander.mli b/src/dune_rules/expander.mli index 70edaf9fc1d..fc40f3f693a 100644 --- a/src/dune_rules/expander.mli +++ b/src/dune_rules/expander.mli @@ -13,12 +13,19 @@ val make_root -> scope:Scope.t Memo.t -> scope_host:Scope.t Memo.t -> context:Context.t + -> context_host:Context.t Memo.t -> env:Env.t Memo.t -> public_libs:Lib.DB.t Memo.t -> public_libs_host:Lib.DB.t Memo.t -> artifacts_host:Artifacts.t Memo.t -> t +(** The host context this expander resolves to (the current context if there + is no cross-compilation). Used for resolving [%{bin:...}] artifacts and + package layouts, which must live in the context that produced the + binaries the action will execute. *) +val host_context : t -> Context.t Memo.t + val set_local_env_var : t -> var:string -> value:string Action_builder.t -> t val set_scope diff --git a/src/dune_rules/foreign_rules.ml b/src/dune_rules/foreign_rules.ml index c5de56ef6a3..011f69e2d96 100644 --- a/src/dune_rules/foreign_rules.ml +++ b/src/dune_rules/foreign_rules.ml @@ -272,7 +272,14 @@ let c_compile_args ~sctx ~dir ~expander ~src ~include_flags = ] ;; -let build_c ~sctx ~dir ~expander ~include_flags (loc, (src : Foreign.Source.t), dst) = +let build_c + ~sctx + ~dir + ~expander + ~include_flags + ~action_env + (loc, (src : Foreign.Source.t), dst) + = let ctx = Super_context.context sctx in let* ocaml = Context.ocaml ctx in (* Emit warning for Stubs case when standard flags are overridden *) @@ -321,8 +328,7 @@ let build_c ~sctx ~dir ~expander ~include_flags (loc, (src : Foreign.Source.t), sctx ~loc ~dir - (let open Action_builder.With_targets.O in - let src_path = Path.build (Foreign.Source.path src) in + (let src_path = Path.build (Foreign.Source.path src) in (* We have to execute the rule in the library directory as the .o is produced in the current directory *) let c_compiler = @@ -347,7 +353,12 @@ let build_c ~sctx ~dir ~expander ~include_flags (loc, (src : Foreign.Source.t), (* With sandboxing we get errors like: bar.c:2:19: fatal error: foo.cxx: No such file or directory #include "foo.cxx". (These errors happen only when compiling c files.) *) - >>| Action.Full.add_sandbox Sandbox_config.no_sandboxing) + |> Action_builder.With_targets.map_build ~f:(fun build -> + let open Action_builder.O in + let+ action = build + and+ env = action_env in + Action.Full.add_sandbox Sandbox_config.no_sandboxing action + |> Action.Full.add_env env)) ;; (* TODO: [requires] is a confusing name, probably because it's too general: it @@ -377,25 +388,30 @@ let build_include_flags ~sctx ~dir ~expander ~dir_contents ~requires ~src = ]) ] in - let extra_deps = - let extra_deps, sandbox = + let extra_deps, action_env = + let action_env, sandbox = match Foreign.Source.kind src with | Stubs stubs -> Dep_conf_eval.unnamed Sandbox_config.no_special_requirements stubs.extra_deps ~expander - | Ctypes _ -> Action_builder.return (), Sandbox_config.default + | Ctypes _ -> Action_builder.return Env.empty, Sandbox_config.default in (* We don't sandbox the C compiler, see comment in [build_c] about this. *) ignore sandbox; - Action_builder.map extra_deps ~f:(fun () -> Command.Args.empty) + let action_env = Action_builder.memoize "foreign action_env" action_env in + let extra_deps = + Action_builder.map (Action_builder.ignore action_env) ~f:(fun () -> + Command.Args.empty) + in + extra_deps, action_env in let extra_flags = include_dir_flags ~expander ~dir ~include_dirs:(Foreign.Source.include_dirs src) in - Command.Args.S [ includes; extra_flags; Dyn extra_deps ] + Command.Args.S [ includes; extra_flags; Dyn extra_deps ], action_env ;; let build_o_files @@ -417,11 +433,13 @@ let build_o_files foreign_sources ~f:(fun obj (loc, (src : Foreign.Source.t)) -> let+ build_file = - let include_flags = + let include_flags, action_env = build_include_flags ~sctx ~dir ~expander ~dir_contents ~requires ~src in let dst = Path.Build.relative dir (obj ^ Filename.Extension.to_string ext_obj) in - let+ () = build_c ~sctx ~dir ~expander ~include_flags (loc, src, dst) in + let+ () = + build_c ~sctx ~dir ~expander ~include_flags ~action_env (loc, src, dst) + in dst in Foreign.Source.mode src, Path.build build_file) diff --git a/src/dune_rules/foreign_rules.mli b/src/dune_rules/foreign_rules.mli index e08ea19540b..b63cb62fcde 100644 --- a/src/dune_rules/foreign_rules.mli +++ b/src/dune_rules/foreign_rules.mli @@ -23,7 +23,9 @@ val foreign_flags_env (** Build the common include flags for C compilation: header hidden deps, library include flags, per-source include_dir_flags, and extra_deps. - Shared between [build_o_files] and [Compile_commands]. *) + Shared between [build_o_files] and [Compile_commands]. Also returns the + action env derived from any [%{bin:...}] pforms in the source's + [extra_deps], so callers can fold it into the resulting action. *) val build_include_flags : sctx:Super_context.t -> dir:Path.Build.t @@ -31,7 +33,7 @@ val build_include_flags -> dir_contents:Dir_contents.t -> requires:Lib.t list Resolve.t -> src:Foreign.Source.t - -> Command.Args.without_targets Command.Args.t + -> Command.Args.without_targets Command.Args.t * Env.t Action_builder.t (** Construct Command.Args.t for C compilation (flags + stdlib include + include_flags). Does not include output (-o) or source (-c) arguments. *) diff --git a/src/dune_rules/gen_rules.ml b/src/dune_rules/gen_rules.ml index 5835336cf96..8071c8c4ed0 100644 --- a/src/dune_rules/gen_rules.ml +++ b/src/dune_rules/gen_rules.ml @@ -803,15 +803,33 @@ let gen_rules ctx ~dir components = Gen_rules.Build_only_sub_dirs.singleton ~dir context_dirs in Gen_rules.make ~build_dir_only_sub_dirs (Memo.return Rules.empty) - | ctx :: _ -> + | ctx :: rest -> let ctx = Context_name.of_string ctx in - with_context ctx ~f:(fun sctx -> - let+ subdirs, rules = Install_rules.symlink_rules sctx ~dir in - let directory_targets = Rules.directory_targets rules in - Gen_rules.make - ~build_dir_only_sub_dirs:(Gen_rules.Build_only_sub_dirs.singleton ~dir subdirs) - ~directory_targets - (Memo.return rules))) + (match rest with + | ".binaries" :: layout_rest -> + has_rules + ~dir + (match layout_rest with + | [] -> Subdir_set.all + | _ -> Subdir_set.empty) + (fun () -> + match layout_rest with + | [ key ] -> Bin_layout.gen_rules ctx ~dir key + | _ -> Memo.return ()) + | _ -> + with_context ctx ~f:(fun sctx -> + let+ subdirs, rules = Install_rules.symlink_rules sctx ~dir in + let subdirs = + if List.is_empty rest + then Subdir_set.union subdirs (Subdir_set.of_list [ ".binaries" ]) + else subdirs + in + let directory_targets = Rules.directory_targets rules in + Gen_rules.make + ~build_dir_only_sub_dirs: + (Gen_rules.Build_only_sub_dirs.singleton ~dir subdirs) + ~directory_targets + (Memo.return rules)))) else if Context_name.equal ctx Private_context.t.name then private_context ~dir components ctx else if Context_name.equal ctx Fetch_rules.context.name diff --git a/src/dune_rules/inline_tests.ml b/src/dune_rules/inline_tests.ml index c01e8b02949..c52caee539d 100644 --- a/src/dune_rules/inline_tests.ml +++ b/src/dune_rules/inline_tests.ml @@ -380,7 +380,7 @@ include Sub_system.Register_end_point (struct in let lib_name = snd lib.name in let partitions_flags = partition_flags ~expander ~lib_name ~backends in - let deps, sandbox = + let action_env, sandbox = let sandbox = if dune_version < (3, 5) then Sandbox_config.no_special_requirements @@ -388,6 +388,8 @@ include Sub_system.Register_end_point (struct in Dep_conf_eval.unnamed sandbox info.deps ~expander in + let action_env = Action_builder.memoize "inline-tests action_env" action_env in + let deps = Action_builder.ignore action_env in let action = action sctx ~deps ~loc ~dir ~inline_test_dir ~runner_name in Memo.parallel_iter modes ~f:(fun (mode : Mode_conf.t) -> let partition_file = @@ -445,7 +447,8 @@ include Sub_system.Register_end_point (struct |> action mode) >>= Action_builder.all and+ () = Action_builder.paths runner_inputs - and+ () = Action_builder.paths promotion_targets in + and+ () = Action_builder.paths promotion_targets + and+ env = action_env in match actions with | [] -> Action.Full.empty | _ :: _ -> @@ -457,7 +460,8 @@ include Sub_system.Register_end_point (struct |> Action.diff ~optional:true fn) |> Action.concurrent in - Action.Full.make ~sandbox @@ Action.progn [ run_tests; diffs ])) + Action.Full.make ~sandbox (Action.progn [ run_tests; diffs ]) + |> Action.Full.add_env env)) ;; let gen_rules diff --git a/src/dune_rules/lib_flags.ml b/src/dune_rules/lib_flags.ml index bd07736aae9..a5f0107910a 100644 --- a/src/dune_rules/lib_flags.ml +++ b/src/dune_rules/lib_flags.ml @@ -254,14 +254,14 @@ module L = struct let dir = Path.as_in_build_dir_exn @@ Lib_info.src_dir info in let headers = let+ expander = Super_context.expander sctx ~dir in - let deps, sandbox = + let action_env, sandbox = Dep_conf_eval.unnamed Sandbox_config.no_special_requirements ~expander public_headers in assert (Sandbox_config.equal sandbox Sandbox_config.no_special_requirements); - deps + Action_builder.ignore action_env in headers :: local, external_) in diff --git a/src/dune_rules/mdx.ml b/src/dune_rules/mdx.ml index a13c16933e7..df2bc31576f 100644 --- a/src/dune_rules/mdx.ml +++ b/src/dune_rules/mdx.ml @@ -372,7 +372,7 @@ let gen_rules_for_single_file stanza ~sctx ~dir ~expander ~mdx_prog ~mdx_prog_ge ; Dep (Path.build files.src) ] ) in - let deps, sandbox = + let action_env, sandbox = let mdx_generic_deps = Bindings.to_list stanza.deps in let mdx_package_deps = stanza.packages @@ -387,9 +387,8 @@ let gen_rules_for_single_file stanza ~sctx ~dir ~expander ~mdx_prog ~mdx_prog_ge (mdx_package_deps @ mdx_generic_deps) in let+ action = - Action_builder.with_no_targets deps - >>> Action_builder.with_no_targets - (Action_builder.env_var "MDX_RUN_NON_DETERMINISTIC") + Action_builder.with_no_targets + (Action_builder.env_var "MDX_RUN_NON_DETERMINISTIC") >>> Action_builder.with_no_targets (Action_builder.map mdx_input_dependencies ~f:(fun d -> (), d) |> Action_builder.dyn_deps) @@ -400,8 +399,10 @@ let gen_rules_for_single_file stanza ~sctx ~dir ~expander ~mdx_prog ~mdx_prog_ge command_line and+ locks = Expander.expand_locks expander stanza.locks |> Action_builder.with_no_targets - in - Action.Full.add_locks locks action |> Action.Full.add_sandbox sandbox + and+ env = Action_builder.with_no_targets action_env in + Action.Full.add_locks locks action + |> Action.Full.add_sandbox sandbox + |> Action.Full.add_env env in Super_context.add_rule sctx ~loc ~dir mdx_action in diff --git a/src/dune_rules/pp_spec_rules.ml b/src/dune_rules/pp_spec_rules.ml index 04eb9864105..6811a8c7d2d 100644 --- a/src/dune_rules/pp_spec_rules.ml +++ b/src/dune_rules/pp_spec_rules.ml @@ -224,6 +224,7 @@ let pp_one_module ~lib_name ~scope ~preprocessor_deps + ~action_env ~(lint_module : source:_ -> ast:_ -> unit Memo.t) ~sandbox ~dir @@ -251,6 +252,11 @@ let pp_one_module pped_module m ~f:(fun _kind src dst -> let action = action_for_pp_with_target ~sandbox ~loc ~expander ~action ~src ~target:dst + |> Action_builder.With_targets.map_build ~f:(fun build -> + let open Action_builder.O in + let+ action = build + and+ env = action_env in + Action.Full.add_env env action) in Super_context.add_rule sctx @@ -360,23 +366,25 @@ let pp_one_module let dir = Super_context.context sctx |> Context.build_dir |> Path.build in - Command.run' - ~dir - (Ok (Path.build exe)) - [ As args - ; A "-o" - ; Path (Path.build dst) - ; Command.Ml_kind.ppx_driver_flag ml_kind - ; Dep (Path.build src) - ; Hidden_deps - (Module.source m ~ml_kind - |> Option.value_exn - |> Module.File.path - |> Dep.file - |> Dep.Set.singleton) - ; As flags - ] - >>| Action.Full.add_sandbox sandbox))))) + let+ action = + Command.run' + ~dir + (Ok (Path.build exe)) + [ As args + ; A "-o" + ; Path (Path.build dst) + ; Command.Ml_kind.ppx_driver_flag ml_kind + ; Dep (Path.build src) + ; Hidden_deps + (Module.source m ~ml_kind + |> Option.value_exn + |> Module.File.path + |> Dep.file + |> Dep.Set.singleton) + ; As flags + ] + and+ env = action_env in + Action.Full.add_sandbox sandbox action |> Action.Full.add_env env))))) ;; let make @@ -396,12 +404,14 @@ let make Module_name.Per_item.map preprocess ~f:(fun pp -> Preprocess.remove_future_syntax ~for_:Compiler pp ocaml.version) in - let preprocessor_deps, sandbox = + let action_env, sandbox = Dep_conf_eval.unnamed Sandbox_config.no_special_requirements preprocessor_deps ~expander in + let action_env = Action_builder.memoize "preprocessor action_env" action_env in + let preprocessor_deps = Action_builder.ignore action_env in let sandbox = match Sandbox_config.equal Sandbox_config.no_special_requirements sandbox with | false -> `Set_by_user sandbox @@ -423,6 +433,7 @@ let make ~lib_name ~scope ~preprocessor_deps + ~action_env ~lint_module ~sandbox ~dir diff --git a/src/dune_rules/simple_rules.ml b/src/dune_rules/simple_rules.ml index 70b8d49b51d..85e506bb62e 100644 --- a/src/dune_rules/simple_rules.ml +++ b/src/dune_rules/simple_rules.ml @@ -345,13 +345,13 @@ let alias sctx ~dir ~expander (alias_conf : Alias_conf.t) = (match alias_conf.action with | None -> (* Sandboxing options don't make sense for deps, only for actions *) - let builder, _expander, _sandbox = + let action_env, _expander, _sandbox = Dep_conf_eval.named ~expander Sandbox_config.no_special_requirements alias_conf.deps in - Rules.Produce.Alias.add_deps alias ~loc builder + Rules.Produce.Alias.add_deps alias ~loc (Action_builder.ignore action_env) | Some (action_loc, action) -> let action = let chdir = Expander.dir expander in diff --git a/src/dune_rules/super_context.ml b/src/dune_rules/super_context.ml index 08ad63d3ae1..deeec4aaff7 100644 --- a/src/dune_rules/super_context.ml +++ b/src/dune_rules/super_context.ml @@ -150,6 +150,10 @@ let extend_action t ~dir action = (let open Memo.O in t.get_node dir >>= Env_node.external_env) in + (* [action.env] is expected to contain only PATH-prepend hints from + [Dep_conf_eval.make_bin_env]. Splice its PATH entries in front of the + external env's PATH, keep other vars as-is. *) + let env = Env_path.extend_env_concat_path env action.env in Action.Full.add_env env action |> Action.Full.map ~f:(function | Chdir _ as a -> a @@ -270,6 +274,8 @@ let create ~(context : Context.t) ~(host : t option) ~packages ~stanzas = let artifacts = Artifacts_db.get context in let+ root_expander = let public_libs = Scope.DB.public_libs context_name in + (* CR-someday Alizter: factor this Context.for_host fallback shared + with dep_conf_eval.ml:make_bin_env into a single helper. *) let artifacts_host, public_libs_host, context_host = match Context.for_host context with | None -> artifacts, public_libs, Memo.return context @@ -286,6 +292,7 @@ let create ~(context : Context.t) ~(host : t option) ~packages ~stanzas = ~scope ~scope_host ~context + ~context_host ~env ~public_libs ~artifacts_host diff --git a/test/blackbox-tests/test-cases/bin-pform/cli-build.t b/test/blackbox-tests/test-cases/bin-pform/cli-build.t index 1903c3a6c36..9452178349d 100644 --- a/test/blackbox-tests/test-cases/bin-pform/cli-build.t +++ b/test/blackbox-tests/test-cases/bin-pform/cli-build.t @@ -13,13 +13,6 @@ Build a binary using a %{bin:..} form. > (public_name bar)) > EOF -BUG: %{bin:bar} expands using _build/default as its base, producing -"../install/default/bin/bar" rather than a path to a buildable -target. See #3324. - -CR-soon Alizter: fix the expansion to point at the build artifact. - $ dune build '%{bin:bar}' - Error: File unavailable: - $TESTCASE_ROOT/../install/default/bin/bar - [1] + $ ls _build/default/bin/bar.exe + _build/default/bin/bar.exe diff --git a/test/blackbox-tests/test-cases/bin-pform/include-deps.t b/test/blackbox-tests/test-cases/bin-pform/include-deps.t index f34d2eab8aa..07eca035a1d 100644 --- a/test/blackbox-tests/test-cases/bin-pform/include-deps.t +++ b/test/blackbox-tests/test-cases/bin-pform/include-deps.t @@ -1,6 +1,6 @@ -%{bin:NAME} inside (include ...) deps is processed: the binary -becomes a tracked dep of the rule and the install bin dir is added -to the action's PATH. +%{bin:...} inside (include ...) deps is processed: the binary's +bin-layout dir gets added to the action's PATH and the binary is a +tracked dep of the rule. $ cat >dune-project < (lang dune 3.24) @@ -27,14 +27,17 @@ to the action's PATH. $ dune build path-output -The action's PATH includes the install bin dir: +The action's PATH includes the bin-layout dir and the install bin +dir: - $ env_added "$(cat _build/default/path-output)" "$PATH" - $TESTCASE_ROOT/_build/install/default/bin + $ env_added "$(cat _build/default/path-output)" "$PATH" | censor + $PWD/_build/install/default/.binaries/$DIGEST + $PWD/_build/install/default/bin -The rule depends on the staging binary: +The rule depends on the build artifact and the bin-layout symlink: $ dune rules --format=json _build/default/path-output \ > | jq 'include "dune"; .[] | ruleDepFilePaths' \ - > | grep mybin - "_build/install/default/bin/mybin" + > | grep mybin | censor + "_build/default/src/mybin.exe" + "_build/install/default/.binaries/$DIGEST/mybin" diff --git a/test/blackbox-tests/test-cases/bin-pform/inline-tests.t b/test/blackbox-tests/test-cases/bin-pform/inline-tests.t index d1160d6ce64..fc72716abd9 100644 --- a/test/blackbox-tests/test-cases/bin-pform/inline-tests.t +++ b/test/blackbox-tests/test-cases/bin-pform/inline-tests.t @@ -40,5 +40,6 @@ sandbox: > EOF $ dune runtest 2>&1 - $ env_added "$(cat path.out)" "$PATH" - $TESTCASE_ROOT/_build/install/default/bin + $ env_added "$(cat path.out)" "$PATH" | censor + $PWD/_build/install/default/.binaries/$DIGEST + $PWD/_build/install/default/bin diff --git a/test/blackbox-tests/test-cases/bin-pform/install-stanza.t b/test/blackbox-tests/test-cases/bin-pform/install-stanza.t new file mode 100644 index 00000000000..e32dd1c1659 --- /dev/null +++ b/test/blackbox-tests/test-cases/bin-pform/install-stanza.t @@ -0,0 +1,37 @@ +%{bin:NAME} for a binary installed via an (install) stanza, where +the install name differs from the source name. + + $ cat >dune-project < (lang dune 3.24) + > (package (name mypkg)) + > EOF + + $ cat >script.sh <<'EOF' + > #!/bin/sh + > echo "hello from script" + > EOF + $ chmod +x script.sh + + $ cat >dune <<'EOF' + > (install + > (package mypkg) + > (section bin) + > (files (script.sh as renamed))) + > (rule + > (deps %{bin:renamed}) + > (action + > (with-stdout-to out (bash "renamed")))) + > EOF + +The action invokes the install-renamed binary via PATH: + + $ dune build out + $ cat _build/default/out + hello from script + +The bin-layout symlink uses the install name: + + $ dune rules --format=json _build/default/out \ + > | jq 'include "dune"; .[] | ruleDepFilePaths' | censor + "_build/default/script.sh" + "_build/install/default/.binaries/$DIGEST/renamed" diff --git a/test/blackbox-tests/test-cases/bin-pform/multiple-bins.t b/test/blackbox-tests/test-cases/bin-pform/multiple-bins.t index 41d8b05e614..d3cffa49a6c 100644 --- a/test/blackbox-tests/test-cases/bin-pform/multiple-bins.t +++ b/test/blackbox-tests/test-cases/bin-pform/multiple-bins.t @@ -24,18 +24,24 @@ Multiple %{bin:...} deps in a single rule. > (bash "echo $PATH")))) > EOF -Both binaries live in the same install bin dir, which is on PATH: +PATH gets a bin-layout dir (with symlinks to both bins) plus the +install bin dir: $ dune build path-output - $ env_added "$(cat _build/default/path-output)" "$PATH" - $TESTCASE_ROOT/_build/install/default/bin + $ env_added "$(cat _build/default/path-output)" "$PATH" | censor + $PWD/_build/install/default/.binaries/$DIGEST + $PWD/_build/install/default/bin -The rule depends on both staging binaries: +The rule depends on each binary via two paths: the build artifact +(from the pform expansion) and the bin-layout symlink (from the PATH +machinery): $ dune rules --format=json _build/default/path-output \ - > | jq 'include "dune"; .[] | ruleDepFilePaths' - "_build/install/default/bin/bar" - "_build/install/default/bin/foo" + > | jq 'include "dune"; .[] | ruleDepFilePaths' | censor + "_build/default/src/bar.exe" + "_build/default/src/foo.exe" + "_build/install/default/.binaries/$DIGEST/bar" + "_build/install/default/.binaries/$DIGEST/foo" Both binaries are callable by name: diff --git a/test/blackbox-tests/test-cases/bin-pform/public-name.t b/test/blackbox-tests/test-cases/bin-pform/public-name.t index a955c25dcd9..2e0ffcca69a 100644 --- a/test/blackbox-tests/test-cases/bin-pform/public-name.t +++ b/test/blackbox-tests/test-cases/bin-pform/public-name.t @@ -14,15 +14,15 @@ > let () = print_endline "hello" > EOF -The pform resolves to the staging path: +The pform resolves to the build artifact: $ dune build bin-path $ cat _build/default/bin-path - ../install/default/bin/mybin + mybin.exe -The rule depends on the staging binary: +The rule depends on the build artifact: $ dune rules --format=json _build/default/bin-path \ > | jq 'include "dune"; .[] | ruleDepFilePaths' \ > | grep mybin - "_build/install/default/bin/mybin" + "_build/default/mybin.exe" diff --git a/test/blackbox-tests/test-cases/bin-pform/run-action.t b/test/blackbox-tests/test-cases/bin-pform/run-action.t index 15429d0c283..c4ec5d83898 100644 --- a/test/blackbox-tests/test-cases/bin-pform/run-action.t +++ b/test/blackbox-tests/test-cases/bin-pform/run-action.t @@ -1,6 +1,6 @@ %{bin:NAME} as a (run ...) target invokes the binary; as a deps -entry it tracks the staging binary. The install bin dir is on the -action's PATH (always-on for actions, not added by the dep). +entry it adds a bin-layout dir to the action's PATH (plus the +always-on install bin dir). $ cat >dune-project < (lang dune 3.24) @@ -22,13 +22,15 @@ action's PATH (always-on for actions, not added by the dep). $ dune build path-output hello from mybin - $ env_added "$(cat _build/default/path-output)" "$PATH" - $TESTCASE_ROOT/_build/install/default/bin + $ env_added "$(cat _build/default/path-output)" "$PATH" | censor + $PWD/_build/install/default/.binaries/$DIGEST + $PWD/_build/install/default/bin -Both pform usages dedupe to a single dep on the install staging -path: +The rule's deps include the build artifact and the bin-layout +symlink: $ dune rules --format=json _build/default/path-output \ > | jq 'include "dune"; .[] | ruleDepFilePaths' \ - > | grep mybin - "_build/install/default/bin/mybin" + > | grep mybin | censor + "_build/default/mybin.exe" + "_build/install/default/.binaries/$DIGEST/mybin" diff --git a/test/blackbox-tests/test-cases/bin-pform/run-literal-vs-pform.t b/test/blackbox-tests/test-cases/bin-pform/run-literal-vs-pform.t index 93fae2f06be..f5b30b6c73f 100644 --- a/test/blackbox-tests/test-cases/bin-pform/run-literal-vs-pform.t +++ b/test/blackbox-tests/test-cases/bin-pform/run-literal-vs-pform.t @@ -1,8 +1,7 @@ -(run NAME) with a bare literal name and (run %{bin:NAME}) record -different deps. The bare-literal form resolves with where=Original_path -(for lang >= 3.14) and records a dep on the build artifact; the pform -form uses the default where=Install_dir and records a dep on the -install staging path. +(run NAME) with a bare literal name and (run %{bin:NAME}) both record +a dep on the build artifact. Before wrv only the bare-literal form +did, since the pform default was where=Install_dir; wrv flips the +pform default to Original_path so both paths agree. $ cat >dune-project < (lang dune 3.24) @@ -31,9 +30,9 @@ install staging path. > | grep mybin "_build/default/src/mybin.exe" -(run %{bin:mybin}) records a dep on the install staging path: +(run %{bin:mybin}) records a dep on the build artifact too: $ dune rules --format=json _build/default/out-pform \ > | jq 'include "dune"; .[] | ruleDepFilePaths' \ > | grep mybin - "_build/install/default/bin/mybin" + "_build/default/src/mybin.exe" diff --git a/test/blackbox-tests/test-cases/bin-pform/sandbox.t b/test/blackbox-tests/test-cases/bin-pform/sandbox.t new file mode 100644 index 00000000000..346d0c6d2c3 --- /dev/null +++ b/test/blackbox-tests/test-cases/bin-pform/sandbox.t @@ -0,0 +1,45 @@ +%{bin:NAME} deps under sandboxing. + +dune's sandbox does not relocate the PATH environment variable. The +action's CWD is sandboxed, but PATH still points at the un-sandboxed +bin-layout dir. This works locally because absolute filesystem paths +are still readable from inside the sandbox. It would break under +remote action execution. + + $ cat >dune-project < (lang dune 3.24) + > (package (name mypkg)) + > EOF + $ mkdir src + $ cat >src/dune <<'EOF' + > (executable (public_name mybin) (package mypkg)) + > EOF + $ cat >src/mybin.ml <<'EOF' + > let () = print_endline "hello from mybin" + > EOF + + $ cat >dune <<'EOF' + > (rule + > (deps (sandbox always) %{bin:mybin}) + > (action + > (with-stdout-to out + > (bash "pwd; command -v mybin; mybin")))) + > EOF + +The action runs in the sandbox; pwd is sandboxed but the resolved +mybin path is the un-sandboxed bin-layout dir: + + $ dune build out --sandbox symlink 2>&1 + $ cat _build/default/out | censor + $PWD/_build/.sandbox/$DIGEST1/default + $PWD/_build/install/default/.binaries/$DIGEST2/mybin + hello from mybin + +The rule's deps include the build artifact and the bin-layout +symlink. Both are paths under the un-sandboxed _build/: + + $ dune rules --format=json _build/default/out \ + > | jq 'include "dune"; .[] | ruleDepFilePaths' \ + > | grep mybin | censor + "_build/default/src/mybin.exe" + "_build/install/default/.binaries/$DIGEST/mybin" diff --git a/test/blackbox-tests/test-cases/bin-pform/shared-layout.t b/test/blackbox-tests/test-cases/bin-pform/shared-layout.t new file mode 100644 index 00000000000..515ffd22583 --- /dev/null +++ b/test/blackbox-tests/test-cases/bin-pform/shared-layout.t @@ -0,0 +1,40 @@ +Two rules with the same set of %{bin:...} deps share a single +bin-layout directory (keyed by the digest of the sorted unique bin +names). + + $ cat >dune-project < (lang dune 3.24) + > (package (name mypkg)) + > EOF + $ mkdir src + $ cat >src/dune <<'EOF' + > (executable (public_name mybin) (package mypkg)) + > EOF + $ cat >src/mybin.ml <<'EOF' + > let () = print_endline "hello from mybin" + > EOF + + $ cat >dune <<'EOF' + > (rule + > (deps %{bin:mybin}) + > (action + > (with-stdout-to out1 + > (bash "echo $PATH")))) + > (rule + > (deps %{bin:mybin}) + > (action + > (with-stdout-to out2 + > (bash "echo $PATH")))) + > EOF + + $ dune build out1 out2 + +Both rules show the same bin-layout digest in PATH (no $DIGEST1 / +$DIGEST2): + + $ env_added "$(cat _build/default/out1)" "$PATH" | censor + $PWD/_build/install/default/.binaries/$DIGEST + $PWD/_build/install/default/bin + $ env_added "$(cat _build/default/out2)" "$PATH" | censor + $PWD/_build/install/default/.binaries/$DIGEST + $PWD/_build/install/default/bin diff --git a/test/blackbox-tests/test-cases/bin-pform/test-stanza.t b/test/blackbox-tests/test-cases/bin-pform/test-stanza.t index e8e94aa2037..0fa16e59b35 100644 --- a/test/blackbox-tests/test-cases/bin-pform/test-stanza.t +++ b/test/blackbox-tests/test-cases/bin-pform/test-stanza.t @@ -30,5 +30,6 @@ mytest.exe.output, which we then read. $ dune runtest 2>/dev/null [1] - $ env_added "$(cat _build/default/mytest.exe.output)" "$PATH" - $TESTCASE_ROOT/_build/install/default/bin + $ env_added "$(cat _build/default/mytest.exe.output)" "$PATH" | censor + $PWD/_build/install/default/.binaries/$DIGEST + $PWD/_build/install/default/bin diff --git a/test/blackbox-tests/test-cases/build-bin.t b/test/blackbox-tests/test-cases/build-bin.t index 0d540f17a90..61330b97104 100644 --- a/test/blackbox-tests/test-cases/build-bin.t +++ b/test/blackbox-tests/test-cases/build-bin.t @@ -35,9 +35,6 @@ We also have a subfolder `foo` Making Dune build the executables should work without error messages: $ dune build %{bin:public} - Error: File unavailable: - $TESTCASE_ROOT/../install/default/bin/public - [1] $ ls _build/default/public.exe _build/default/public.exe diff --git a/test/blackbox-tests/test-cases/custom-cross-compilation/bin-pform-context-expansion.t b/test/blackbox-tests/test-cases/custom-cross-compilation/bin-pform-context-expansion.t index 9c8c962c8f6..2d3ceb15ba5 100644 --- a/test/blackbox-tests/test-cases/custom-cross-compilation/bin-pform-context-expansion.t +++ b/test/blackbox-tests/test-cases/custom-cross-compilation/bin-pform-context-expansion.t @@ -1,9 +1,6 @@ %{bin:...} in a cross-compilation context. The pform expands via the -host context's artifacts, and the install bin dir on the action's -PATH is the host's install bin dir. - -mybin is gated to the host context only. If cross-context resolution -were broken, the binary wouldn't be found and the action would fail. +host context's artifacts, and the action's PATH gets the bin-layout +dir and the install bin dir, both under the host context. $ cat >dune-project < (lang dune 3.24) @@ -17,18 +14,13 @@ were broken, the binary wouldn't be found and the action would fail. > EOF $ cat >dune <<'EOF' - > (executable - > (public_name mybin) - > (package mypkg) - > (enabled_if (= %{context_name} host))) + > (executable (public_name mybin) (package mypkg)) > (rule > (enabled_if (= %{context_name} target)) > (deps %{bin:mybin}) > (action - > (progn - > (with-stdout-to path-output - > (bash "echo $PATH")) - > (run mybin)))) + > (with-stdout-to path-output + > (bash "echo $PATH")))) > EOF $ cat >mybin.ml <<'EOF' @@ -36,7 +28,7 @@ were broken, the binary wouldn't be found and the action would fail. > EOF $ dune build _build/target/path-output - hello - $ env_added "$(cat _build/target/path-output)" "$PATH" - $TESTCASE_ROOT/_build/install/host/bin + $ env_added "$(cat _build/target/path-output)" "$PATH" | censor + $PWD/_build/install/host/.binaries/$DIGEST + $PWD/_build/install/host/bin diff --git a/test/blackbox-tests/test-cases/depend-on/named-binding-with-package-error.t b/test/blackbox-tests/test-cases/depend-on/named-binding-with-package-error.t new file mode 100644 index 00000000000..96f002fbfc7 --- /dev/null +++ b/test/blackbox-tests/test-cases/depend-on/named-binding-with-package-error.t @@ -0,0 +1,39 @@ +Writing `(package ...)` inside a named dependency binding like +`(:name (package foo))` is rejected: the binding would resolve to an +empty path list, which is rarely what the user intended. + + $ cat >dune-project < (lang dune 3.24) + > (package (name mypkg)) + > EOF + $ mkdir src + $ cat >src/dune < (library (public_name mypkg)) + > EOF + $ cat >src/mypkg.ml <<'EOF' + > let x = 1 + > EOF + + $ cat >dune <<'EOF' + > (rule + > (deps (:pkg (package mypkg))) + > (action (with-stdout-to out (echo %{pkg})))) + > EOF + + $ dune build out 2>&1 + File "dune", line 2, characters 22-27: + 2 | (deps (:pkg (package mypkg))) + ^^^^^ + Error: (package ...) is not supported inside a named dependency binding + (:pkg). + Hint: Place the (package ...) entry in the deps list directly. + [1] + +Putting the package outside the named binding works: + + $ cat >dune <<'EOF' + > (rule + > (deps (package mypkg)) + > (action (with-stdout-to out (echo done)))) + > EOF + $ dune build out diff --git a/test/blackbox-tests/test-cases/describe/describe_location.t b/test/blackbox-tests/test-cases/describe/describe_location.t index ca033362902..eb329fd3b35 100644 --- a/test/blackbox-tests/test-cases/describe/describe_location.t +++ b/test/blackbox-tests/test-cases/describe/describe_location.t @@ -18,7 +18,7 @@ Exercise the various ways of resolving executable names with `dune exec`. An executable that would be installed by the current package: $ dune describe location foo - _build/install/default/bin/foo + _build/default/foo.exe An executable from the current project: $ dune describe location ./foo.exe @@ -64,4 +64,4 @@ Test that executables from PATH are located correctly: $TESTCASE_ROOT/bin/baz $ dune exec echo '%{bin:foo}' - _build/install/default/bin/foo + _build/default/foo.exe diff --git a/test/blackbox-tests/test-cases/exec/exec-bin.t b/test/blackbox-tests/test-cases/exec/exec-bin.t index 8237cce360c..8508fc36a90 100644 --- a/test/blackbox-tests/test-cases/exec/exec-bin.t +++ b/test/blackbox-tests/test-cases/exec/exec-bin.t @@ -32,7 +32,7 @@ The special form %{bin:public_name} is supported. $ dune exec %{bin:e} a b c Hello - argv[0] = ./_build/install/default/bin/e + argv[0] = ./_build/default/e.exe argv[1] = a argv[2] = b argv[3] = c @@ -58,7 +58,7 @@ It is possible to put the %{bin:...} pform in arguments rather than first. Got option: y Before Hello - argv[0] = _build/install/default/bin/e + argv[0] = _build/default/e.exe argv[1] = a argv[2] = b argv[3] = c @@ -67,13 +67,13 @@ It is possible to put the %{bin:...} pform in arguments rather than first. The first item is still looked up in PATH. $ dune exec ls %{bin:e} - _build/install/default/bin/e + _build/default/e.exe Pforms can appear several times. $ dune exec ls %{bin:e} %{bin:e} - _build/install/default/bin/e - _build/install/default/bin/e + _build/default/e.exe + _build/default/e.exe It should also be possible to call another program that is also supposed to be built if referenced, for this we create a new binary that calls its first @@ -103,6 +103,6 @@ If we then ask it to execute, both `call_arg` and `called` should be compiled and run, successfully. $ dune exec %{bin:call_arg} %{bin:called} - Calling my first arg, "_build/install/default/bin/called": + Calling my first arg, "_build/default/called.exe": I was called All good diff --git a/test/blackbox-tests/test-cases/optional-executable.t b/test/blackbox-tests/test-cases/optional-executable.t index 530db7e8855..af4d99cfffc 100644 --- a/test/blackbox-tests/test-cases/optional-executable.t +++ b/test/blackbox-tests/test-cases/optional-executable.t @@ -151,7 +151,6 @@ present even if the binary is not optional. Error: Library "doesnotexistatall" not found. -> required by _build/default/exe/.bar.eobjs/native/dune__exe__Bar.cmx -> required by _build/default/exe/bar.exe - -> required by _build/install/default/bin/dunetestbar -> required by %{bin:dunetestbar} at dune:3 -> required by alias run-x in dune:1 [1] diff --git a/test/blackbox-tests/test-cases/oxcaml/instantiate-parameterised.t b/test/blackbox-tests/test-cases/oxcaml/instantiate-parameterised.t index 76cdc9d4957..e4d857b8bd1 100644 --- a/test/blackbox-tests/test-cases/oxcaml/instantiate-parameterised.t +++ b/test/blackbox-tests/test-cases/oxcaml/instantiate-parameterised.t @@ -72,7 +72,6 @@ It's an error for the binary to partially instantiate `lib_ab`: ^^^^^^ Error: Missing argument for parameter "project.a". -> required by _build/default/bin/bin.exe - -> required by _build/install/default/bin/project.bin Hint: Pass an argument implementing "project.a" to the dependency. [1] @@ -99,7 +98,6 @@ overlapping modules) -> required by _build/default/bin/.bin.eobjs/byte/dune__exe.cmi -> required by _build/default/bin/.bin.eobjs/native/dune__exe.cmx -> required by _build/default/bin/bin.exe - -> required by _build/install/default/bin/project.bin [1] We add another way to implement the parameter `b` from the parameter `a`: @@ -136,14 +134,12 @@ dependencies, because its parameter `b` is missing: -> required by _build/default/bin/.bin.eobjs/byte/dune__exe.cmi -> required by _build/default/bin/.bin.eobjs/native/dune__exe.cmx -> required by _build/default/bin/bin.exe - -> required by _build/install/default/bin/project.bin File "bin/dune", line 6, characters 31-37: 6 | (instantiate lib_ab a_impl a_of_b))) ^^^^^^ Error: Missing argument for parameter "project.b". -> required by _build/default/bin/.bin.eobjs/native/dune__exe__Bin.cmx -> required by _build/default/bin/bin.exe - -> required by _build/install/default/bin/project.bin Hint: Pass an argument implementing "project.b" to the dependency. [1] @@ -209,7 +205,6 @@ It's an error to provide a non-required parameter: -> required by _build/default/bin/.bin.eobjs/byte/dune__exe.cmi -> required by _build/default/bin/.bin.eobjs/native/dune__exe.cmx -> required by _build/default/bin/bin.exe - -> required by _build/install/default/bin/project.bin Hint: Remove this argument [1] @@ -241,7 +236,6 @@ which one to use: -> required by _build/default/bin/.bin.eobjs/byte/dune__exe.cmi -> required by _build/default/bin/.bin.eobjs/native/dune__exe.cmx -> required by _build/default/bin/bin.exe - -> required by _build/install/default/bin/project.bin [1] Same error if the argument is repeated: @@ -262,7 +256,6 @@ Same error if the argument is repeated: -> required by _build/default/bin/.bin.eobjs/byte/dune__exe.cmi -> required by _build/default/bin/.bin.eobjs/native/dune__exe.cmx -> required by _build/default/bin/bin.exe - -> required by _build/install/default/bin/project.bin [1] We can instantiate the same library multiple times by giving it different names: diff --git a/test/blackbox-tests/test-cases/pkg/ocamlformat/ocamlformat-dev-tool-deps-conflict-project-deps.t b/test/blackbox-tests/test-cases/pkg/ocamlformat/ocamlformat-dev-tool-deps-conflict-project-deps.t index 3c22e2631ca..972e24b2d3a 100644 --- a/test/blackbox-tests/test-cases/pkg/ocamlformat/ocamlformat-dev-tool-deps-conflict-project-deps.t +++ b/test/blackbox-tests/test-cases/pkg/ocamlformat/ocamlformat-dev-tool-deps-conflict-project-deps.t @@ -130,7 +130,6 @@ There is no leak here. It is not taking the "printer" lib from dev-tools. Error: Library "printer" not found. -> required by _build/default/.foo.eobjs/native/dune__exe__Foo.cmx -> required by _build/default/foo.exe - -> required by _build/install/default/bin/foo [1] Update the executable "foo" to not depend on the library "printer", but "foo.ml" still diff --git a/test/blackbox-tests/test-cases/sandbox/sandboxing-package-deps.t b/test/blackbox-tests/test-cases/sandbox/sandboxing-package-deps.t index c53c68ec672..eddb7c0db97 100644 --- a/test/blackbox-tests/test-cases/sandbox/sandboxing-package-deps.t +++ b/test/blackbox-tests/test-cases/sandbox/sandboxing-package-deps.t @@ -26,5 +26,5 @@ Test sandboxing when depending on things from the install context using $ dune build --sandbox symlink @foo 2>&1 | sed -E 's#.*.sandbox/[^/]+/#.sandbox/$SANDBOX/#g' .sandbox/$SANDBOX/default .sandbox/$SANDBOX/install/default/bin/mybin - ../install/default/bin/mybin + foo/mybin.exe hello from package foo