Skip to content

Commit 3489428

Browse files
committed
Set an environment variable for tests to find executables.
1 parent db0dac5 commit 3489428

File tree

4 files changed

+104
-1
lines changed

4 files changed

+104
-1
lines changed

src/cargo/core/compiler/context/compilation_files.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use log::info;
1010

1111
use super::{BuildContext, CompileKind, Context, FileFlavor, Layout};
1212
use crate::core::compiler::{CompileMode, CompileTarget, Unit};
13-
use crate::core::{TargetKind, Workspace};
13+
use crate::core::{Target, TargetKind, Workspace};
1414
use crate::util::{self, CargoResult};
1515

1616
/// The `Metadata` is a hash used to make unique file names for each unit in a build.
@@ -241,6 +241,36 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
241241
}
242242
}
243243

244+
/// Returns the path to the executable binary for the given bin target.
245+
///
246+
/// This should only to be used when a `Unit` is not available.
247+
pub fn bin_link_for_target(
248+
&self,
249+
target: &Target,
250+
kind: CompileKind,
251+
bcx: &BuildContext<'_, '_>,
252+
) -> CargoResult<PathBuf> {
253+
assert!(target.is_bin());
254+
let dest = self.layout(kind).dest();
255+
let info = bcx.info(kind);
256+
let file_types = info
257+
.file_types(
258+
"bin",
259+
FileFlavor::Normal,
260+
&TargetKind::Bin,
261+
kind.short_name(bcx),
262+
)?
263+
.expect("target must support `bin`");
264+
265+
let file_type = file_types
266+
.iter()
267+
.filter(|file_type| file_type.flavor == FileFlavor::Normal)
268+
.next()
269+
.expect("target must support `bin`");
270+
271+
Ok(dest.join(file_type.filename(target.name())))
272+
}
273+
244274
/// Returns the filenames that the given unit will generate.
245275
pub(super) fn outputs(
246276
&self,

src/cargo/core/compiler/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,23 @@ fn build_base_args<'a, 'cfg>(
876876
cmd.arg("-Zforce-unstable-if-unmarked")
877877
.env("RUSTC_BOOTSTRAP", "1");
878878
}
879+
880+
// Add `CARGO_BIN_` environment variables for building tests.
881+
if unit.target.is_test() || unit.target.is_bench() {
882+
for bin_target in unit
883+
.pkg
884+
.manifest()
885+
.targets()
886+
.iter()
887+
.filter(|target| target.is_bin())
888+
{
889+
let exe_path = cx
890+
.files()
891+
.bin_link_for_target(bin_target, unit.kind, cx.bcx)?;
892+
let key = format!("CARGO_BIN_EXE_{}", bin_target.crate_name().to_uppercase());
893+
cmd.env(&key, exe_path);
894+
}
895+
}
879896
Ok(())
880897
}
881898

src/doc/src/reference/environment-variables.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,15 @@ let version = env!("CARGO_PKG_VERSION");
187187
* `OUT_DIR` — If the package has a build script, this is set to the folder where the build
188188
script should place its output. See below for more information.
189189
(Only set during compilation.)
190+
* `CARGO_BIN_EXE_<name>` — The absolute path to a binary target's executable.
191+
This is only set when building an [integration test] or benchmark. This may
192+
be used with the [`env` macro] to find the executable to run for testing
193+
purposes. The `<name>` is the name of the binary converted to uppercase, and
194+
`-` converted to `_`. Binaries are automatically built when the test is
195+
built, unless the binary has required features that are not enabled.
196+
197+
[integration test]: manifest.md#integration-tests
198+
[`env` macro]: ../../std/macro.env.html
190199

191200
#### Dynamic library paths
192201

tests/testsuite/test.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3995,3 +3995,50 @@ fn panic_abort_test_profile_inherits() {
39953995
.with_status(0)
39963996
.run();
39973997
}
3998+
3999+
#[cargo_test]
4000+
fn bin_env_for_test() {
4001+
// Test for the `CARGO_BIN_` environment variables for tests.
4002+
//
4003+
// Note: The Unicode binary uses a `[[bin]]` definition because different
4004+
// filesystems normalize utf-8 in different ways. For example, HFS uses
4005+
// "gru\u{308}ßen" and APFS uses "gr\u{fc}ßen". Defining it in TOML forces
4006+
// one form to be used.
4007+
let p = project()
4008+
.file(
4009+
"Cargo.toml",
4010+
r#"
4011+
[package]
4012+
name = "foo"
4013+
version = "0.1.0"
4014+
edition = "2018"
4015+
4016+
[[bin]]
4017+
name = 'grüßen'
4018+
path = 'src/bin/grussen.rs'
4019+
"#,
4020+
)
4021+
.file("src/bin/foo.rs", "fn main() {}")
4022+
.file("src/bin/with-dash.rs", "fn main() {}")
4023+
.file("src/bin/grussen.rs", "fn main() {}")
4024+
.build();
4025+
4026+
let bin_path = |name| p.bin(name).to_string_lossy().replace("\\", "\\\\");
4027+
p.change_file(
4028+
"tests/check_env.rs",
4029+
&r#"
4030+
#[test]
4031+
fn run_bins() {
4032+
assert_eq!(env!("CARGO_BIN_EXE_FOO"), "<FOO_PATH>");
4033+
assert_eq!(env!("CARGO_BIN_EXE_WITH_DASH"), "<WITH_DASH_PATH>");
4034+
assert_eq!(env!("CARGO_BIN_EXE_GRÜSSEN"), "<GRÜSSEN_PATH>");
4035+
}
4036+
"#
4037+
.replace("<FOO_PATH>", &bin_path("foo"))
4038+
.replace("<WITH_DASH_PATH>", &bin_path("with-dash"))
4039+
.replace("<GRÜSSEN_PATH>", &bin_path("grüßen")),
4040+
);
4041+
4042+
p.cargo("test --test check_env").run();
4043+
p.cargo("check --test check_env").run();
4044+
}

0 commit comments

Comments
 (0)