Rust no_std 裸机移植:9 条避坑与实战手册

引言:从"云端"到"铁端"

Rust 的野心从来不是只做 C++ 的替代品,它的目标是全场景覆盖 。但从 OS 环境切换到"裸机"(Bare Metal),就像是从五星级酒店搬到了荒岛求生。没有操作系统,没有文件系统,甚至连 std 库都没了。

怎么优雅地完成代码移植?收好这 9 条"求生指南"。


第一阶段:生存环境大检查

规则 1:先过 WASM 这道关

如果你想让代码跑在单片机上,先试试能不能跑在浏览器里(WASM)。

  • 技巧 :使用 wasm32-wasip1wasm32-unknown-unknown 进行测试。如果你的代码在 WASM 下都因为找不到某些 std 方法而挂掉,那单片机基本也悬了。
规则 2:利用 cargo tree 捕获隐藏的"间谍"

很多时候你的代码没用 std,但你引用的依赖项偷偷用了。

  • 必杀技

    cargo tree --edges no-dev --format "{p} {f}"

  • 这个命令能让你看清哪个依赖项开启了 std feature。一旦发现,立刻在 Cargo.toml 里加上 default-features = false


第二阶段:代码重构------从 stdcore

规则 3:全员换装 corealloc

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 不靠谱,那就上模拟器。

  1. 安装 qemu-system-arm

  2. 创建一个独立的 tests/embedded 子项目。

  3. 利用 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 库。

  • 逻辑 :用静态分配的 VecString 代替动态分配。

  • 代价 :你必须在编译时确定最大长度。比如 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 给了你一把最锋利的刺刀。


参考:

相关推荐
万联WANFLOW32 分钟前
多分支企业组网,IP 网段到底该怎么规划
开发语言·php
阿里嘎多学长44 分钟前
2026-07-07 GitHub 热点项目精选
开发语言·程序员·github·代码托管
cookies_s_s2 小时前
C++ 字符串动态创建对象 -- 工厂模式、自动注册、模板递归动态调用
服务器·开发语言·c++
盐焗鹌鹑蛋3 小时前
【C++】继承
开发语言·c++
栈溢出了4 小时前
Java Lambda 表达式笔记
java·开发语言·intellij-idea
zhixingheyi_tian4 小时前
一份GC日志的解读
java·开发语言
czhaii4 小时前
串口1中断收发-C语言-MODBUS协议
c语言·开发语言
apihz5 小时前
随机驾考题目(C 照科一 / 科四 2000+ 题)免费API调用教程
android·java·c语言·开发语言·网络协议·tcp/ip
matlab代码5 小时前
基于matlab人脸疲劳驾驶检测系统(可使用其它人脸视频)【源码39期】
开发语言·matlab·人脸疲劳检测
zenithdev16 小时前
fastcache:为 Go 设计的低 GC 压力内存缓存
开发语言·其他·缓存·golang