Skip to content

Commit

Permalink
Add rustc folder to dynamic linker search path
Browse files Browse the repository at this point in the history
... 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.
  • Loading branch information
06393993 committed May 14, 2024
1 parent 627e282 commit ccf511a
Show file tree
Hide file tree
Showing 21 changed files with 345 additions and 44 deletions.
36 changes: 35 additions & 1 deletion cargo-nextest/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use std::{
collections::BTreeSet,
env::VarError,
io::{Cursor, Write},
path::PathBuf,
sync::Arc,
};
use swrite::{swrite, SWrite};
Expand Down Expand Up @@ -1009,7 +1010,31 @@ impl BaseApp {
None => {
let target_triple =
discover_target_triple(&cargo_configs, cargo_opts.target.as_deref());
BuildPlatforms::new(target_triple)?
let mut args = vec!["--print", "sysroot"];
if let Some(target_triple) = &target_triple {
args.extend(["--target", target_triple.platform.triple_str()]);

Check warning on line 1015 in cargo-nextest/src/dispatch.rs

View check run for this annotation

Codecov / codecov/patch

cargo-nextest/src/dispatch.rs#L1015

Added line #L1015 was not covered by tests
}
let output = duct::cmd(rustc_path().as_str(), args)
.stdout_capture()
.unchecked()
.run()
.ok()
.and_then(|output| {
if output.status.success() {
Some(Cursor::new(output.stdout))
} else {
log::debug!(
"failed to execute sysroot discover command: {}",

Check warning on line 1027 in cargo-nextest/src/dispatch.rs

View check run for this annotation

Codecov / codecov/patch

cargo-nextest/src/dispatch.rs#L1026-L1027

Added lines #L1026 - L1027 were not covered by tests
output.status
);
log::debug!("stdout:");
log::debug!("{}", String::from_utf8_lossy(&output.stdout));
log::debug!("stderr:");
log::debug!("{}", String::from_utf8_lossy(&output.stderr));
None

Check warning on line 1034 in cargo-nextest/src/dispatch.rs

View check run for this annotation

Codecov / codecov/patch

cargo-nextest/src/dispatch.rs#L1030-L1034

Added lines #L1030 - L1034 were not covered by tests
}
});
BuildPlatforms::new(output, target_triple)?
}
};

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

fn rustc_path() -> Utf8PathBuf {
match std::env::var_os("RUSTC") {
Some(rustc_path) => PathBuf::from(rustc_path)
.try_into()
.expect("RUSTC env var is not valid UTF-8"),

Check warning on line 2044 in cargo-nextest/src/dispatch.rs

View check run for this annotation

Codecov / codecov/patch

cargo-nextest/src/dispatch.rs#L2042-L2044

Added lines #L2042 - L2044 were not covered by tests
None => Utf8PathBuf::from("rustc"),
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
4 changes: 4 additions & 0 deletions fixtures/nextest-tests/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions fixtures/nextest-tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ members = [
"derive",
"dylib-test",
"with-build-script",
"proc-macro-test"
]

[dependencies]
Expand Down
7 changes: 7 additions & 0 deletions fixtures/nextest-tests/proc-macro-test/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "proc-macro-test"
version = "0.1.0"
edition = "2021"

[lib]
proc-macro = true
Empty file.
16 changes: 15 additions & 1 deletion integration-tests/tests/integration/fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ pub static EXPECTED_LIST: Lazy<Vec<TestInfo>> = Lazy::new(|| {
BuildPlatform::Target,
vec![("tests::test_out_dir_present", false)],
),
TestInfo::new("proc-macro-test", BuildPlatform::Host, vec![]),
]
});

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

let test_suite = &*EXPECTED_LIST;
assert_eq!(test_suite.len(), result.rust_binaries.len());
let mut expected_binary_ids = test_suite
.iter()
.map(|test_info| test_info.id.clone())
.collect::<Vec<_>>();
expected_binary_ids.sort();
let mut actual_binary_ids = result.rust_binaries.keys().collect::<Vec<_>>();
actual_binary_ids.sort();
assert_eq!(
test_suite.len(),
result.rust_binaries.len(),
"expected rust binaries:\n{:?}\nactual rust binaries\n{:?}",
expected_binary_ids,
actual_binary_ids
);

for test in test_suite {
let entry = result
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
source: integration-tests/tests/integration/main.rs
expression: output.stderr_as_str()
---
Archiving 16 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 7 extra paths to <archive-file>
Archiving 17 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 7 extra paths to <archive-file>
Warning ignoring extra path `<target-dir>/excluded-dir` because it does not exist
Warning ignoring extra path `<target-dir>/depth-0-dir` specified with depth 0 since it is a directory
Warning ignoring extra path `<target-dir>/file_that_does_not_exist.txt` because it does not exist
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
source: integration-tests/tests/integration/main.rs
expression: output.stderr_as_str()
---
Archiving 16 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 7 extra paths to <archive-file>
Archiving 17 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 7 extra paths to <archive-file>
Warning ignoring extra path `<target-dir>/excluded-dir` because it does not exist
Warning ignoring extra path `<target-dir>/depth-0-dir` specified with depth 0 since it is a directory
Warning ignoring extra path `<target-dir>/file_that_does_not_exist.txt` because it does not exist
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
source: integration-tests/tests/integration/main.rs
expression: output.stderr_as_str()
---
Archiving 16 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 1 extra path to <archive-file>
Archiving 17 binaries (including 2 non-test binaries), 2 build script output directories, 2 linked paths, and 1 extra path to <archive-file>
error: error creating archive `<archive-file>`

Caused by:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
source: integration-tests/tests/integration/main.rs
expression: output.stderr_as_str()
---
Archiving 16 binaries (including 2 non-test binaries), 2 build script output directories, and 2 linked paths to <archive-file>
Archiving 17 binaries (including 2 non-test binaries), 2 build script output directories, and 2 linked paths to <archive-file>
Warning linked path `<target-dir>/debug/build/<cdylib-link-hash>/does-not-exist` not found, requested by: cdylib-link v0.1.0
(this is a bug in this crate that should be fixed)
Archived <file-count> files to <archive-file> in <duration>
6 changes: 6 additions & 0 deletions nextest-metadata/src/test_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,12 @@ pub struct BuildPlatformsSummary {
/// In the future, this will become a list of target triples once multiple `--target` arguments
/// are supported.
pub target: PlatformSummary,

/// The sysroot for the target platform.
///
/// Empty if failed to discover.
#[serde(default)]
pub sysroot: Option<Utf8PathBuf>,
}

/// Information about the kind of a Rust non-test binary.
Expand Down
12 changes: 8 additions & 4 deletions nextest-runner/src/config/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,18 @@ pub(super) fn binary_query<'a>(
}

pub(super) fn build_platforms() -> BuildPlatforms {
BuildPlatforms::new_with_host(
Platform::new("x86_64-unknown-linux-gnu", TargetFeatures::Unknown).unwrap(),
Some(TargetTriple {
BuildPlatforms {
host: Platform::new("x86_64-unknown-linux-gnu", TargetFeatures::Unknown).unwrap(),
target: Some(TargetTriple {
platform: Platform::new("aarch64-apple-darwin", TargetFeatures::Unknown).unwrap(),
source: TargetTripleSource::Env,
location: TargetDefinitionLocation::Builtin,
}),
)
sysroot: Some(
Utf8PathBuf::from("/home/fake/.rustup/toolchains/stable-x86_64-unknown-linux-gnu")
.into_boxed_path(),
),
}
}

pub(super) fn test_group(name: &str) -> TestGroup {
Expand Down
8 changes: 6 additions & 2 deletions nextest-runner/src/list/binary_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ mod tests {
use indoc::indoc;
use maplit::btreeset;
use pretty_assertions::assert_eq;
use std::io::Cursor;
use target_spec::{Platform, TargetFeatures};

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

let mut rust_build_meta = RustBuildMeta::new("/fake/target", build_platforms);
rust_build_meta
Expand Down Expand Up @@ -504,7 +507,8 @@ mod tests {
"target": {
"triple": "x86_64-unknown-linux-gnu",
"target-features": "unknown"
}
},
"sysroot": "/home/fake/.rustup/toolchains/stable-x86_64-unknown-linux-gnu"
}
],
"target-platforms": [
Expand Down
78 changes: 75 additions & 3 deletions nextest-runner/src/list/rust_build_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{
reuse_build::PathMapper,
};
use camino::Utf8PathBuf;
use itertools::Itertools;
use nextest_metadata::{RustBuildMetaSummary, RustNonTestBinarySummary};
use std::{
collections::{BTreeMap, BTreeSet},
Expand Down Expand Up @@ -95,6 +96,7 @@ impl RustBuildMeta<TestListState> {
build_platforms: BuildPlatforms {
host: Platform::current().unwrap(),
target: None,
sysroot: None,
},
}
}
Expand All @@ -109,6 +111,9 @@ impl RustBuildMeta<TestListState> {
// FIXME/HELP WANTED: get the rustc sysroot library path here.
// See https://github.com/nextest-rs/nextest/issues/267.

if self.build_platforms.sysroot.is_none() {
log::warn!("failed to detect the rustc sysroot, may fail to list or run tests");
}
// Cargo puts linked paths before base output directories.
self.linked_paths
.keys()
Expand All @@ -127,6 +132,15 @@ impl RustBuildMeta<TestListState> {
// This is the order paths are added in by Cargo.
[with_deps, abs_base]
}))
// Add the rustc path to the search paths to run procudure macro binaries. See
// details in https://github.com/nextest-rs/nextest/issues/1493.
.chain(
self.build_platforms
.sysroot
.as_ref()
.map(|sysroot| sysroot.to_path_buf().join("bin")),
)
.unique()
.collect()
}
}
Expand Down Expand Up @@ -180,14 +194,18 @@ mod tests {
use super::*;
use crate::cargo_config::TargetTriple;
use nextest_metadata::BuildPlatformsSummary;
use std::{
fs,
io::{self, Cursor},
};
use target_spec::{summaries::PlatformSummary, Platform};
use test_case::test_case;

impl Default for RustBuildMeta<BinaryListState> {
fn default() -> Self {
RustBuildMeta::<BinaryListState>::new(
Utf8PathBuf::default(),
BuildPlatforms::new(None)
BuildPlatforms::new(None::<io::Empty>, None)
.expect("creating BuildPlatforms without target triple should succeed"),
)
}
Expand Down Expand Up @@ -221,6 +239,7 @@ mod tests {
build_platforms: BuildPlatforms {
host: host_platform(),
target: None,
sysroot: None,
},
..Default::default()
}; "no target platforms")]
Expand All @@ -231,6 +250,7 @@ mod tests {
build_platforms: BuildPlatforms {
host: host_platform(),
target: Some(x86_64_unknown_linux_gnu_triple()),
sysroot: None,
},
..Default::default()
}; "only target platform field")]
Expand All @@ -242,6 +262,7 @@ mod tests {
build_platforms: BuildPlatforms {
host: host_platform(),
target: Some(x86_64_pc_windows_msvc_triple()),
sysroot: None,
},
..Default::default()
}; "target platform and target platforms field")]
Expand All @@ -250,12 +271,14 @@ mod tests {
target_platforms: vec![PlatformSummary::new("x86_64-pc-windows-msvc")],
target_platforms_v2: vec![BuildPlatformsSummary {
target: PlatformSummary::new("x86_64-apple-darwin"),
sysroot: Some("/fake/test/sysroot/281".into())
}],
..Default::default()
}, RustBuildMeta::<BinaryListState> {
build_platforms: BuildPlatforms {
host: host_platform(),
target: Some(x86_64_apple_darwin_triple()),
sysroot: Some(Utf8PathBuf::from("/fake/test/sysroot/281").into_boxed_path())
},
..Default::default()
}; "target platform and target platforms and target platforms v2 field")]
Expand All @@ -279,32 +302,81 @@ mod tests {
build_platforms: BuildPlatforms {
host: host_platform(),
target: None,
sysroot: None,
},
..Default::default()
}, RustBuildMetaSummary {
target_platform: None,
target_platforms: vec![host_platform().to_summary()],
target_platforms_v2: vec![BuildPlatformsSummary{
target: host_platform().to_summary()
target: host_platform().to_summary(),
sysroot: None,
}],
..Default::default()
}; "build platforms without target")]
#[test_case(RustBuildMeta::<BinaryListState> {
build_platforms: BuildPlatforms {
host: host_platform(),
target: Some(not_host_platform_triple()),
sysroot: Some(Utf8PathBuf::from("/fake/test/sysroot/873").into_boxed_path()),
},
..Default::default()
}, RustBuildMetaSummary {
target_platform: Some(not_host_platform_triple().platform.triple_str().to_owned()),
target_platforms: vec![not_host_platform_triple().platform.to_summary()],
target_platforms_v2: vec![BuildPlatformsSummary{
target: not_host_platform_triple().platform.to_summary()
target: not_host_platform_triple().platform.to_summary(),
sysroot: Some("/fake/test/sysroot/873".into()),
}],
..Default::default()
}; "build platforms with target")]
fn test_to_summary(meta: RustBuildMeta<BinaryListState>, expected: RustBuildMetaSummary) {
let actual = meta.to_summary();
assert_eq!(actual, expected);
}

#[test]
fn test_dylib_paths_should_include_rustc_dir() {
let rust_sysroot = Utf8PathBuf::from("/fake/rustc/sysroot");
let rustc_dir = rust_sysroot.join("bin");

let rust_build_meta = RustBuildMeta {
build_platforms: BuildPlatforms::new(Some(Cursor::new(rust_sysroot.as_str())), None)
.expect("Should create BuildPlatforms with fake sysroot successfully"),
..RustBuildMeta::empty()
};
let dylib_paths = rust_build_meta.dylib_paths();

assert!(
dylib_paths.contains(&rustc_dir),
"{:?} should contain {}",

Check warning on line 352 in nextest-runner/src/list/rust_build_meta.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/list/rust_build_meta.rs#L352

Added line #L352 was not covered by tests
dylib_paths,
rustc_dir
);
}

#[test]
fn test_dylib_paths_should_not_contain_duplicate_paths() {
let tmpdir = camino_tempfile::tempdir().expect("should create temp dir successfully");
let rust_sysroot = tmpdir.path().to_path_buf();
let rustc_dir = rust_sysroot.join("bin");
fs::create_dir(rustc_dir)
.expect("should create bin directory in the tmp folder successfully");

let rust_build_meta = RustBuildMeta {
target_directory: rust_sysroot.clone(),
linked_paths: [(Utf8PathBuf::from("bin"), Default::default())].into(),
base_output_directories: [Utf8PathBuf::from("bin")].into(),
build_platforms: BuildPlatforms::new(Some(Cursor::new(rust_sysroot.as_str())), None)
.expect("Should create BuildPlatforms with fake sysroot successfully"),
..RustBuildMeta::empty()
};
let dylib_paths = rust_build_meta.dylib_paths();

assert!(
dylib_paths.clone().into_iter().all_unique(),
"{:?} should not contain duplicate paths",

Check warning on line 378 in nextest-runner/src/list/rust_build_meta.rs

View check run for this annotation

Codecov / codecov/patch

nextest-runner/src/list/rust_build_meta.rs#L378

Added line #L378 was not covered by tests
dylib_paths
);
}
}
Loading

0 comments on commit ccf511a

Please sign in to comment.