#!/usr/bin/env -S cargo +nightly -Zscript
---
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
[package]
edition = "2024"
[dependencies]
argh = "0.1"
---
use std::env;
use std::path::Path;
use std::process::{Command, ExitCode};
use argh::FromArgs;
const PACKAGE: &str = "multitude";
const MIRI_CONFIGS: &[MiriConfig] = &[
MiriConfig {
label: "stacked borrows",
flags: "",
},
MiriConfig {
label: "tree borrows",
flags: "-Zmiri-tree-borrows",
},
MiriConfig {
label: "strict provenance",
flags: "-Zmiri-strict-provenance",
},
MiriConfig {
label: "race coverage",
flags: "-Zmiri-many-seeds=0..32",
},
];
struct MiriConfig {
label: &'static str,
flags: &'static str,
}
#[derive(FromArgs)]
struct Args {
#[argh(switch)]
miri: bool,
#[argh(switch)]
loom: bool,
#[argh(switch)]
bolero: bool,
#[argh(switch)]
careful: bool,
}
struct Toolchains {
nightly: String,
latest: String,
}
fn main() -> ExitCode {
let args: Args = argh::from_env();
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let workspace_root = manifest_dir
.ancestors()
.find(|p| p.join("Cargo.lock").exists())
.expect("could not locate workspace root (no Cargo.lock found)")
.to_path_buf();
let toolchains = load_toolchains(&workspace_root);
let run_all = !args.miri && !args.loom && !args.bolero && !args.careful;
println!();
println!("=== Multitude Correctness Suite ===");
println!();
println!("Toolchains:");
println!(" Nightly: {}", toolchains.nightly);
println!(" Latest: {}", toolchains.latest);
let mut failures: Vec<String> = Vec::new();
if run_all || args.miri {
for config in MIRI_CONFIGS {
run_miri(&workspace_root, &toolchains, config, &mut failures);
}
}
if run_all || args.loom {
run_loom(&workspace_root, &toolchains, &mut failures);
}
if run_all || args.bolero {
run_bolero(&workspace_root, &toolchains, &mut failures);
}
if run_all || args.careful {
run_careful(&workspace_root, &toolchains, &mut failures);
}
println!();
println!("=====================================");
if failures.is_empty() {
println!("✅ All correctness checks passed!");
ExitCode::SUCCESS
} else {
eprintln!("❌ {} check(s) failed:", failures.len());
for f in &failures {
eprintln!(" - {f}");
}
ExitCode::FAILURE
}
}
fn run_miri(root: &Path, tc: &Toolchains, config: &MiriConfig, failures: &mut Vec<String>) {
let label = format!("Miri ({})", config.label);
let mut cmd = cargo(root, &tc.nightly);
cmd.args(["miri", "nextest", "run", "--all-features", "-p", PACKAGE, "--lib", "--tests"]);
if config.flags.is_empty() {
cmd.env_remove("MIRIFLAGS");
} else {
cmd.env("MIRIFLAGS", config.flags);
}
run_step(&label, cmd, failures);
}
fn run_loom(root: &Path, tc: &Toolchains, failures: &mut Vec<String>) {
let mut rustflags = env::var("RUSTFLAGS").unwrap_or_default();
if !rustflags.is_empty() {
rustflags.push(' ');
}
rustflags.push_str("--cfg loom");
let mut cmd = cargo(root, &tc.latest);
cmd.args([
"test",
"--release",
"-p",
PACKAGE,
"--test",
"loom",
"--locked",
"--",
"--test-threads=1",
]);
cmd.env("RUSTFLAGS", &rustflags);
run_step("Loom", cmd, failures);
}
fn run_bolero(root: &Path, tc: &Toolchains, failures: &mut Vec<String>) {
let mut cmd = cargo(root, &tc.nightly);
cmd.args(["test", "-p", PACKAGE, "--test", "bolero", "--all-features", "--locked"]);
run_step("Bolero", cmd, failures);
}
fn run_careful(root: &Path, tc: &Toolchains, failures: &mut Vec<String>) {
let mut cmd = cargo(root, &tc.nightly);
cmd.args(["careful", "nextest", "run", "--all-features", "-p", PACKAGE]);
run_step("cargo-careful", cmd, failures);
}
fn cargo(workspace_root: &Path, toolchain: &str) -> Command {
let mut cmd = Command::new("cargo");
cmd.arg(format!("+{toolchain}"));
cmd.current_dir(workspace_root);
cmd
}
fn run_step(label: &str, mut cmd: Command, failures: &mut Vec<String>) {
let display = format_cmd(&cmd);
println!();
println!("--- {label} ---");
println!("{display}");
match cmd.status() {
Ok(status) if status.success() => {
println!("✅ {label}");
}
Ok(status) => {
eprintln!("❌ {label} (exit code: {:?})", status.code());
failures.push(label.to_string());
}
Err(e) => {
eprintln!("❌ {label}: failed to execute: {e}");
failures.push(label.to_string());
}
}
}
fn format_cmd(cmd: &Command) -> String {
let mut parts = Vec::new();
for (key, value) in cmd.get_envs() {
if let Some(val) = value {
parts.push(format!("{}={}", key.to_string_lossy(), val.to_string_lossy()));
}
}
parts.push(cmd.get_program().to_string_lossy().into_owned());
for arg in cmd.get_args() {
parts.push(arg.to_string_lossy().into_owned());
}
parts.join(" ")
}
fn load_toolchains(workspace_root: &Path) -> Toolchains {
let env_path = workspace_root.join("constants.env");
let content = std::fs::read_to_string(&env_path).unwrap_or_else(|e| panic!("failed to read {}: {e}", env_path.display()));
let mut nightly = None;
let mut latest = None;
for line in content.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
if let Some((key, value)) = line.split_once('=') {
match key.trim() {
"RUST_NIGHTLY" => nightly = Some(value.trim().to_string()),
"RUST_LATEST" => latest = Some(value.trim().to_string()),
_ => {}
}
}
}
Toolchains {
nightly: nightly.expect("RUST_NIGHTLY not found in constants.env"),
latest: latest.expect("RUST_LATEST not found in constants.env"),
}
}