Skip to content

Commit 945b6bc

Browse files
committed
Add rustc folder to dynamic linker search path
... so that we can run cargo-nextest with proc-macro projects on Windows. This commit also adds integration tests for running cargo-nextest for proc-macro projects.
1 parent 627e282 commit 945b6bc

21 files changed

+344
-44
lines changed

cargo-nextest/src/dispatch.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use std::{
4545
collections::BTreeSet,
4646
env::VarError,
4747
io::{Cursor, Write},
48+
path::PathBuf,
4849
sync::Arc,
4950
};
5051
use swrite::{swrite, SWrite};
@@ -1009,7 +1010,31 @@ impl BaseApp {
10091010
None => {
10101011
let target_triple =
10111012
discover_target_triple(&cargo_configs, cargo_opts.target.as_deref());
1012-
BuildPlatforms::new(target_triple)?
1013+
let mut args = vec!["--print", "sysroot"];
1014+
if let Some(target_triple) = &target_triple {
1015+
args.extend(["--target", target_triple.platform.triple_str()]);
1016+
}
1017+
let output = duct::cmd(rustc_path().as_str(), args)
1018+
.stdout_capture()
1019+
.unchecked()
1020+
.run()
1021+
.ok()
1022+
.and_then(|output| {
1023+
if output.status.success() {
1024+
Some(Cursor::new(output.stdout))
1025+
} else {
1026+
log::debug!(
1027+
"failed to execute sysroot discover command: {}",
1028+
output.status
1029+
);
1030+
log::debug!("stdout:");
1031+
log::debug!("{}", String::from_utf8_lossy(&output.stdout));
1032+
log::debug!("stderr:");
1033+
log::debug!("{}", String::from_utf8_lossy(&output.stderr));
1034+
None
1035+
}
1036+
});
1037+
BuildPlatforms::new(output, target_triple)?
10131038
}
10141039
};
10151040

@@ -2012,6 +2037,15 @@ fn warn_on_err(thing: &str, err: &(dyn std::error::Error)) {
20122037
log::warn!("{}", s);
20132038
}
20142039

2040+
fn rustc_path() -> Utf8PathBuf {
2041+
match std::env::var_os("RUSTC") {
2042+
Some(rustc_path) => PathBuf::from(rustc_path)
2043+
.try_into()
2044+
.expect("RUSTC env var is not valid UTF-8"),
2045+
None => Utf8PathBuf::from("rustc"),
2046+
}
2047+
}
2048+
20152049
#[cfg(test)]
20162050
mod tests {
20172051
use super::*;

fixtures/nextest-tests/Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fixtures/nextest-tests/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ members = [
3434
"derive",
3535
"dylib-test",
3636
"with-build-script",
37+
"proc-macro-test"
3738
]
3839

3940
[dependencies]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "proc-macro-test"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
proc-macro = true

fixtures/nextest-tests/proc-macro-test/src/lib.rs

Whitespace-only changes.

integration-tests/tests/integration/fixtures.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ pub static EXPECTED_LIST: Lazy<Vec<TestInfo>> = Lazy::new(|| {
128128
BuildPlatform::Target,
129129
vec![("tests::test_out_dir_present", false)],
130130
),
131+
TestInfo::new("proc-macro-test", BuildPlatform::Host, vec![]),
131132
]
132133
});
133134

@@ -379,7 +380,20 @@ pub fn check_list_binaries_output(stdout: &[u8]) {
379380
let result: BinaryListSummary = serde_json::from_slice(stdout).unwrap();
380381

381382
let test_suite = &*EXPECTED_LIST;
382-
assert_eq!(test_suite.len(), result.rust_binaries.len());
383+
let mut expected_binary_ids = test_suite
384+
.iter()
385+
.map(|test_info| test_info.id.clone())
386+
.collect::<Vec<_>>();
387+
expected_binary_ids.sort();
388+
let mut actual_binary_ids = result.rust_binaries.keys().collect::<Vec<_>>();
389+
actual_binary_ids.sort();
390+
assert_eq!(
391+
test_suite.len(),
392+
result.rust_binaries.len(),
393+
"expected rust binaries:\n{:?}\nactual rust binaries\n{:?}",
394+
expected_binary_ids,
395+
actual_binary_ids
396+
);
383397

384398
for test in test_suite {
385399
let entry = result

integration-tests/tests/integration/snapshots/integration__archive_includes.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
source: integration-tests/tests/integration/main.rs
33
expression: output.stderr_as_str()
44
---
5-
Archiving 16 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 7 extra paths to <archive-file>
5+
Archiving 17 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 7 extra paths to <archive-file>
66
Warning ignoring extra path `<target-dir>/excluded-dir` because it does not exist
77
Warning ignoring extra path `<target-dir>/depth-0-dir` specified with depth 0 since it is a directory
88
Warning ignoring extra path `<target-dir>/file_that_does_not_exist.txt` because it does not exist

integration-tests/tests/integration/snapshots/integration__archive_includes_without_uds.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
source: integration-tests/tests/integration/main.rs
33
expression: output.stderr_as_str()
44
---
5-
Archiving 16 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 7 extra paths to <archive-file>
5+
Archiving 17 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 7 extra paths to <archive-file>
66
Warning ignoring extra path `<target-dir>/excluded-dir` because it does not exist
77
Warning ignoring extra path `<target-dir>/depth-0-dir` specified with depth 0 since it is a directory
88
Warning ignoring extra path `<target-dir>/file_that_does_not_exist.txt` because it does not exist

integration-tests/tests/integration/snapshots/integration__archive_missing_includes.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
source: integration-tests/tests/integration/main.rs
33
expression: output.stderr_as_str()
44
---
5-
Archiving 16 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 1 extra path to <archive-file>
5+
Archiving 17 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 1 extra path to <archive-file>
66
error: error creating archive `<archive-file>`
77

88
Caused by:

integration-tests/tests/integration/snapshots/integration__archive_no_includes.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
source: integration-tests/tests/integration/main.rs
33
expression: output.stderr_as_str()
44
---
5-
Archiving 16 binaries (including 2 non-test binaries), 2 build script output directories, and 2 linked paths to <archive-file>
5+
Archiving 17 binaries (including 2 non-test binaries), 2 build script output directories, and 2 linked paths to <archive-file>
66
Warning linked path `<target-dir>/debug/build/<cdylib-link-hash>/does-not-exist` not found, requested by: cdylib-link v0.1.0
77
(this is a bug in this crate that should be fixed)
88
Archived <file-count> files to <archive-file> in <duration>

nextest-metadata/src/test_list.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,12 @@ pub struct BuildPlatformsSummary {
524524
/// In the future, this will become a list of target triples once multiple `--target` arguments
525525
/// are supported.
526526
pub target: PlatformSummary,
527+
528+
/// The sysroot for the target platform.
529+
///
530+
/// Empty if failed to discover.
531+
#[serde(default)]
532+
pub sysroot: Option<Utf8PathBuf>,
527533
}
528534

529535
/// Information about the kind of a Rust non-test binary.

nextest-runner/src/config/test_helpers.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,18 @@ pub(super) fn binary_query<'a>(
8484
}
8585

8686
pub(super) fn build_platforms() -> BuildPlatforms {
87-
BuildPlatforms::new_with_host(
88-
Platform::new("x86_64-unknown-linux-gnu", TargetFeatures::Unknown).unwrap(),
89-
Some(TargetTriple {
87+
BuildPlatforms {
88+
host: Platform::new("x86_64-unknown-linux-gnu", TargetFeatures::Unknown).unwrap(),
89+
target: Some(TargetTriple {
9090
platform: Platform::new("aarch64-apple-darwin", TargetFeatures::Unknown).unwrap(),
9191
source: TargetTripleSource::Env,
9292
location: TargetDefinitionLocation::Builtin,
9393
}),
94-
)
94+
sysroot: Some(
95+
Utf8PathBuf::from("/home/fake/.rustup/toolchains/stable-x86_64-unknown-linux-gnu")
96+
.into_boxed_path(),
97+
),
98+
}
9599
}
96100

97101
pub(super) fn test_group(name: &str) -> TestGroup {

nextest-runner/src/list/binary_list.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,7 @@ mod tests {
398398
use indoc::indoc;
399399
use maplit::btreeset;
400400
use pretty_assertions::assert_eq;
401+
use std::io::Cursor;
401402
use target_spec::{Platform, TargetFeatures};
402403

403404
#[test]
@@ -426,7 +427,9 @@ mod tests {
426427
source: TargetTripleSource::CliOption,
427428
location: TargetDefinitionLocation::Builtin,
428429
};
429-
let build_platforms = BuildPlatforms::new(Some(fake_triple)).unwrap();
430+
let fake_sysroot = "/home/fake/.rustup/toolchains/stable-x86_64-unknown-linux-gnu";
431+
let build_platforms =
432+
BuildPlatforms::new(Some(Cursor::new(fake_sysroot)), Some(fake_triple)).unwrap();
430433

431434
let mut rust_build_meta = RustBuildMeta::new("/fake/target", build_platforms);
432435
rust_build_meta
@@ -504,7 +507,8 @@ mod tests {
504507
"target": {
505508
"triple": "x86_64-unknown-linux-gnu",
506509
"target-features": "unknown"
507-
}
510+
},
511+
"sysroot": "/home/fake/.rustup/toolchains/stable-x86_64-unknown-linux-gnu"
508512
}
509513
],
510514
"target-platforms": [

nextest-runner/src/list/rust_build_meta.rs

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::{
99
reuse_build::PathMapper,
1010
};
1111
use camino::Utf8PathBuf;
12+
use itertools::Itertools;
1213
use nextest_metadata::{RustBuildMetaSummary, RustNonTestBinarySummary};
1314
use std::{
1415
collections::{BTreeMap, BTreeSet},
@@ -95,6 +96,7 @@ impl RustBuildMeta<TestListState> {
9596
build_platforms: BuildPlatforms {
9697
host: Platform::current().unwrap(),
9798
target: None,
99+
sysroot: None,
98100
},
99101
}
100102
}
@@ -109,6 +111,9 @@ impl RustBuildMeta<TestListState> {
109111
// FIXME/HELP WANTED: get the rustc sysroot library path here.
110112
// See https://github.com/nextest-rs/nextest/issues/267.
111113

114+
if self.build_platforms.sysroot.is_none() {
115+
log::warn!("failed to detect the rustc sysroot, may fail to list or run tests");
116+
}
112117
// Cargo puts linked paths before base output directories.
113118
self.linked_paths
114119
.keys()
@@ -127,6 +132,15 @@ impl RustBuildMeta<TestListState> {
127132
// This is the order paths are added in by Cargo.
128133
[with_deps, abs_base]
129134
}))
135+
// Add the rustc path to the search paths to run procudure macro binaries. See
136+
// details in https://github.com/nextest-rs/nextest/issues/1493.
137+
.chain(
138+
self.build_platforms
139+
.sysroot
140+
.as_ref()
141+
.map(|sysroot| sysroot.to_path_buf().join("bin")),
142+
)
143+
.unique()
130144
.collect()
131145
}
132146
}
@@ -180,14 +194,18 @@ mod tests {
180194
use super::*;
181195
use crate::cargo_config::TargetTriple;
182196
use nextest_metadata::BuildPlatformsSummary;
197+
use std::{
198+
fs,
199+
io::{self, Cursor},
200+
};
183201
use target_spec::{summaries::PlatformSummary, Platform};
184202
use test_case::test_case;
185203

186204
impl Default for RustBuildMeta<BinaryListState> {
187205
fn default() -> Self {
188206
RustBuildMeta::<BinaryListState>::new(
189207
Utf8PathBuf::default(),
190-
BuildPlatforms::new(None)
208+
BuildPlatforms::new(None::<io::Empty>, None)
191209
.expect("creating BuildPlatforms without target triple should succeed"),
192210
)
193211
}
@@ -221,6 +239,7 @@ mod tests {
221239
build_platforms: BuildPlatforms {
222240
host: host_platform(),
223241
target: None,
242+
sysroot: None,
224243
},
225244
..Default::default()
226245
}; "no target platforms")]
@@ -231,6 +250,7 @@ mod tests {
231250
build_platforms: BuildPlatforms {
232251
host: host_platform(),
233252
target: Some(x86_64_unknown_linux_gnu_triple()),
253+
sysroot: None,
234254
},
235255
..Default::default()
236256
}; "only target platform field")]
@@ -242,6 +262,7 @@ mod tests {
242262
build_platforms: BuildPlatforms {
243263
host: host_platform(),
244264
target: Some(x86_64_pc_windows_msvc_triple()),
265+
sysroot: None,
245266
},
246267
..Default::default()
247268
}; "target platform and target platforms field")]
@@ -250,12 +271,14 @@ mod tests {
250271
target_platforms: vec![PlatformSummary::new("x86_64-pc-windows-msvc")],
251272
target_platforms_v2: vec![BuildPlatformsSummary {
252273
target: PlatformSummary::new("x86_64-apple-darwin"),
274+
sysroot: Some("/fake/test/sysroot/281".into())
253275
}],
254276
..Default::default()
255277
}, RustBuildMeta::<BinaryListState> {
256278
build_platforms: BuildPlatforms {
257279
host: host_platform(),
258280
target: Some(x86_64_apple_darwin_triple()),
281+
sysroot: Some(Utf8PathBuf::from("/fake/test/sysroot/281").into_boxed_path())
259282
},
260283
..Default::default()
261284
}; "target platform and target platforms and target platforms v2 field")]
@@ -279,32 +302,81 @@ mod tests {
279302
build_platforms: BuildPlatforms {
280303
host: host_platform(),
281304
target: None,
305+
sysroot: None,
282306
},
283307
..Default::default()
284308
}, RustBuildMetaSummary {
285309
target_platform: None,
286310
target_platforms: vec![host_platform().to_summary()],
287311
target_platforms_v2: vec![BuildPlatformsSummary{
288-
target: host_platform().to_summary()
312+
target: host_platform().to_summary(),
313+
sysroot: None,
289314
}],
290315
..Default::default()
291316
}; "build platforms without target")]
292317
#[test_case(RustBuildMeta::<BinaryListState> {
293318
build_platforms: BuildPlatforms {
294319
host: host_platform(),
295320
target: Some(not_host_platform_triple()),
321+
sysroot: Some(Utf8PathBuf::from("/fake/test/sysroot/873").into_boxed_path()),
296322
},
297323
..Default::default()
298324
}, RustBuildMetaSummary {
299325
target_platform: Some(not_host_platform_triple().platform.triple_str().to_owned()),
300326
target_platforms: vec![not_host_platform_triple().platform.to_summary()],
301327
target_platforms_v2: vec![BuildPlatformsSummary{
302-
target: not_host_platform_triple().platform.to_summary()
328+
target: not_host_platform_triple().platform.to_summary(),
329+
sysroot: Some("/fake/test/sysroot/873".into()),
303330
}],
304331
..Default::default()
305332
}; "build platforms with target")]
306333
fn test_to_summary(meta: RustBuildMeta<BinaryListState>, expected: RustBuildMetaSummary) {
307334
let actual = meta.to_summary();
308335
assert_eq!(actual, expected);
309336
}
337+
338+
#[test]
339+
fn test_dylib_paths_should_include_rustc_dir() {
340+
let rust_sysroot = Utf8PathBuf::from("/fake/rustc/sysroot");
341+
let rustc_dir = rust_sysroot.join("bin");
342+
343+
let rust_build_meta = RustBuildMeta {
344+
build_platforms: BuildPlatforms::new(Some(Cursor::new(rust_sysroot.as_str())), None)
345+
.expect("Should create BuildPlatforms with fake sysroot successfully"),
346+
..RustBuildMeta::empty()
347+
};
348+
let dylib_paths = rust_build_meta.dylib_paths();
349+
350+
assert!(
351+
dylib_paths.contains(&rustc_dir),
352+
"{:?} should contain {}",
353+
dylib_paths,
354+
rustc_dir
355+
);
356+
}
357+
358+
#[test]
359+
fn test_dylib_paths_should_not_contain_duplicate_paths() {
360+
let tmpdir = camino_tempfile::tempdir().expect("should create temp dir successfully");
361+
let rust_sysroot = tmpdir.path().to_path_buf();
362+
let rustc_dir = rust_sysroot.join("bin");
363+
fs::create_dir(rustc_dir)
364+
.expect("should create bin directory in the tmp folder successfully");
365+
366+
let rust_build_meta = RustBuildMeta {
367+
target_directory: rust_sysroot.clone(),
368+
linked_paths: [(Utf8PathBuf::from("bin"), Default::default())].into(),
369+
base_output_directories: [Utf8PathBuf::from("bin")].into(),
370+
build_platforms: BuildPlatforms::new(Some(Cursor::new(rust_sysroot.as_str())), None)
371+
.expect("Should create BuildPlatforms with fake sysroot successfully"),
372+
..RustBuildMeta::empty()
373+
};
374+
let dylib_paths = rust_build_meta.dylib_paths();
375+
376+
assert!(
377+
dylib_paths.clone().into_iter().all_unique(),
378+
"{:?} should not contain duplicate paths",
379+
dylib_paths
380+
);
381+
}
310382
}

0 commit comments

Comments
 (0)