blob: 99cb9f9b0f4d4f3b41a160a91206c99975d97060 [file] [log] [blame] [edit]
// This test ensures we are able to compile -Zbuild-std=core under a variety of profiles.
// Currently, it tests that we can compile to all Tier 1 targets, and it does this by checking what
// the tier metadata in target-spec JSON. This means that all in-tree targets must have a tier set.
#![deny(warnings)]
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;
use run_make_support::serde_json::{self, Value};
use run_make_support::tempfile::TempDir;
use run_make_support::{cargo, rfs, rustc};
#[derive(Clone)]
struct Task {
target: String,
opt_level: u8,
debug: u8,
panic: &'static str,
}
fn manifest(task: &Task) -> String {
let Task { opt_level, debug, panic, target: _ } = task;
format!(
r#"[package]
name = "scratch"
version = "0.1.0"
edition = "2024"
[lib]
path = "lib.rs"
[profile.release]
opt-level = {opt_level}
debug = {debug}
panic = "{panic}"
"#
)
}
fn main() {
let mut targets = Vec::new();
let all_targets =
rustc().args(&["--print=all-target-specs-json", "-Zunstable-options"]).run().stdout_utf8();
let all_targets: HashMap<String, Value> = serde_json::from_str(&all_targets).unwrap();
for (target, spec) in all_targets {
let metadata = spec.as_object().unwrap()["metadata"].as_object().unwrap();
let tier = metadata["tier"]
.as_u64()
.expect(&format!("Target {} is missing tier metadata", target));
if tier == 1 {
targets.push(target);
}
}
let mut tasks = Vec::new();
// Testing every combination of compiler flags is infeasible. So we are making some attempt to
// choose combinations that will tend to run into problems.
//
// The particular combination of settings below is tuned to look for problems generating the
// code for compiler-builtins.
// We only exercise opt-level 0 and 3 to exercise mir-opt-level 1 and 2.
// We only exercise debug 0 and 2 because level 2 turns off some MIR optimizations.
// We only test abort and immediate-abort because abort vs unwind doesn't change MIR much at
// all. but immediate-abort does.
//
// Currently this only tests that we can compile the tier 1 targets. But since we are using
// -Zbuild-std=core, we could have any list of targets.
for opt_level in [0, 3] {
for debug in [0, 2] {
for panic in ["abort", "immediate-abort"] {
for target in &targets {
tasks.push(Task { target: target.clone(), opt_level, debug, panic });
}
}
}
}
let tasks = Arc::new(Mutex::new(tasks));
let mut threads = Vec::new();
// Try to obey the -j argument passed to bootstrap, otherwise fall back to using all the system
// resouces. This test can be rather memory-hungry (~1 GB/thread); if it causes trouble in
// practice do not hesitate to limit its parallelism.
for _ in 0..run_make_support::env::jobs() {
let tasks = Arc::clone(&tasks);
let handle = thread::spawn(move || {
loop {
let maybe_task = tasks.lock().unwrap().pop();
if let Some(task) = maybe_task {
test(task);
} else {
break;
}
}
});
threads.push(handle);
}
for t in threads {
t.join().unwrap();
}
}
fn test(task: Task) {
let dir = TempDir::new().unwrap();
let manifest = manifest(&task);
rfs::write(dir.path().join("Cargo.toml"), &manifest);
rfs::write(dir.path().join("lib.rs"), "#![no_std]");
let mut args = vec!["build", "--release", "-Zbuild-std=core", "--target", &task.target, "-j1"];
if task.panic == "immediate-abort" {
args.push("-Zpanic-immediate-abort");
}
cargo()
.current_dir(dir.path())
.args(&args)
.env("RUSTC_BOOTSTRAP", "1")
// Visual Studio 2022 requires that the LIB env var be set so it can
// find the Windows SDK.
.env("LIB", std::env::var("LIB").unwrap_or_default())
.context(&format!(
"build-std for target `{}` failed with the following Cargo.toml:\n\n{manifest}",
task.target
))
.run();
}