From 6ff028757515587cc85a2f6ecf9bcfce6eeb9e49 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 Dec 2025 13:43:58 -0600 Subject: [PATCH 1/7] refactor(compile): Only generate the name if needed --- src/cargo/core/compiler/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 7695a526f42..e14d4828f21 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -1498,7 +1498,7 @@ fn build_base_args( let name = bin_target .binary_filename() - .unwrap_or(bin_target.name().to_string()); + .unwrap_or_else(|| bin_target.name().to_string()); let key = format!("CARGO_BIN_EXE_{}", name); cmd.env(&key, exe_path); } From c574ad3ad71cde8f8f2bd335fa2d3502256cc22a Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 Dec 2025 13:44:43 -0600 Subject: [PATCH 2/7] refactor(compile): Use the binary name for the placeholder --- src/cargo/core/compiler/mod.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index e14d4828f21..db9f5f17e48 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -1487,6 +1487,10 @@ fn build_base_args( .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. @@ -1494,12 +1498,9 @@ fn build_base_args( .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()))); + .unwrap_or_else(|| OsString::from(format!("placeholder:{name}"))); - let name = bin_target - .binary_filename() - .unwrap_or_else(|| bin_target.name().to_string()); - let key = format!("CARGO_BIN_EXE_{}", name); + let key = format!("CARGO_BIN_EXE_{name}"); cmd.env(&key, exe_path); } } From 41c171bd35da5582abf9853d29498f7e6bcecad4 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 Dec 2025 14:01:40 -0600 Subject: [PATCH 3/7] refactor(compile): Move CARGO_BIN_EXE_ next to artifact deps Seeing as this is an implicit artifact At this new location, it will now run as part of `cargo rustdoc --test ` which technically fixes a bug but `--test` is not really supported (#13427) so I didn't mark this as a `fix` nor did I add tests. --- src/cargo/core/compiler/mod.rs | 53 +++++++++++++++++----------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index db9f5f17e48..f6551162ea7 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -1478,32 +1478,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()) - { - 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}"); - cmd.env(&key, exe_path); - } - } Ok(()) } @@ -1807,6 +1781,33 @@ fn build_deps_args( cmd.arg(arg); } + // 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()) + { + 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}"); + cmd.env(&key, exe_path); + } + } + for (var, env) in artifact::get_env(build_runner, deps)? { cmd.env(&var, env); } From 6e0bb91058f1379c5fc508714384dfecb9930f13 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 Dec 2025 14:39:25 -0600 Subject: [PATCH 4/7] refactor(compile): Move implicit artfacts into explicit artifacts This now runs in build scripts and doctests *but* the unit check should prevent any side effects from happening. --- src/cargo/core/compiler/artifact.rs | 31 +++++++++++++++++++++ src/cargo/core/compiler/build_runner/mod.rs | 2 +- src/cargo/core/compiler/custom_build.rs | 2 +- src/cargo/core/compiler/mod.rs | 29 +------------------ 4 files changed, 34 insertions(+), 30 deletions(-) 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 35a7aff8f07..ebaa95bbf36 100644 --- a/src/cargo/core/compiler/build_runner/mod.rs +++ b/src/cargo/core/compiler/build_runner/mod.rs @@ -284,7 +284,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))?, }); } diff --git a/src/cargo/core/compiler/custom_build.rs b/src/cargo/core/compiler/custom_build.rs index d05201d6c5b..851b5101891 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 f6551162ea7..1dbc52bd5bc 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -1781,34 +1781,7 @@ fn build_deps_args( cmd.arg(arg); } - // 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()) - { - 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}"); - cmd.env(&key, exe_path); - } - } - - 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); } From 13e120ba5bcd08de234094fbaee13d8d71cf43b7 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 Dec 2025 14:45:31 -0600 Subject: [PATCH 5/7] refactor(compile): Relax traits for UnitOutput --- src/cargo/core/compiler/compilation.rs | 1 - src/cargo/ops/cargo_test.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cargo/core/compiler/compilation.rs b/src/cargo/core/compiler/compilation.rs index dff2d00ba80..9c4febabd91 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, diff --git a/src/cargo/ops/cargo_test.rs b/src/cargo/ops/cargo_test.rs index 0e3e309c3b6..7ddf662464b 100644 --- a/src/cargo/ops/cargo_test.rs +++ b/src/cargo/ops/cargo_test.rs @@ -103,7 +103,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) } From 5b9bd20121ab641412b2e325dcd96f57a507d7df Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 Dec 2025 14:54:10 -0600 Subject: [PATCH 6/7] test(test): Show runtime behavior of CARGO_BIN_EXE --- tests/testsuite/test.rs | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/tests/testsuite/test.rs b/tests/testsuite/test.rs index dacff7631b7..2db3b7a22cb 100644 --- a/tests/testsuite/test.rs +++ b/tests/testsuite/test.rs @@ -5205,6 +5205,29 @@ fn bin_env_for_test() { .file("src/bin/foo.rs", "fn main() {}") .file("src/bin/with-dash.rs", "fn main() {}") .file("src/bin/grussen.rs", "fn main() {}") + .file( + "src/lib.rs", + r#" + //! ``` + //! assert_eq!(option_env!("CARGO_BIN_EXE_foo"), None); + //! assert_eq!(option_env!("CARGO_BIN_EXE_with-dash"), None); + //! assert_eq!(option_env!("CARGO_BIN_EXE_grüßen"), None); + //! assert_eq!(std::env::var("CARGO_BIN_EXE_foo").ok(), None); + //! assert_eq!(std::env::var("CARGO_BIN_EXE_with-dash").ok(), None); + //! assert_eq!(std::env::var("CARGO_BIN_EXE_grüßen").ok(), None); + //! ``` + + #[test] + fn no_bins() { + assert_eq!(option_env!("CARGO_BIN_EXE_foo"), None); + assert_eq!(option_env!("CARGO_BIN_EXE_with-dash"), None); + assert_eq!(option_env!("CARGO_BIN_EXE_grüßen"), None); + assert_eq!(std::env::var("CARGO_BIN_EXE_foo").ok(), None); + assert_eq!(std::env::var("CARGO_BIN_EXE_with-dash").ok(), None); + assert_eq!(std::env::var("CARGO_BIN_EXE_grüßen").ok(), None); + } +"#, + ) .build(); let bin_path = |name| p.bin(name).to_string_lossy().replace("\\", "\\\\"); @@ -5216,6 +5239,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(), None); + assert_eq!(std::env::var("CARGO_BIN_EXE_with-dash").ok(), None); + assert_eq!(std::env::var("CARGO_BIN_EXE_grüßen").ok(), None); } "# .replace("", &bin_path("foo")) @@ -5223,8 +5249,8 @@ fn bin_env_for_test() { .replace("", &bin_path("grüßen")), ); - p.cargo("test --test check_env").run(); - p.cargo("check --test check_env").run(); + p.cargo("test").run(); + p.cargo("check --all-targets").run(); } #[cargo_test] From fb81b05d81f492b39480359d34d6c1c15cfdbc36 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Fri, 19 Dec 2025 15:01:56 -0600 Subject: [PATCH 7/7] feat(test): Make CARGO_BIN_EXE_ available at runtime This also makes artifact deps available for consistency purposes. I originally proposed this for when moving Cargo off of Cargo's own internals but went with a different solution. Re-visiting this because `assert_cmd` has 2300+ dependents and it seems like making `assert_cmd::cargo_bin` work would be a better use of time than migrating all of those users to `assert_cmd::cargo_bin!`. For example, within the top 130 dependents (100,000 downloads or more), I found 66 that used `assert_cmd::cargo_bin` (rust-lang/rust#149852). > The reason to make `CARGO_BIN_EXE` set only at build-time was to > address the concern of manually running the test executable. > It's not > too common for tests to look at any runtime environment variables > (that I know of), so it usually just works (like running > `gdb target/debug/.../test-xxx`). > The concern was that if it were set at > runtime it would move more down the path where directly running the test > executable doesn't "just work". See https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/cargo_bin_exe.20and.20tests/near/513638220 However, - This is user opt-in - Users can run with `-vv` to see the env variables that are set - Users can run `CARGO_TARGET_..._RUNNER=gdb` - We can notify the `cargo nextest`, the main third-party test runner, about this. It should be easy to support as they have their own version of this, see https://nexte.st/docs/configuration/env-vars/?h=nextest_bin_exe#environment-variables-nextest-sets --- src/cargo/core/compiler/build_runner/mod.rs | 14 ++++++++------ src/cargo/core/compiler/compilation.rs | 3 +++ src/cargo/ops/cargo_run.rs | 1 + src/cargo/ops/cargo_test.rs | 9 +++++++++ src/doc/man/generated_txt/cargo-bench.txt | 5 +++-- src/doc/man/generated_txt/cargo-build.txt | 5 +++-- src/doc/man/generated_txt/cargo-rustc.txt | 5 +++-- src/doc/man/generated_txt/cargo-test.txt | 5 +++-- .../includes/options-targets-bin-auto-built.md | 5 +++-- src/doc/src/commands/cargo-bench.md | 5 +++-- src/doc/src/commands/cargo-build.md | 5 +++-- src/doc/src/commands/cargo-rustc.md | 5 +++-- src/doc/src/commands/cargo-test.md | 5 +++-- src/doc/src/reference/cargo-targets.md | 5 +++-- src/doc/src/reference/environment-variables.md | 17 +++++++++++++++++ src/etc/man/cargo-bench.1 | 5 +++-- src/etc/man/cargo-build.1 | 5 +++-- src/etc/man/cargo-rustc.1 | 5 +++-- src/etc/man/cargo-test.1 | 5 +++-- tests/testsuite/test.rs | 6 +++--- 20 files changed, 83 insertions(+), 37 deletions(-) diff --git a/src/cargo/core/compiler/build_runner/mod.rs b/src/cargo/core/compiler/build_runner/mod.rs index ebaa95bbf36..caa10f0af4a 100644 --- a/src/cargo/core/compiler/build_runner/mod.rs +++ b/src/cargo/core/compiler/build_runner/mod.rs @@ -321,17 +321,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(()) @@ -561,13 +561,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 9c4febabd91..24431fe979b 100644 --- a/src/cargo/core/compiler/compilation.rs +++ b/src/cargo/core/compiler/compilation.rs @@ -62,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/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 7ddf662464b..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}; @@ -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/src/doc/man/generated_txt/cargo-bench.txt b/src/doc/man/generated_txt/cargo-bench.txt index 8be0ed97f72..f1fa449452a 100644 --- a/src/doc/man/generated_txt/cargo-bench.txt +++ b/src/doc/man/generated_txt/cargo-bench.txt @@ -138,8 +138,9 @@ OPTIONS test to execute the binary to exercise and test its behavior. The CARGO_BIN_EXE_ environment variable - is set when the integration test is built so that it can use the env - macro to locate the + is set when the integration test is built and run so that it can use the + env macro or the var + function to locate the executable. Passing target selection flags will benchmark only the specified diff --git a/src/doc/man/generated_txt/cargo-build.txt b/src/doc/man/generated_txt/cargo-build.txt index 57983b8c109..acce0baf363 100644 --- a/src/doc/man/generated_txt/cargo-build.txt +++ b/src/doc/man/generated_txt/cargo-build.txt @@ -56,8 +56,9 @@ OPTIONS execute the binary to exercise and test its behavior. The CARGO_BIN_EXE_ environment variable - is set when the integration test is built so that it can use the env - macro to locate the + is set when the integration test is built and run so that it can use the + env macro or the var + function to locate the executable. Passing target selection flags will build only the specified targets. diff --git a/src/doc/man/generated_txt/cargo-rustc.txt b/src/doc/man/generated_txt/cargo-rustc.txt index bdb03f6eda2..6f7dad5b0a1 100644 --- a/src/doc/man/generated_txt/cargo-rustc.txt +++ b/src/doc/man/generated_txt/cargo-rustc.txt @@ -47,8 +47,9 @@ OPTIONS execute the binary to exercise and test its behavior. The CARGO_BIN_EXE_ environment variable - is set when the integration test is built so that it can use the env - macro to locate the + is set when the integration test is built and run so that it can use the + env macro or the var + function to locate the executable. Passing target selection flags will build only the specified targets. diff --git a/src/doc/man/generated_txt/cargo-test.txt b/src/doc/man/generated_txt/cargo-test.txt index a40ffe1c010..ae3a6b66b45 100644 --- a/src/doc/man/generated_txt/cargo-test.txt +++ b/src/doc/man/generated_txt/cargo-test.txt @@ -157,8 +157,9 @@ OPTIONS execute the binary to exercise and test its behavior. The CARGO_BIN_EXE_ environment variable - is set when the integration test is built so that it can use the env - macro to locate the + is set when the integration test is built and run so that it can use the + env macro or the var + function to locate the executable. Passing target selection flags will test only the specified targets. diff --git a/src/doc/man/includes/options-targets-bin-auto-built.md b/src/doc/man/includes/options-targets-bin-auto-built.md index c2234ab79f9..57146427b3e 100644 --- a/src/doc/man/includes/options-targets-bin-auto-built.md +++ b/src/doc/man/includes/options-targets-bin-auto-built.md @@ -3,6 +3,7 @@ benchmark being selected to {{lower actionverb}}. This allows an integration test to execute the binary to exercise and test its behavior. The `CARGO_BIN_EXE_` [environment variable](../reference/environment-variables.html#environment-variables-cargo-sets-for-crates) -is set when the integration test is built so that it can use the -[`env` macro](https://doc.rust-lang.org/std/macro.env.html) to locate the +is set when the integration test is built and run so that it can use the +[`env` macro](https://doc.rust-lang.org/std/macro.env.html) or the +[`var` function](https://doc.rust-lang.org/std/env/fn.var.html) to locate the executable. diff --git a/src/doc/src/commands/cargo-bench.md b/src/doc/src/commands/cargo-bench.md index cab06a0b74c..63eedeb5e68 100644 --- a/src/doc/src/commands/cargo-bench.md +++ b/src/doc/src/commands/cargo-bench.md @@ -157,8 +157,9 @@ benchmark being selected to benchmark. This allows an integration test to execute the binary to exercise and test its behavior. The `CARGO_BIN_EXE_` [environment variable](../reference/environment-variables.html#environment-variables-cargo-sets-for-crates) -is set when the integration test is built so that it can use the -[`env` macro](https://doc.rust-lang.org/std/macro.env.html) to locate the +is set when the integration test is built and run so that it can use the +[`env` macro](https://doc.rust-lang.org/std/macro.env.html) or the +[`var` function](https://doc.rust-lang.org/std/env/fn.var.html) to locate the executable. Passing target selection flags will benchmark only the specified diff --git a/src/doc/src/commands/cargo-build.md b/src/doc/src/commands/cargo-build.md index f47254d7b1d..83eee7cab04 100644 --- a/src/doc/src/commands/cargo-build.md +++ b/src/doc/src/commands/cargo-build.md @@ -70,8 +70,9 @@ benchmark being selected to build. This allows an integration test to execute the binary to exercise and test its behavior. The `CARGO_BIN_EXE_` [environment variable](../reference/environment-variables.html#environment-variables-cargo-sets-for-crates) -is set when the integration test is built so that it can use the -[`env` macro](https://doc.rust-lang.org/std/macro.env.html) to locate the +is set when the integration test is built and run so that it can use the +[`env` macro](https://doc.rust-lang.org/std/macro.env.html) or the +[`var` function](https://doc.rust-lang.org/std/env/fn.var.html) to locate the executable. Passing target selection flags will build only the specified diff --git a/src/doc/src/commands/cargo-rustc.md b/src/doc/src/commands/cargo-rustc.md index 6c81459a264..c009704f885 100644 --- a/src/doc/src/commands/cargo-rustc.md +++ b/src/doc/src/commands/cargo-rustc.md @@ -56,8 +56,9 @@ benchmark being selected to build. This allows an integration test to execute the binary to exercise and test its behavior. The `CARGO_BIN_EXE_` [environment variable](../reference/environment-variables.html#environment-variables-cargo-sets-for-crates) -is set when the integration test is built so that it can use the -[`env` macro](https://doc.rust-lang.org/std/macro.env.html) to locate the +is set when the integration test is built and run so that it can use the +[`env` macro](https://doc.rust-lang.org/std/macro.env.html) or the +[`var` function](https://doc.rust-lang.org/std/env/fn.var.html) to locate the executable. Passing target selection flags will build only the specified diff --git a/src/doc/src/commands/cargo-test.md b/src/doc/src/commands/cargo-test.md index bcf2d31bf04..881f9230dd5 100644 --- a/src/doc/src/commands/cargo-test.md +++ b/src/doc/src/commands/cargo-test.md @@ -170,8 +170,9 @@ benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. The `CARGO_BIN_EXE_` [environment variable](../reference/environment-variables.html#environment-variables-cargo-sets-for-crates) -is set when the integration test is built so that it can use the -[`env` macro](https://doc.rust-lang.org/std/macro.env.html) to locate the +is set when the integration test is built and run so that it can use the +[`env` macro](https://doc.rust-lang.org/std/macro.env.html) or the +[`var` function](https://doc.rust-lang.org/std/env/fn.var.html) to locate the executable. Passing target selection flags will test only the specified diff --git a/src/doc/src/reference/cargo-targets.md b/src/doc/src/reference/cargo-targets.md index 160988ca9f0..47021a1ce3b 100644 --- a/src/doc/src/reference/cargo-targets.md +++ b/src/doc/src/reference/cargo-targets.md @@ -134,11 +134,12 @@ annotated functions and run them in parallel. You can pass module names to Binary targets are automatically built if there is an integration test. This allows an integration test to execute the binary to exercise and test its behavior. The `CARGO_BIN_EXE_` [environment variable] is set when the -integration test is built so that it can use the [`env` macro] to locate the -executable. +integration test is built and run so that it can use the [`env` macro] or [`var` function] +to locate the executable. [environment variable]: environment-variables.md#environment-variables-cargo-sets-for-crates [`env` macro]: ../../std/macro.env.html +[`var` function]: ../../std/env/fn.var.html ## Benchmarks diff --git a/src/doc/src/reference/environment-variables.md b/src/doc/src/reference/environment-variables.md index 31764dd0ce1..e2da513d490 100644 --- a/src/doc/src/reference/environment-variables.md +++ b/src/doc/src/reference/environment-variables.md @@ -430,6 +430,23 @@ let out_dir = env::var("OUT_DIR").unwrap(); [`debug`]: profiles.md#debug [`opt-level`]: profiles.md#opt-level +## Environment variables Cargo sets for `cargo test` + +Cargo sets several environment variables when tests are run. +You can retrieve the values when the tests are run: + +```rust,ignore +use std::env; +let out_dir = env::var("CARGO_BIN_EXE_foo").unwrap(); +``` + +* `CARGO_BIN_EXE_` --- The absolute path to a binary target's executable. + This is only set when running an [integration test] or benchmark. + The `` is the name of the binary target, exactly as-is. For + example, `CARGO_BIN_EXE_my-program` for a binary named `my-program`. + Binaries are automatically built when the test is built, unless the binary + has required features that are not enabled. + ## Environment variables Cargo sets for 3rd party subcommands Cargo exposes this environment variable to 3rd party subcommands diff --git a/src/etc/man/cargo-bench.1 b/src/etc/man/cargo-bench.1 index 2b72a53a295..c447bb058e9 100644 --- a/src/etc/man/cargo-bench.1 +++ b/src/etc/man/cargo-bench.1 @@ -161,8 +161,9 @@ benchmark being selected to benchmark. This allows an integration test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR -is set when the integration test is built so that it can use the -\fI\f(BIenv\fI macro\fR to locate the +is set when the integration test is built and run so that it can use the +\fI\f(BIenv\fI macro\fR or the +\fI\f(BIvar\fI function\fR to locate the executable. .sp Passing target selection flags will benchmark only the specified diff --git a/src/etc/man/cargo-build.1 b/src/etc/man/cargo-build.1 index 38bb7172c75..a256bcb6d42 100644 --- a/src/etc/man/cargo-build.1 +++ b/src/etc/man/cargo-build.1 @@ -60,8 +60,9 @@ benchmark being selected to build. This allows an integration test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR -is set when the integration test is built so that it can use the -\fI\f(BIenv\fI macro\fR to locate the +is set when the integration test is built and run so that it can use the +\fI\f(BIenv\fI macro\fR or the +\fI\f(BIvar\fI function\fR to locate the executable. .sp Passing target selection flags will build only the specified diff --git a/src/etc/man/cargo-rustc.1 b/src/etc/man/cargo-rustc.1 index 5c43e3bdc48..6bcb3a5a4bb 100644 --- a/src/etc/man/cargo-rustc.1 +++ b/src/etc/man/cargo-rustc.1 @@ -46,8 +46,9 @@ benchmark being selected to build. This allows an integration test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR -is set when the integration test is built so that it can use the -\fI\f(BIenv\fI macro\fR to locate the +is set when the integration test is built and run so that it can use the +\fI\f(BIenv\fI macro\fR or the +\fI\f(BIvar\fI function\fR to locate the executable. .sp Passing target selection flags will build only the specified diff --git a/src/etc/man/cargo-test.1 b/src/etc/man/cargo-test.1 index 58dd1fb6c5a..acc4b27b2b1 100644 --- a/src/etc/man/cargo-test.1 +++ b/src/etc/man/cargo-test.1 @@ -175,8 +175,9 @@ benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. The \fBCARGO_BIN_EXE_\fR \fIenvironment variable\fR -is set when the integration test is built so that it can use the -\fI\f(BIenv\fI macro\fR to locate the +is set when the integration test is built and run so that it can use the +\fI\f(BIenv\fI macro\fR or the +\fI\f(BIvar\fI function\fR to locate the executable. .sp Passing target selection flags will test only the specified diff --git a/tests/testsuite/test.rs b/tests/testsuite/test.rs index 2db3b7a22cb..77c244d6169 100644 --- a/tests/testsuite/test.rs +++ b/tests/testsuite/test.rs @@ -5239,9 +5239,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(), None); - assert_eq!(std::env::var("CARGO_BIN_EXE_with-dash").ok(), None); - assert_eq!(std::env::var("CARGO_BIN_EXE_grüßen").ok(), None); + 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"))