diff --git a/src/cargo/core/compiler/artifact.rs b/src/cargo/core/compiler/artifact.rs index 42d979eed1b..d6b9fc105b3 100644 --- a/src/cargo/core/compiler/artifact.rs +++ b/src/cargo/core/compiler/artifact.rs @@ -12,9 +12,40 @@ use std::ffi::OsString; /// if artifacts are present. pub fn get_env( build_runner: &BuildRunner<'_, '_>, + unit: &Unit, dependencies: &[UnitDep], ) -> CargoResult> { let mut env = HashMap::new(); + + // Add `CARGO_BIN_EXE_` environment variables for building tests. + // + // These aren't built for `cargo check`, so can't use `dependencies` + if unit.target.is_test() || unit.target.is_bench() { + for bin_target in unit + .pkg + .manifest() + .targets() + .iter() + .filter(|target| target.is_bin()) + { + let name = bin_target + .binary_filename() + .unwrap_or_else(|| bin_target.name().to_string()); + + // For `cargo check` builds we do not uplift the CARGO_BIN_EXE_ artifacts to the + // artifact-dir. We do not want to provide a path to a non-existent binary but we still + // need to provide *something* so `env!("CARGO_BIN_EXE_...")` macros will compile. + let exe_path = build_runner + .files() + .bin_link_for_target(bin_target, unit.kind, build_runner.bcx)? + .map(|path| path.as_os_str().to_os_string()) + .unwrap_or_else(|| OsString::from(format!("placeholder:{name}"))); + + let key = format!("CARGO_BIN_EXE_{name}"); + env.insert(key, exe_path); + } + } + for unit_dep in dependencies.iter().filter(|d| d.unit.artifact.is_true()) { for artifact_path in build_runner .outputs(&unit_dep.unit)? diff --git a/src/cargo/core/compiler/build_runner/mod.rs b/src/cargo/core/compiler/build_runner/mod.rs index 02f3c62267a..ca223cf8395 100644 --- a/src/cargo/core/compiler/build_runner/mod.rs +++ b/src/cargo/core/compiler/build_runner/mod.rs @@ -279,7 +279,7 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { unstable_opts, linker: self.compilation.target_linker(unit.kind).clone(), script_metas, - env: artifact::get_env(&self, self.unit_deps(unit))?, + env: artifact::get_env(&self, unit, self.unit_deps(unit))?, }); } @@ -316,17 +316,17 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { if unit.mode == CompileMode::Test { self.compilation .tests - .push(self.unit_output(unit, &output.path)); + .push(self.unit_output(unit, &output.path)?); } else if unit.target.is_executable() { self.compilation .binaries - .push(self.unit_output(unit, bindst)); + .push(self.unit_output(unit, bindst)?); } else if unit.target.is_cdylib() && !self.compilation.cdylibs.iter().any(|uo| uo.unit == *unit) { self.compilation .cdylibs - .push(self.unit_output(unit, bindst)); + .push(self.unit_output(unit, bindst)?); } } Ok(()) @@ -554,13 +554,15 @@ impl<'a, 'gctx> BuildRunner<'a, 'gctx> { /// Returns a [`UnitOutput`] which represents some information about the /// output of a unit. - pub fn unit_output(&self, unit: &Unit, path: &Path) -> UnitOutput { + pub fn unit_output(&self, unit: &Unit, path: &Path) -> CargoResult { let script_metas = self.find_build_script_metadatas(unit); - UnitOutput { + let env = artifact::get_env(&self, unit, self.unit_deps(unit))?; + Ok(UnitOutput { unit: unit.clone(), path: path.to_path_buf(), script_metas, - } + env, + }) } /// Check if any output file name collision happens. diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index dff2d00ba80..24431fe979b 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -53,7 +53,6 @@ pub struct Doctest { } /// Information about the output of a unit. -#[derive(Ord, PartialOrd, Eq, PartialEq)] pub struct UnitOutput { /// The unit that generated this output. pub unit: Unit, @@ -63,6 +62,9 @@ pub struct UnitOutput { /// /// This is used for indexing [`Compilation::extra_env`]. pub script_metas: Option>, + + /// Environment variables to set in the unit's process. + pub env: HashMap, } /// A structure returning the result of a compilation. diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index db9bc9fce07..70a07c8c512 100644 --- a/src/cargo/core/compiler/custom_build.rs +++ b/src/cargo/core/compiler/custom_build.rs @@ -377,7 +377,7 @@ fn build_work(build_runner: &mut BuildRunner<'_, '_>, unit: &Unit) -> CargoResul .inherit_jobserver(&build_runner.jobserver); // Find all artifact dependencies and make their file and containing directory discoverable using environment variables. - for (var, value) in artifact::get_env(build_runner, dependencies)? { + for (var, value) in artifact::get_env(build_runner, unit, dependencies)? { cmd.env(&var, value); } diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index cffa9a69cf6..6aa74cfba84 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -1441,31 +1441,6 @@ fn build_base_args( .env("RUSTC_BOOTSTRAP", "1"); } - // Add `CARGO_BIN_EXE_` environment variables for building tests. - if unit.target.is_test() || unit.target.is_bench() { - for bin_target in unit - .pkg - .manifest() - .targets() - .iter() - .filter(|target| target.is_bin()) - { - // For `cargo check` builds we do not uplift the CARGO_BIN_EXE_ artifacts to the - // artifact-dir. We do not want to provide a path to a non-existent binary but we still - // need to provide *something* so `env!("CARGO_BIN_EXE_...")` macros will compile. - let exe_path = build_runner - .files() - .bin_link_for_target(bin_target, unit.kind, build_runner.bcx)? - .map(|path| path.as_os_str().to_os_string()) - .unwrap_or_else(|| OsString::from(format!("placeholder:{}", bin_target.name()))); - - let name = bin_target - .binary_filename() - .unwrap_or(bin_target.name().to_string()); - let key = format!("CARGO_BIN_EXE_{}", name); - cmd.env(&key, exe_path); - } - } Ok(()) } @@ -1769,7 +1744,7 @@ fn build_deps_args( cmd.arg(arg); } - for (var, env) in artifact::get_env(build_runner, deps)? { + for (var, env) in artifact::get_env(build_runner, unit, deps)? { cmd.env(&var, env); } diff --git a/src/cargo/ops/cargo_run.rs b/src/cargo/ops/cargo_run.rs index b7a56a8a0b0..240865ec5e5 100644 --- a/src/cargo/ops/cargo_run.rs +++ b/src/cargo/ops/cargo_run.rs @@ -97,6 +97,7 @@ pub fn run( unit, path, script_metas, + env: _env, } = &compile.binaries[0]; let exe = match path.strip_prefix(gctx.cwd()) { Ok(path) if path.file_name() == Some(path.as_os_str()) => Path::new(".").join(path), diff --git a/src/cargo/ops/cargo_test.rs b/src/cargo/ops/cargo_test.rs index 0e3e309c3b6..9ea6231ef56 100644 --- a/src/cargo/ops/cargo_test.rs +++ b/src/cargo/ops/cargo_test.rs @@ -8,6 +8,7 @@ use crate::util::errors::CargoResult; use crate::util::{CliError, CliResult, GlobalContext, add_path_args}; use anyhow::format_err; use cargo_util::{ProcessBuilder, ProcessError}; +use std::collections::HashMap; use std::ffi::OsString; use std::fmt::Write; use std::path::{Path, PathBuf}; @@ -103,7 +104,7 @@ pub fn run_benches(ws: &Workspace<'_>, options: &TestOptions, args: &[&str]) -> fn compile_tests<'a>(ws: &Workspace<'a>, options: &TestOptions) -> CargoResult> { let mut compilation = ops::compile(ws, &options.compile_opts)?; - compilation.tests.sort(); + compilation.tests.sort_by_key(|u| u.unit.clone()); Ok(compilation) } @@ -126,6 +127,7 @@ fn run_unit_tests( unit, path, script_metas, + env, } in compilation.tests.iter() { let (exe_display, mut cmd) = cmd_builds( @@ -134,6 +136,7 @@ fn run_unit_tests( unit, path, script_metas.as_ref(), + env, test_args, compilation, "unittests", @@ -287,6 +290,7 @@ fn display_no_run_information( unit, path, script_metas, + env, } in compilation.tests.iter() { let (exe_display, cmd) = cmd_builds( @@ -295,6 +299,7 @@ fn display_no_run_information( unit, path, script_metas.as_ref(), + env, test_args, compilation, exec_type, @@ -319,6 +324,7 @@ fn cmd_builds( unit: &Unit, path: &PathBuf, script_metas: Option<&Vec>, + env: &HashMap, test_args: &[&str], compilation: &Compilation<'_>, exec_type: &str, @@ -348,6 +354,9 @@ fn cmd_builds( if unit.target.harness() && gctx.shell().verbosity() == Verbosity::Quiet { cmd.arg("--quiet"); } + for (key, val) in env.iter() { + cmd.env(key, val); + } Ok((exe_display, cmd)) } diff --git a/tests/testsuite/test.rs b/tests/testsuite/test.rs index dacff7631b7..ef4c985f7c6 100644 --- a/tests/testsuite/test.rs +++ b/tests/testsuite/test.rs @@ -5216,6 +5216,9 @@ fn bin_env_for_test() { assert_eq!(env!("CARGO_BIN_EXE_foo"), ""); assert_eq!(env!("CARGO_BIN_EXE_with-dash"), ""); assert_eq!(env!("CARGO_BIN_EXE_grüßen"), ""); + assert_eq!(std::env::var("CARGO_BIN_EXE_foo").ok().as_deref(), Some("")); + assert_eq!(std::env::var("CARGO_BIN_EXE_with-dash").ok().as_deref(), Some("")); + assert_eq!(std::env::var("CARGO_BIN_EXE_grüßen").ok().as_deref(), Some("")); } "# .replace("", &bin_path("foo"))