编译no_std二进制文件时rustc无限挂起问题求助
spin::Mutex in Rust OS Development Hey there, let's break down the compiler hang issue you're facing while working through Writing an Operating System in Rust 2nd Edition, Chapter 3. Even your simplified code gives us clues about the underlying problems—let's tackle them step by step.
1. First, Fix the Obsolete Atomic Initializer
Your simplified code uses ATOMIC_BOOL_INIT, which has been deprecated since Rust 1.34. This isn't the direct cause of the compiler hang, but it's a critical cleanup that avoids warnings and potential edge cases. Replace it with the const-safe constructor:
use core::sync::atomic::{Ordering, AtomicBool}; const ATOMIC_BOOL: AtomicBool = AtomicBool::new(false); #[no_mangle] pub extern "C" fn _start() -> ! { ATOMIC_BOOL.store(true, Ordering::SeqCst); loop {} }
2. The Root Cause: Static spin::Mutex Initialization
The compiler hang you're seeing with static spin::Mutex almost always stems from one of two issues in no_std environments:
- Old
spincrate versions: Earlier versions of thespincrate didn't support const-safe constructors forMutex, forcing the compiler to handle runtime initialization during static setup—a process that can trigger infinite loops in the compiler's type checker. - Missing const initialization support: Static variables in Rust require compile-time constant values unless you use lazy initialization.
Fixes for Static spin::Mutex:
Option A: Use a spin Version with Const Constructors
Update your Cargo.toml to use spin 0.9 or later (these versions added const-safe Mutex::new):
[dependencies] spin = "0.9"
Then define your static mutex like this (no compiler hang, since it's initialized at compile time):
static MUTEX: spin::Mutex<u32> = spin::Mutex::new(0);
Option B: Lazy Initialization (For Older spin Versions)
If you need to stick with an older spin version, use once_cell or lazy_static to delay initialization until runtime, avoiding compiler static initialization issues:
use once_cell::sync::OnceCell; use spin::Mutex; static MUTEX: OnceCell<Mutex<u32>> = OnceCell::new(); #[no_mangle] pub extern "C" fn _start() -> ! { // Initialize the mutex only once, when first accessed let mutex = MUTEX.get_or_init(|| Mutex::new(0)); let mut value = mutex.lock(); *value += 1; loop {} }
Add once_cell to your Cargo.toml for this to work:
[dependencies] once_cell = "1.18" spin = "0.8" # Example older version
3. Complete the Missing panic_fmt Lang Item
Your code cuts off at #[lang = "panic_fmt"]—this incomplete lang item will cause compilation failures even after fixing the mutex issue. You need a minimal implementation for no_std:
#[lang = "panic_fmt"] pub extern "C" fn panic_fmt( _args: core::fmt::Arguments, _file: &'static str, _line: u32, ) -> ! { // Just loop indefinitely on panic (standard for bare-metal OS) loop {} }
Why This Fixes the Compiler Hang
In no_std environments, the Rust compiler can't fall back to standard library runtime initialization logic. When you try to initialize a static Mutex without a const-safe constructor, the compiler struggles to resolve the initialization dependencies, leading to infinite loops in its internal analysis. Using const initialization or lazy runtime initialization breaks this cycle.
内容的提问来源于stack exchange,提问作者user3447239

