Skip to content

Commit fce2636

Browse files
[rust][tools] Fix Rust build example configuration handling
Improve the Rust build integration across core, applications, components, and module examples. Fix build failure propagation, target and feature handling, linker flags, example configuration semantics, and add STM32 CI attach coverage.
1 parent 622c552 commit fce2636

24 files changed

Lines changed: 810 additions & 176 deletions

File tree

bsp/stm32/stm32f407-rt-spark/.ci/attachconfig/ci.attachconfig.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,26 @@ component.cherryusb_cdc:
246246
- CONFIG_RT_CHERRYUSB_DEVICE_DWC2_ST=y
247247
- CONFIG_RT_CHERRYUSB_DEVICE_CDC_ACM=y
248248
- CONFIG_RT_CHERRYUSB_DEVICE_TEMPLATE_CDC_ACM=y
249+
# ------ rust CI ------
250+
rust:
251+
<<: *scons
252+
pre_build: |
253+
python3 -m pip install --user toml
254+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly --profile minimal
255+
sudo ln -sf "$HOME/.cargo/bin/cargo" /usr/local/bin/cargo
256+
sudo ln -sf "$HOME/.cargo/bin/rustc" /usr/local/bin/rustc
257+
sudo ln -sf "$HOME/.cargo/bin/rustup" /usr/local/bin/rustup
258+
rustup target add thumbv7em-none-eabihf
259+
rustup component add rust-src
260+
rustc --version
261+
cargo --version
262+
kconfig:
263+
- CONFIG_RT_USING_RUST=y
264+
- CONFIG_RT_RUST_CORE=y
265+
- CONFIG_RT_USING_RUST_EXAMPLES=y
266+
- CONFIG_RT_RUST_BUILD_APPLICATIONS=y
267+
- CONFIG_RT_RUST_BUILD_COMPONENTS=y
268+
- CONFIG_RUST_LOG_COMPONENT=y
249269

250270
devices.soft_i2c:
251271
<<: *scons

components/rust/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ rustup target add thumbv7em-none-eabi
8484
# Add other targets that match your toolchain/ABI as needed
8585
```
8686

87+
For ARM targets whose C toolchain uses `-fshort-wchar`, RT-Thread uses the nightly-only `build-std` feature to rebuild Rust `core` and `alloc` from source, keeping the Rust ARM EABI wchar size aligned with the C toolchain. Install `rust-src` and the corresponding target for the same nightly toolchain. From the RT-Thread repository root, set a directory-local nightly override so that the plain `cargo` and `rustc` commands invoked by SCons use this toolchain throughout the repository:
88+
89+
```bash
90+
rustup toolchain install nightly --profile minimal --component rust-src
91+
rustup target add --toolchain nightly <target-name>
92+
rustup override set nightly
93+
```
94+
8795
### Build
8896

8997
```bash

components/rust/README_zh.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ rustup target add thumbv7em-none-eabi
8484
# 其他目标请根据实际工具链/ABI 添加对应的 Rust target
8585
```
8686

87+
对于 C 工具链使用 `-fshort-wchar` 的 ARM 目标,RT-Thread 会使用仅 nightly 支持的 `build-std` 从源码重新构建 Rust `core``alloc`,使 Rust ARM EABI wchar 大小与 C 工具链保持一致。请为同一个 nightly 工具链安装 `rust-src` 和对应 target,并在 RT-Thread 仓库根目录设置目录级 nightly override,使 SCons 在整个仓库目录树中调用的普通 `cargo``rustc` 命令使用该工具链:
88+
89+
```bash
90+
rustup toolchain install nightly --profile minimal --component rust-src
91+
rustup target add --toolchain nightly <target-name>
92+
rustup override set nightly
93+
```
94+
8795
### 构建
8896

8997
```bash

components/rust/SConscript

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def _has(sym: str) -> bool:
1010
except Exception:
1111
return bool(GetDepend(sym))
1212

13-
if not _has('RT_USING_RUST'):
13+
if not _has('RT_USING_RUST') and not GetOption('clean'):
1414
Return('objs')
1515

1616
cwd = GetCurrentDir()

components/rust/core/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ crate-type = ["rlib", "staticlib"]
1010
[features]
1111
default = []
1212
smp = []
13+
fs = []
14+
libdl = []
15+
16+
[package.metadata.rt-thread.features.smp]
17+
all = ["RT_USING_SMP"]
18+
19+
[package.metadata.rt-thread.features.fs]
20+
all = ["RT_USING_DFS", "DFS_USING_POSIX"]
21+
22+
[package.metadata.rt-thread.features.libdl]
23+
all = ["RT_USING_MODULE"]
1324

1425
[profile.dev]
1526
panic = "abort"

components/rust/core/SConscript

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import os
2+
import sys
23
from building import *
4+
from SCons.Subst import quote_spaces
35

46
cwd = GetCurrentDir()
57

68
sys.path.append(os.path.join(cwd, '../tools'))
79
from build_support import (
810
detect_rust_target,
911
make_rustflags,
12+
make_cargo_build_std_args,
1013
collect_features,
1114
verify_rust_toolchain,
1215
ensure_rust_target_installed,
1316
cargo_build_staticlib,
17+
get_staticlib_link_name,
1418
clean_rust_build,
1519
)
1620
def _has(sym: str) -> bool:
@@ -20,10 +24,28 @@ def _has(sym: str) -> bool:
2024
return bool(GetDepend(sym))
2125

2226

23-
# Source files – MSH command glue
24-
src = ['rust_cmd.c']
27+
group = []
28+
if not _has('RT_RUST_CORE') and not GetOption('clean'):
29+
Return('group')
30+
31+
32+
def get_staticlib_link_name_from_artifact(lib_path):
33+
"""Derive the link name from the actual staticlib artifact file name."""
34+
artifact_name = os.path.basename(os.fspath(lib_path))
35+
if artifact_name.startswith("lib") and artifact_name.endswith(".a"):
36+
return artifact_name[3:-2]
37+
return None
38+
39+
40+
# Source files – MSH command glue.
41+
# rust_cmd.c references rust_init(), which is only provided by the Rust core
42+
# static library. It must only enter the build when that library is actually
43+
# produced; otherwise the C link stage fails with 'undefined reference to
44+
# rust_init' instead of failing/skipping cleanly at the Rust build step.
2545
LIBS = []
2646
LIBPATH = []
47+
LINKFLAGS = ""
48+
include_rust_cmd = False
2749

2850
if GetOption('clean'):
2951
# Register Rust artifacts for cleaning
@@ -33,39 +55,65 @@ if GetOption('clean'):
3355
Clean('.', rust_build_dir)
3456
else:
3557
print('No rust build artifacts to clean')
58+
# Keep rust_cmd.c in the group during clean so its object is cleaned too.
59+
include_rust_cmd = True
3660
else:
3761
if verify_rust_toolchain():
3862
import rtconfig
63+
rust_build_dir = clean_rust_build(Dir('#').abspath)
3964

4065
target = detect_rust_target(_has, rtconfig)
4166
if not target:
4267
print('Error: Unable to detect Rust target; please check configuration')
68+
sys.exit(1)
4369
else:
4470
print(f'Detected Rust target: {target}')
4571

4672
# Optional hint if target missing
47-
ensure_rust_target_installed(target)
48-
49-
# Build mode and features
50-
debug = bool(_has('RUST_DEBUG_BUILD'))
51-
features = collect_features(_has)
73+
if not ensure_rust_target_installed(target):
74+
print('Error: Rust target is not installed; Rust library build failed')
75+
sys.exit(1)
76+
else:
77+
# Build mode and features
78+
debug = bool(_has('RUST_DEBUG_BUILD'))
79+
features = collect_features(_has)
5280

53-
rustflags = make_rustflags(rtconfig, target)
54-
rust_lib = cargo_build_staticlib(
55-
rust_dir=cwd, target=target, features=features, debug=debug, rustflags=rustflags
56-
)
81+
rustflags = make_rustflags(rtconfig, target)
82+
cargo_extra_args = make_cargo_build_std_args(rtconfig, target)
83+
rust_lib = cargo_build_staticlib(
84+
rust_dir=cwd, target=target, features=features, debug=debug, rustflags=rustflags, build_root=rust_build_dir, cargo_extra_args=cargo_extra_args
85+
)
5786

58-
if rust_lib:
59-
LIBS = ['rt_rust']
60-
LIBPATH = [os.path.dirname(rust_lib)]
61-
print('Rust library linked successfully')
62-
else:
63-
print('Warning: Failed to build Rust library')
87+
if rust_lib:
88+
# Derive the link name from the actual artifact so it always
89+
# matches the file that was built. Only fall back to
90+
# re-parsing Cargo.toml when the artifact name does not
91+
# follow the lib<name>.a convention.
92+
link_lib_name = get_staticlib_link_name_from_artifact(rust_lib)
93+
if not link_lib_name:
94+
link_lib_name = get_staticlib_link_name(cwd)
95+
LIBS = [link_lib_name]
96+
LIBPATH = [os.path.dirname(rust_lib)]
97+
if rtconfig.PLATFORM == 'armclang':
98+
if not (os.path.isfile(rust_lib) and os.path.getsize(rust_lib) > 0):
99+
print(f'Error: ArmClang Rust core link requires a non-empty archive, but got: {rust_lib}')
100+
sys.exit(1)
101+
LINKFLAGS = " " + quote_spaces(os.fspath(rust_lib))
102+
LIBS = []
103+
LIBPATH = []
104+
include_rust_cmd = True
105+
print('Rust library linked successfully')
106+
else:
107+
print('Error: Failed to build Rust library')
108+
sys.exit(1)
64109
else:
65-
print('Warning: Rust toolchain not found')
110+
print('Error: Rust toolchain not found')
66111
print('Please install Rust from https://rustup.rs')
112+
sys.exit(1)
67113

68-
# Define component group for SCons
69-
group = DefineGroup('rust', src, depend=['RT_USING_RUST'], LIBS=LIBS, LIBPATH=LIBPATH)
114+
# Only define the component group (with rust_cmd.c) when the Rust core static
115+
# library was actually produced, so its rust_init() reference always resolves.
116+
if include_rust_cmd:
117+
group = DefineGroup('rust', ['rust_cmd.c'], depend=['RT_USING_RUST', 'RT_RUST_CORE'], LIBS=LIBS, LIBPATH=LIBPATH, LINKFLAGS=LINKFLAGS)
70118

71119
Return('group')

components/rust/core/src/api/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod thread;
1414
pub mod mutex;
1515
pub mod sem;
1616
pub mod queue;
17+
#[cfg(feature = "libdl")]
1718
pub mod libloading;
1819

1920

@@ -24,4 +25,5 @@ pub use thread::*;
2425
pub use mutex::*;
2526
pub use sem::*;
2627
pub use queue::*;
28+
#[cfg(feature = "libdl")]
2729
pub use libloading::*;

components/rust/core/src/api/queue.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub type APIRawQueue = rt_mq_t;
2020
pub(crate) fn queue_create(name: &str, len: u64, message_size: u64) -> Option<APIRawQueue> {
2121
let s = CString::new(name).unwrap();
2222
let raw;
23-
unsafe { raw = rt_mq_create(s.as_ptr(), message_size, len, 0) }
23+
unsafe { raw = rt_mq_create(s.as_ptr(), message_size as rt_size_t, len as rt_size_t, 0) }
2424
if raw == ptr::null_mut() {
2525
None
2626
} else {
@@ -35,7 +35,7 @@ pub(crate) fn queue_send_wait(
3535
msg_size: u64,
3636
tick: i32,
3737
) -> RttCResult {
38-
unsafe { rt_mq_send_wait(handle, msg, msg_size, tick).into() }
38+
unsafe { rt_mq_send_wait(handle, msg, msg_size as rt_size_t, tick).into() }
3939
}
4040

4141
#[inline]
@@ -45,7 +45,12 @@ pub(crate) fn queue_receive_wait(
4545
msg_size: u64,
4646
tick: i32,
4747
) -> RttCResult {
48-
unsafe { rt_mq_recv(handle, msg, msg_size, tick).into() }
48+
let ret = unsafe { rt_mq_recv(handle, msg, msg_size as rt_size_t, tick) };
49+
if ret >= 0 {
50+
RttCResult::Ok
51+
} else {
52+
ret.into()
53+
}
4954
}
5055

5156
#[inline]

components/rust/core/src/bindings/librt.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub type rt_int32_t = c_int;
2626
pub type rt_uint8_t = c_uchar;
2727
pub type rt_tick_t = rt_uint32_t;
2828
pub type rt_size_t = rt_ubase_t;
29+
pub type rt_ssize_t = rt_base_t;
2930

3031
pub type rt_thread_t = *mut c_void;
3132
pub type rt_sem_t = *mut c_void;
@@ -94,7 +95,7 @@ unsafe extern "C" {
9495
pub fn rt_mq_create(name: *const c_char, msg_size: rt_size_t, max_msgs: rt_size_t, flag: rt_uint8_t) -> rt_mq_t;
9596
pub fn rt_mq_send(mq: rt_mq_t, buffer: *const c_void, size: rt_size_t) -> rt_err_t;
9697
pub fn rt_mq_send_wait(mq: rt_mq_t, buffer: *const c_void, size: rt_size_t, timeout: rt_int32_t) -> rt_err_t;
97-
pub fn rt_mq_recv(mq: rt_mq_t, buffer: *mut c_void, size: rt_size_t, timeout: rt_int32_t) -> rt_base_t;
98+
pub fn rt_mq_recv(mq: rt_mq_t, buffer: *mut c_void, size: rt_size_t, timeout: rt_int32_t) -> rt_ssize_t;
9899
pub fn rt_mq_delete(mq: rt_mq_t) -> rt_err_t;
99100
pub fn rt_mq_detach(mq: rt_mq_t) -> rt_err_t;
100101
}

components/rust/core/src/bindings/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ pub use librt::{
4646

4747
/* Memory management functions */
4848
pub use librt::{
49-
rt_malloc, rt_free, rt_realloc, rt_calloc, rt_malloc_align, rt_free_align,
50-
rt_safe_malloc, rt_safe_free
49+
rt_malloc, rt_free, rt_realloc, rt_calloc, rt_malloc_align, rt_free_align
5150
};
5251

5352
/* Device management functions */

0 commit comments

Comments
 (0)