Files
rt-thread/components/rust/docs/5.rt-macro/rt-macros.md
zhang san 69980f8b9d
Some checks failed
ToolsCI / Tools (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
Weekly CI Scheduler / Trigger and Monitor CIs (push) Has been cancelled
Weekly CI Scheduler / Create Discussion Report (push) Has been cancelled
Adding Rust Language Support for RT-Thread #10910
2025-12-08 18:34:25 +08:00

4.1 KiB
Raw Blame History

rt_macros Usage Guide

rt_macros is a collection of Rust procedural macros for RT-Thread. It helps export Rust functions as system entry points, initialization entries, or shell commands in a no_std environment, so they integrate cleanly with RT-Threads startup and command mechanisms.

Background and Goals

In no_std mode, the traditional main function is not directly available. rt_macros generates C-ABI-compatible wrapper entries and the required link-section items so RT-Thread can discover and invoke the corresponding Rust logic during startup or shell command scanning.

Provided Macros (aligned with RT-Thread conventions)

  • rt_thread_main!: Marks the Rust main-thread entry.

    • Function signature: fn() (no parameters, no return value).
    • Constraints: no const, unsafe, async, varargs; no explicit ABI; no generics; default visibility (non-pub).
    • Purpose: exports an entry that RT-Thread can recognize and call as the main thread.
  • rt_component_export!: Exports a component initialization entry.

    • Function signature: fn().
    • Same constraints; optional parameter: name = "..." (used to generate internal symbol names).
    • Link section: places the function pointer into .rti_fn.4, executed during the component initialization phase.
  • rt_app_export!: Exports an application initialization entry.

    • Function signature: fn().
    • Same constraints; optional parameter: name = "...".
    • Link section: places the function pointer into .rti_fn.6, executed during the application initialization phase.
  • msh_cmd_export!: Exports an RT-Thread shell command.

    • Function signature: fn(args: vec::IntoIter<rt_rust::param::ParamItem>).
    • Attributes: name (required, command name), desc (optional, command description).
    • Link sections and data:
      • Generates a command descriptor struct placed into FSymTab.
      • Command name and description are \0-terminated byte arrays placed into .rodata.name.
    • Invocation wrapper: generates an extern "C" wrapper (argc, argv), converts argv to Vec<ParamItem>, and calls the original Rust command function.
  • Component init entries: .rti_fn.4
  • Application init entries: .rti_fn.6
  • Shell command table: FSymTab
  • Shell name/description strings: .rodata.name

During startup or shell scanning, RT-Thread traverses these sections to register or invoke the corresponding Rust logic.

Usage Examples

Main-thread entry

use rt_macros::rt_thread_main;

#[rt_thread_main]
fn main() {
    // Main thread logic here
}

Component export

use rt_macros::rt_component_export;

#[rt_component_export(name = "rust_component_registry")]
fn my_component_init() {
    // Component init logic
}

Application export

use rt_macros::rt_app_export;

#[rt_app_export(name = "rust_app_example")]
fn my_app_init() {
    // Application init logic
}

Shell command export

use rt_macros::msh_cmd_export;

#[msh_cmd_export(name = "hello", desc = "Say hello")]
fn hello_cmd(args: vec::IntoIter<rt_rust::param::ParamItem>) {
    // Handle args and print output, etc.
}

Interacting with C Code

When calling exported Rust entries from C, declare the prototype and use extern "C" for the calling convention, for example:

extern "C" void rust_function_name(void);

The command export macro generates a wrapper with (argc, argv); RT-Threads command system calls this wrapper and passes the arguments to the original Rust function.

Common Issues and Diagnostics

  • Compile-time errors: the macros produce explicit diagnostics if the function signature does not match (e.g., must be fn() or a specific parameter shape). Adjust the function to meet the requirements above.
  • Visibility requirement: keep the entry function at default (non-pub) visibility to satisfy macro constraints.
  • alloc dependency: the shell command macro uses alloc::vec::Vec, ensure an allocator is available at runtime (RT-Thread usually provides one).

References