diff --git a/CHANGELOG.md b/CHANGELOG.md index 1628929c..8601ab6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +* Passing `--target` to build command when cross-compiling. + ### Changed ### Removed diff --git a/src/config.rs b/src/config.rs index 63849fed..b9f9b82f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -258,6 +258,11 @@ impl Config { Ok(()) } + /// Check whether the host is the specified string + pub fn host_matches(&self, target: &str) -> bool { + self.host.as_ref().expect("host should have been filled in") == target + } + pub(crate) fn has_asm_support(&self) -> bool { static ASM_SUPPORTED_ARCHS: &[&str] = &[ "x86", "x86_64", "arm", "aarch64", "riscv32", diff --git a/src/lib.rs b/src/lib.rs index 6b27ba41..b1f74d85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,18 +170,44 @@ pub fn default_any_file_filter(path: &Path, config: &Config) -> bool { /// The default per-file config used by `run_tests`. pub fn default_per_file_config(config: &mut Config, _path: &Path, file_contents: &[u8]) { - // Heuristic: - // * if the file contains `#[test]`, automatically pass `--cfg test`. - // * if the file does not contain `fn main()` or `#[start]`, automatically pass `--crate-type=lib`. - // This avoids having to spam `fn main() {}` in almost every test. + config.program.args.push( + match crate_type(file_contents) { + CrateType::ProcMacro => "--crate-type=proc-macro", + CrateType::Test => "--test", + CrateType::Bin => return, + CrateType::Lib => "--crate-type=lib", + } + .into(), + ) +} + +/// The kind of crate we're building here. Corresponds to `--crate-type` flags of rustc +pub enum CrateType { + /// A proc macro + ProcMacro, + /// A file containing unit tests + Test, + /// A binary file containing a main function or start function + Bin, + /// A library crate + Lib, +} + +/// Heuristic: +/// * if the file contains `#[test]`, automatically pass `--cfg test`. +/// * if the file does not contain `fn main()` or `#[start]`, automatically pass `--crate-type=lib`. +/// This avoids having to spam `fn main() {}` in almost every test. +pub fn crate_type(file_contents: &[u8]) -> CrateType { if file_contents.find(b"#[proc_macro").is_some() { - config.program.args.push("--crate-type=proc-macro".into()) + CrateType::ProcMacro } else if file_contents.find(b"#[test]").is_some() { - config.program.args.push("--test".into()); + CrateType::Test } else if file_contents.find(b"fn main()").is_none() && file_contents.find(b"#[start]").is_none() { - config.program.args.push("--crate-type=lib".into()); + CrateType::Lib + } else { + CrateType::Bin } } @@ -520,6 +546,15 @@ fn build_command( cmd.arg("--edition").arg(&*edition); } + if let Some(target) = &config.target { + // Adding a `--target` arg to calls to Cargo will cause target folders + // to create a target-specific sub-folder. We can avoid that by just + // not passing a `--target` arg if its the same as the host. + if !config.host_matches(target) { + cmd.arg("--target").arg(target); + } + } + // False positive in miri, our `map` uses a ref pattern to get the references to the tuple fields instead // of a reference to a tuple #[allow(clippy::map_identity)] @@ -574,6 +609,12 @@ fn build_aux( default_per_file_config(&mut config, aux_file, &file_contents); + match crate_type(&file_contents) { + // Proc macros must be run on the host + CrateType::ProcMacro => config.target = config.host.clone(), + CrateType::Test | CrateType::Bin | CrateType::Lib => {} + } + // Put aux builds into a separate directory per path so that multiple aux files // from different directories (but with the same file name) don't collide. let relative = strip_path_prefix(aux_file.parent().unwrap(), &config.out_dir); @@ -1281,7 +1322,7 @@ fn test_condition(condition: &Condition, config: &Config) -> bool { Condition::Bitwidth(bits) => get_pointer_width(target) == *bits, Condition::Target(t) => target.contains(t), Condition::Host(t) => config.host.as_ref().unwrap().contains(t), - Condition::OnHost => target == config.host.as_ref().unwrap(), + Condition::OnHost => config.host_matches(target), } } diff --git a/tests/integration.rs b/tests/integration.rs index d1b5e4ef..4b414290 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -82,6 +82,11 @@ fn main() -> Result<()> { config.filter("program not found", "No such file or directory"); config.filter(" \\(os error [0-9]+\\)", ""); config.filter("note: rustc 1\\..*", ""); + // Cross compilation paths contain an additional target directory name + config.stderr_filter( + "(/target/ui/tests/integrations/[^/]+).*debug/deps", + "$1/debug/deps", + ); let text = ui_test::status_emitter::Text::from(args.format); diff --git a/tests/integrations/basic/tests/ui_tests.rs b/tests/integrations/basic/tests/ui_tests.rs index 321f7c84..45129138 100644 --- a/tests/integrations/basic/tests/ui_tests.rs +++ b/tests/integrations/basic/tests/ui_tests.rs @@ -17,6 +17,11 @@ fn main() -> ui_test::color_eyre::Result<()> { config.stderr_filter(r"[^ ]*/\.?cargo/registry/.*/", "$$CARGO_REGISTRY"); config.path_stderr_filter(&std::path::Path::new(path), "$DIR"); + if let Ok(target) = std::env::var("UITEST_TEST_TARGET") { + config.target = Some(target); + config.output_conflict_handling = OutputConflictHandling::Ignore; + } + // hide binaries generated for successfully passing tests let tmp_dir = tempfile::tempdir_in(path)?; let tmp_dir = tmp_dir.path();