diff --git a/README.md b/README.md index 2386915..d117007 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,16 @@ RUSTUP_TOOLCHAIN=stable cargo install espup --locked ``` ```bash -espup install +espup install --toolchain-version 1.93.0.0 ``` +Pin the toolchain to 1.93.0.0. Newer esp toolchains (1.94.x, 1.95.x) +ship LLVM 21, whose Xtensa backend miscompiles optimized builds and +aborts with `rustc-LLVM ERROR: Cannot select ... XtensaISD::PCREL_WRAPPER`. +1.93.0.0 (LLVM 20) is the last known-good version. `build.rs` refuses to +build on the affected toolchains, so an accidental `espup update` fails +fast with the same instructions instead of a cryptic backend crash. + ### Install flashing tools ```bash cargo install cargo-espflash espflash --locked diff --git a/build.rs b/build.rs index f164761..ba33913 100644 --- a/build.rs +++ b/build.rs @@ -1,10 +1,48 @@ fn main() { linker_be_nice(); + check_llvm_version(); println!("cargo:rustc-link-arg=-Tdefmt.x"); // make sure linkall.x is the last linker script (otherwise might cause problems with flip-link) println!("cargo:rustc-link-arg=-Tlinkall.x"); } +// esp toolchains built on LLVM 21 (Xtensa Rust 1.94.x / 1.95.x) fail to +// compile release builds for the Xtensa target: the backend can't select +// XtensaISD::PCREL_WRAPPER for a constant-pool string reference and aborts +// with `rustc-LLVM ERROR: Cannot select`. LLVM 20 (Xtensa Rust 1.93.0.0) is +// the last good version. Turn that cryptic crash into an actionable message. +// Revisit the version bound once esp-rs ships a fixed LLVM 21. +fn check_llvm_version() { + let rustc = std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into()); + let output = match std::process::Command::new(&rustc) + .args(["--version", "--verbose"]) + .output() + { + Ok(output) => output, + // Can't probe rustc; don't block the build over it. + Err(_) => return, + }; + + let major = String::from_utf8_lossy(&output.stdout) + .lines() + .find_map(|line| line.strip_prefix("LLVM version:")) + .and_then(|version| version.trim().split('.').next()) + .and_then(|major| major.parse::().ok()); + + if let Some(major) = major { + if major >= 21 { + eprintln!(); + eprintln!("This esp toolchain bundles LLVM {major}, which miscompiles optimized"); + eprintln!("Xtensa builds (XtensaISD::PCREL_WRAPPER cannot be selected). Install the"); + eprintln!("last known-good toolchain:"); + eprintln!(); + eprintln!(" espup install --toolchain-version 1.93.0.0"); + eprintln!(); + std::process::exit(1); + } + } +} + fn linker_be_nice() { let args: Vec = std::env::args().collect(); if args.len() > 1 {