use std::fs; use std::process::{self, Command}; use rustc_version::VersionMeta; use tempfile::tempdir; use rustc_build_sysroot::*; fn run(cmd: &mut Command) { assert!(cmd .stdout(process::Stdio::null()) .stderr(process::Stdio::null()) .status() .expect("failed to run {cmd:?}") .success()); } fn build_sysroot(b: SysrootBuilder) { let src_dir = rustc_sysroot_src(Command::new("rustc")).unwrap(); b.cargo(Command::new("cargo")) .build_from_source(&src_dir) .unwrap(); } fn test_sysroot_build(target: &str, mode: BuildMode, rustc_version: &VersionMeta) { let sysroot_dir = tempdir().unwrap(); build_sysroot( SysrootBuilder::new(sysroot_dir.path(), target) .build_mode(mode) .rustc_version(rustc_version.clone()), ); let crate_name = "rustc-build-sysroot-test-crate"; let crate_dir = tempdir().unwrap(); run(Command::new("cargo") .args(["new", crate_name]) .current_dir(&crate_dir)); let crate_dir = crate_dir.path().join(crate_name); run(Command::new("cargo") .arg(mode.as_str()) .arg("--target") .arg(target) .current_dir(&crate_dir) .env( "RUSTFLAGS", format!("--sysroot {}", sysroot_dir.path().display()), )); if mode == BuildMode::Build && target == rustc_version.host { run(Command::new("cargo") .arg("run") .current_dir(&crate_dir) .env( "RUSTFLAGS", format!("--sysroot {}", sysroot_dir.path().display()), )); } } #[test] fn host() { let rustc_version = VersionMeta::for_command(Command::new("rustc")).unwrap(); for mode in [BuildMode::Build, BuildMode::Check] { test_sysroot_build(&rustc_version.host, mode, &rustc_version); } } #[test] fn cross() { let rustc_version = VersionMeta::for_command(Command::new("rustc")).unwrap(); // Cover three CPU architectures and three OSes. for target in [ "i686-unknown-linux-gnu", "aarch64-apple-darwin", "x86_64-pc-windows-msvc", ] { test_sysroot_build(target, BuildMode::Check, &rustc_version); } } #[test] fn no_std() { let sysroot_dir = tempdir().unwrap(); build_sysroot( SysrootBuilder::new(sysroot_dir.path(), "thumbv7em-none-eabihf") .build_mode(BuildMode::Check) .sysroot_config(SysrootConfig::NoStd), ); } #[test] fn json_target() { // Example taken from https://book.avr-rust.com/005.1-the-target-specification-json-file.html let target = r#"{ "arch": "avr", "cpu": "atmega328p", "data-layout": "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8", "env": "", "executables": true, "linker": "avr-gcc", "linker-flavor": "gcc", "linker-is-gnu": true, "llvm-target": "avr-unknown-unknown", "no-compiler-rt": true, "os": "unknown", "position-independent-executables": false, "exe-suffix": ".elf", "eh-frame-header": false, "pre-link-args": { "gcc": ["-mmcu=atmega328p"] }, "late-link-args": { "gcc": ["-lgcc"] }, "target-c-int-width": "16", "target-endian": "little", "target-pointer-width": "16", "vendor": "unknown" }"#; let sysroot_dir = tempdir().unwrap(); let target_file = sysroot_dir.path().join("mytarget.json"); fs::write(&target_file, target).unwrap(); build_sysroot( SysrootBuilder::new(sysroot_dir.path(), &target_file) .build_mode(BuildMode::Check) .sysroot_config(SysrootConfig::NoStd), ); }