mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-08-24 11:08:38 +08:00
3.8 KiB
3.8 KiB
rt_macros 使用说明
rt_macros 是为 RT-Thread 提供的 Rust 过程宏集合,帮助在 no_std 环境下将 Rust 函数以约定的方式导出为系统入口、初始化段或 Shell 命令,从而与 RT-Thread 的启动与命令机制顺畅对接。
背景与目标
在 no_std 模式下不能直接使用传统的 main 函数。rt_macros 通过过程宏生成符合 C ABI 的包装入口,以及必要的链接段条目,让 RT-Thread 能在启动期或命令扫描阶段发现并调用对应的 Rust 逻辑。
提供的宏(参考RT-Thread的声明)
-
rt_thread_main!:标记 Rust 主线程入口。- 函数签名:
fn()(无参数、无返回值)。 - 约束:不支持
const、unsafe、async、变参;不可使用显式 ABI;不可含泛型;函数可见性需为默认(非pub)。 - 作用:导出可由 RT-Thread 识别和调用的主线程入口。
- 函数签名:
-
rt_component_export!:导出为组件初始化入口。- 函数签名:
fn()。 - 约束同上;可选参数:
name = "..."(用于生成内部符号名称)。 - 链接段:将函数指针落入
.rti_fn.4段,供组件初始化阶段调用。
- 函数签名:
-
rt_app_export!:导出为应用初始化入口。- 函数签名:
fn()。 - 约束同上;可选参数:
name = "..."。 - 链接段:将函数指针落入
.rti_fn.6段,供应用初始化阶段调用。
- 函数签名:
-
msh_cmd_export!:导出为 RT-Thread Shell 命令。- 函数签名:
fn(args: vec::IntoIter<rt_rust::param::ParamItem>)。 - 属性参数:
name(必填,命令名),desc(可选,命令描述)。 - 链接段与数据:
- 生成命令描述结构体并落入
FSymTab段。 - 命令名与描述以以
\0结尾的字节数组形式落入.rodata.name段。
- 生成命令描述结构体并落入
- 调用封装:生成
extern "C"包装函数(argc, argv),把argv转换为Vec<ParamItem>,再调用原始 Rust 命令函数。
- 函数签名:
链接段与启动流程
- 组件初始化入口:
.rti_fn.4 - 应用初始化入口:
.rti_fn.6 - Shell 命令表:
FSymTab - Shell 名称/描述字符串:
.rodata.name
RT-Thread 在启动或命令表扫描时,会遍历对应段的条目并完成调用或注册,从而将 Rust 编写的逻辑纳入系统。
使用示例
主线程入口
use rt_macros::rt_thread_main;
#[rt_thread_main]
fn main() {
// 在此编写主线程逻辑
}
组件导出
use rt_macros::rt_component_export;
#[rt_component_export(name = "rust_component_registry")]
fn my_component_init() {
// 组件初始化逻辑
}
应用导出
use rt_macros::rt_app_export;
#[rt_app_export(name = "rust_app_example")]
fn my_app_init() {
// 应用初始化逻辑
}
Shell 命令导出
use rt_macros::msh_cmd_export;
#[msh_cmd_export(name = "hello", desc = "Say hello")]
fn hello_cmd(args: vec::IntoIter<rt_rust::param::ParamItem>) {
// 命令处理逻辑,例如解析 args 并打印输出
}
与 C 代码的交互
当需要从 C 调用导出的 Rust 入口时,应在 C 侧声明原型并使用 extern "C" 指定调用约定,例如:
extern "C" void rust_function_name(void);
命令导出宏会生成 (argc, argv) 形式的包装函数,RT-Thread 的命令系统会调用该包装函数并将参数传递给原始 Rust 函数。
常见问题与诊断
- 编译期报错:宏会在函数签名不符合约束时给出明确的错误信息(例如必须为
fn()或必须为特定的参数形式)。请按上文的签名要求调整。 - 可见性要求:入口函数应保持默认(非
pub),以满足宏的约束。 alloc依赖:Shell 命令宏内部使用alloc::vec::Vec,需确保运行环境提供分配器(RT-Thread 通常可满足)。