引言:从“云端”到“铁端”
Rust 的野心从来不是只做 C++ 的替代品,它的目标是全场景覆盖。但从 OS 环境切换到“裸机”(Bare Metal),就像是从五星级酒店搬到了荒岛求生。没有操作系统,没有文件系统,甚至连 std 库都没了。
怎么优雅地完成代码移植?收好这 9 条“求生指南”。
第一阶段:生存环境大检查
规则 1:先过 WASM 这道关
如果你想让代码跑在单片机上,先试试能不能跑在浏览器里(WASM)。
-
技巧:使用 wasm32-wasip1 或 wasm32-unknown-unknown 进行测试。如果你的代码在 WASM 下都因为找不到某些 std 方法而挂掉,那单片机基本也悬了。
规则 2:利用 cargo tree 捕获隐藏的“间谍”
很多时候你的代码没用 std,但你引用的依赖项偷偷用了。
-
必杀技:
cargo tree –edges no-dev –format "{p} {f}"
-
这个命令能让你看清哪个依赖项开启了 std feature。一旦发现,立刻在 Cargo.toml 里加上 default-features = false。
第二阶段:代码重构——从 std 到 core
规则 3:全员换装 core 和 alloc
在 lib.rs 开头大声宣布:
#![no_std]
extern crate alloc;
-
骚操作:全局搜索 std:: 改为 core::。比如 std::cmp::max 变成 core::cmp::max。如果涉及到内存分配(如 Vec, BTreeMap),请指向 alloc::。
规则4:让 std 变成“可选配置”
为了让你的库既能跑在 Linux 服务器上,又能跑在单片机上,利用 Cargo Features:
[features]
default = ["std"]
std = ["itertools/use_std", "num-traits/std"]
在代码里通过 #[cfg(feature = "std")] 来包裹那些只有 OS 才能跑的功能(比如文件 I/O)。
第三阶段:测试——解决“嵌入式开发最难的一环”
规则 5:清楚 cargo test 永远带 std
这是一个很多新手都会掉进去的坑:即便你标记了 no_std,运行 cargo test 时,Rust 依然会链接标准库来运行测试框架。 这意味着:cargo test 通过了,不代表你的 no_std 环境没问题。
规则 6:QEMU 仍旧权威!
既然本地 test 不靠谱,那就上模拟器。
安装 qemu-system-arm。
创建一个独立的 tests/embedded 子项目。
利用 semihosting(半主机)技术,让单片机模拟器把日志打印到你电脑的控制台上。
-
代码示范:
#[entry]
fn main() -> ! {
// … 初始化堆内存 …
hprintln!("Running embedded tests…");
if test_logic() {
debug::exit(debug::EXIT_SUCCESS);
} else {
debug::exit(debug::EXIT_FAILURE);
}
loop {}
}
第四阶段:进阶与工程化
规则 7:贴上“嵌入式友好”标签
如果你打算开源你的库,记得在 Cargo.toml 里加上 categories = ["no-std", "embedded"]。这不仅是荣誉勋章,更是流量密码,让全世界的嵌入式大佬能搜到你。
规则 8:极致压榨——拥抱 heapless(可选)
如果你的单片机内存小到连 alloc 都不敢开(比如只有几 KB RAM),那就祭出 heapless 库。
-
逻辑:用静态分配的 Vec、String 代替动态分配。
-
代价:你必须在编译时确定最大长度。比如 heapless::Vec<u8, 64>。
规则 9:CI 是唯一的真相
“在我的 QEMU 上能跑”不叫能跑,“在 GitHub Actions 里能跑”才叫稳。 在 CI 配置文件里加上 thumbv7m-none-eabi 目标的编译检查和 QEMU 自动化测试。只有自动化,才能防止你某天手抖引入了一个带 std 的库导致版本崩盘。
总结
移植 no_std 并不是简单的代码搬运,它其实是对模块化思维的终极考验。
-
底层逻辑:把业务逻辑(Pure Logic)和平台实现(I/O, Time, File)彻底解耦。
-
避坑指南:很多三方库(如 thiserror)默认是不支持 no_std 的,寻找替代品(如 anyhow 的某些配置或自己写宏)是常态。
正如 Carl 在博文中展示的,哪怕是复杂的 range-set-blaze 这种涉及数据结构合并的算法,只要遵循这 9 条规则,也能在 Raspberry Pi Pico 的 LED 动画里闪耀。
嵌入式的世界没有银弹,但 Rust 给了你一把最锋利的刺刀。
参考:
-
Nine Rules for Running Rust on Embedded Systems


