summaryrefslogtreecommitdiff
path: root/components/rust/docs/5.rt-macro/README.md
blob: 3f448d77fc59faa7ae3bf03de01c25e395a6b1f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# 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-Thread’s 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.

## Link Sections and Startup Flow

- 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
```rust
use rt_macros::rt_thread_main;

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

### Component export
```rust
use rt_macros::rt_component_export;

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

### Application export
```rust
use rt_macros::rt_app_export;

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

### Shell command export
```rust
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:

```c
extern "C" void rust_function_name(void);
```

The command export macro generates a wrapper with `(argc, argv)`; RT-Thread’s 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

- [RUST support for rt-thread](https://github.com/rust-for-rtthread/rtt_rust)