引言:从"云端"到"铁端"
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}"
-
这个命令能让你看清哪个依赖项开启了
stdfeature。一旦发现,立刻在Cargo.toml里加上default-features = false。
第二阶段:代码重构------从 std 到 core
规则 3:全员换装 core 和 alloc
在 lib.rs 开头大声宣布:
rust
#![no_std]
extern crate alloc;
- 骚操作 :全局搜索
std::改为core::。比如std::cmp::max变成core::cmp::max。如果涉及到内存分配(如Vec,BTreeMap),请指向alloc::。
规则4:让 std 变成"可选配置"
为了让你的库既能跑在 Linux 服务器上,又能跑在单片机上,利用 Cargo Features:
rust
[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(半主机)技术,让单片机模拟器把日志打印到你电脑的控制台上。
- 代码示范:
rust
#[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 给了你一把最锋利的刺刀。
参考: