mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-09-22 19:44:24 +08:00
Adding Rust Language Support for RT-Thread #10910
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
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
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
menuconfig RT_USING_RUST_EXAMPLES
|
||||
bool "Enable Rust Examples"
|
||||
depends on RT_USING_RUST
|
||||
default n
|
||||
help
|
||||
Enable Rust example applications, components, and modules.
|
||||
|
||||
if RT_USING_RUST_EXAMPLES
|
||||
|
||||
config RT_RUST_BUILD_ALL_EXAMPLES
|
||||
bool "Build All Examples"
|
||||
default n
|
||||
help
|
||||
Build all available Rust examples.
|
||||
|
||||
menu "Application Examples"
|
||||
config RT_RUST_BUILD_APPLICATIONS
|
||||
bool "Build Application Examples"
|
||||
default y
|
||||
depends on RT_USING_FINSH
|
||||
help
|
||||
Build Rust application examples.
|
||||
|
||||
if RT_RUST_BUILD_APPLICATIONS
|
||||
config RT_RUST_EXAMPLE_FS
|
||||
bool "File System Example"
|
||||
default n
|
||||
help
|
||||
File system operations example.
|
||||
|
||||
config RT_RUST_EXAMPLE_LOADLIB
|
||||
bool "Dynamic Library Loading Example"
|
||||
default n
|
||||
depends on RT_USING_MODULE
|
||||
help
|
||||
Dynamic library loading and usage example.
|
||||
|
||||
config RT_RUST_EXAMPLE_MUTEX
|
||||
bool "Mutex Example"
|
||||
default y
|
||||
help
|
||||
Mutex synchronization example.
|
||||
|
||||
config RT_RUST_EXAMPLE_PARAM
|
||||
bool "Parameter Example"
|
||||
default y
|
||||
help
|
||||
Basic parameter handling example.
|
||||
|
||||
config RT_RUST_EXAMPLE_QUEUE
|
||||
bool "Queue Example"
|
||||
default y
|
||||
help
|
||||
Message queue example.
|
||||
|
||||
config RT_RUST_EXAMPLE_SEMAPHORE
|
||||
bool "Semaphore Example"
|
||||
default y
|
||||
help
|
||||
Semaphore synchronization example.
|
||||
|
||||
config RT_RUST_EXAMPLE_THREAD
|
||||
bool "Thread Example"
|
||||
default y
|
||||
help
|
||||
Thread creation and management example.
|
||||
endif
|
||||
endmenu
|
||||
|
||||
menu "Component Examples"
|
||||
config RT_RUST_BUILD_COMPONENTS
|
||||
bool "Build Component Examples"
|
||||
default y
|
||||
help
|
||||
Build Rust component examples.
|
||||
|
||||
if RT_RUST_BUILD_COMPONENTS
|
||||
config RUST_LOG_COMPONENT
|
||||
bool "Auto-initialize Rust log component"
|
||||
default y
|
||||
help
|
||||
Automatically initialize Rust log component during RT-Thread startup.
|
||||
endif
|
||||
endmenu
|
||||
|
||||
menu "Module Examples"
|
||||
config RT_RUST_BUILD_MODULES
|
||||
bool "Build Module Examples"
|
||||
default n
|
||||
depends on RT_USING_MODULE
|
||||
help
|
||||
Build Rust dynamic module examples.
|
||||
|
||||
if RT_RUST_BUILD_MODULES
|
||||
config RT_RUST_MODULE_SIMPLE_MODULE
|
||||
bool "Simple Module"
|
||||
default y
|
||||
help
|
||||
Basic dynamic module template.
|
||||
|
||||
endif
|
||||
endmenu
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,22 @@
|
||||
# RT-Thread building script for Rust examples
|
||||
|
||||
import os
|
||||
from building import *
|
||||
|
||||
Import('rtconfig')
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
group = []
|
||||
entries = os.listdir(cwd)
|
||||
|
||||
subdirs = ['application', 'component', 'modules']
|
||||
|
||||
for subdir in subdirs:
|
||||
if subdir in entries:
|
||||
result = SConscript(os.path.join(subdir, 'SConscript'))
|
||||
if isinstance(result, (list, tuple)):
|
||||
group.extend(result)
|
||||
else:
|
||||
group.append(result)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,70 @@
|
||||
import os
|
||||
import sys
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
|
||||
# Import usrapp build module and build support
|
||||
sys.path.append(os.path.join(cwd, '../../tools'))
|
||||
from build_usrapp import build_example_usrapp
|
||||
from build_support import clean_rust_build
|
||||
|
||||
|
||||
def _has(sym: str) -> bool:
|
||||
try:
|
||||
return bool(GetDepend([sym]))
|
||||
except Exception:
|
||||
return bool(GetDepend(sym))
|
||||
|
||||
|
||||
def load_extended_feature_configs():
|
||||
"""
|
||||
Load extended feature configurations if available.
|
||||
This allows users to add custom configuration mappings.
|
||||
"""
|
||||
try:
|
||||
from feature_config_examples import setup_all_example_features
|
||||
setup_all_example_features()
|
||||
print("Extended feature configurations loaded successfully.")
|
||||
except ImportError:
|
||||
print("Using default feature configurations.")
|
||||
|
||||
group = []
|
||||
|
||||
if not _has('RT_RUST_BUILD_APPLICATIONS'):
|
||||
Return('group')
|
||||
|
||||
# Load extended feature configurations
|
||||
load_extended_feature_configs()
|
||||
|
||||
src = []
|
||||
LIBS = []
|
||||
LIBPATH = []
|
||||
LINKFLAGS = ""
|
||||
|
||||
if GetOption('clean'):
|
||||
app_build_dir = clean_rust_build(Dir('#').abspath, "example_usrapp")
|
||||
if os.path.exists(app_build_dir):
|
||||
print(f'Registering {app_build_dir} for cleanup')
|
||||
Clean('.', app_build_dir)
|
||||
else:
|
||||
print('No example_usrapp build artifacts to clean')
|
||||
else:
|
||||
import rtconfig
|
||||
LIBS, LIBPATH, LINKFLAGS = build_example_usrapp(
|
||||
cwd=cwd,
|
||||
has_func=_has,
|
||||
rtconfig=rtconfig,
|
||||
build_root=os.path.join(Dir('#').abspath, "build", "example_usrapp")
|
||||
)
|
||||
|
||||
group = DefineGroup(
|
||||
'example_usrapp',
|
||||
src,
|
||||
depend=['RT_USING_RUST'],
|
||||
LIBS=LIBS,
|
||||
LIBPATH=LIBPATH,
|
||||
LINKFLAGS=LINKFLAGS
|
||||
)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "em_fs"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_fs"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enable-log = ["em_component_log/enable-log"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
rt_macros = { path = "../../../rt_macros" }
|
||||
em_component_log = { path = "../../component/log"}
|
||||
@@ -0,0 +1,73 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-20 foxglove Rust file operation test.
|
||||
* 2025-10-29 foxglove Updated to demonstrate new modular macro interface
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use rt_macros::msh_cmd_export;
|
||||
use rt_rust::{fs, println};
|
||||
use rt_rust::param::Param;
|
||||
use em_component_log::{info, error};
|
||||
|
||||
#[msh_cmd_export(name = "rust_file_demo", desc = "Rust example app.")]
|
||||
fn main(_param: Param) {
|
||||
println!("[rust_file_test] start");
|
||||
|
||||
let mut file = match fs::OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.append(false)
|
||||
.truncate(true)
|
||||
.open("test.txt")
|
||||
{
|
||||
Ok(f) => {
|
||||
info!("open test.txt ok");
|
||||
f
|
||||
}
|
||||
Err(e) => {
|
||||
error!("open error: {:?}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = file.write_all("Hello from FS wrapper!\n") {
|
||||
error!("write_all error: {:?}", e);
|
||||
return;
|
||||
}
|
||||
info!("write_all done");
|
||||
|
||||
if let Err(e) = file.flush() {
|
||||
error!("flush error: {:?}", e);
|
||||
} else {
|
||||
info!("flush ok");
|
||||
}
|
||||
|
||||
match file.read_to_string() {
|
||||
Ok(s) => info!("read_back: {}", s),
|
||||
Err(e) => error!("read_to_string error: {:?}", e),
|
||||
}
|
||||
|
||||
if let Err(e) = file.set_len(5) {
|
||||
error!("truncate error: {:?}", e);
|
||||
} else {
|
||||
info!("truncate to 5 ok");
|
||||
}
|
||||
|
||||
if let Err(e) = file.close() {
|
||||
error!("close error: {:?}", e);
|
||||
} else {
|
||||
info!("close ok");
|
||||
}
|
||||
|
||||
info!("[rust_file_test] end");
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "em_loadlib"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_loadlib"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
rt_macros = { path = "../../../rt_macros" }
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-10 foxglove load library example
|
||||
* 2025-10-29 foxglove Updated to demonstrate new modular macro interface
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use rt_macros::msh_cmd_export;
|
||||
use rt_rust::println;
|
||||
use rt_rust::get_libfn;
|
||||
use core::ffi::{c_int, c_char};
|
||||
use rt_rust::param::Param;
|
||||
|
||||
#[msh_cmd_export(name = "rust_dl_demo", desc = "Rust dynamic library demo")]
|
||||
fn main(_param: Param) {
|
||||
println!("\n=== Dynamic Library Demo ===");
|
||||
|
||||
get_libfn!("/hello.mo", "main", my_hello, ());
|
||||
my_hello();
|
||||
|
||||
get_libfn!("/libmylib.mo", "rust_mylib_add", my_add, c_int, a: c_int, b: c_int);
|
||||
let s = my_add(15, 20);
|
||||
println!("my_add(15, 20) = {}", s);
|
||||
|
||||
get_libfn!("/libmylib.mo", "rust_mylib_println", my_println, (), s: *const c_char);
|
||||
my_println(b"rustlib: Hello World\0".as_ptr() as *const c_char);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "em_mutex"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_mutex"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
rt_macros = { path = "../../../rt_macros" }
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-10 foxglove mutex test demo
|
||||
* 2025-10-29 foxglove Updated to demonstrate new modular macro interface
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use core::time::Duration;
|
||||
use rt_macros::msh_cmd_export;
|
||||
use rt_rust::mutex::Mutex;
|
||||
use rt_rust::param::Param;
|
||||
use rt_rust::println;
|
||||
use rt_rust::thread;
|
||||
use rt_rust::time;
|
||||
|
||||
#[msh_cmd_export(name = "rust_mutex_demo", desc = "Rust example app.")]
|
||||
fn main(_param: Param) {
|
||||
let counter = Arc::new(Mutex::new(0).unwrap());
|
||||
let run = move || loop {
|
||||
time::sleep(Duration::new(2, 0));
|
||||
{
|
||||
let mut c = counter.lock().unwrap();
|
||||
*c += 1;
|
||||
println!("{}", *c);
|
||||
}
|
||||
};
|
||||
|
||||
let _ = thread::Thread::new()
|
||||
.name("thread 1")
|
||||
.stack_size(2048)
|
||||
.start(run.clone());
|
||||
time::sleep(Duration::new(1, 0));
|
||||
let _ = thread::Thread::new()
|
||||
.name("thread 2")
|
||||
.stack_size(2048)
|
||||
.start(run.clone());
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "em_param"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_param"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
rt_macros = { path = "../../../rt_macros" }
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-10 foxglove param test demo
|
||||
* 2025-10-29 foxglove Updated to demonstrate new modular macro interface
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::string::String;
|
||||
use rt_macros::{rt_app_export, msh_cmd_export};
|
||||
use rt_rust::param::Param;
|
||||
use rt_rust::println;
|
||||
|
||||
// 演示新的模块化宏接口 - 使用 msh_cmd_export 导出参数测试命令
|
||||
#[msh_cmd_export(name = "rust_param_demo", desc = "Rust parameter demo")]
|
||||
fn main(param: Param) {
|
||||
for i in param {
|
||||
println!("{}", String::from_utf8_lossy(&*i))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "em_queue"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_queue"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
rt_macros = { path = "../../../rt_macros" }
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-10 foxglove queue test demo
|
||||
* 2025-10-29 foxglove Updated to demonstrate new modular macro interface
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use core::time::Duration;
|
||||
use rt_macros::msh_cmd_export;
|
||||
use rt_rust::queue::Queue;
|
||||
use rt_rust::param::Param;
|
||||
use rt_rust::println;
|
||||
use rt_rust::thread;
|
||||
use rt_rust::time;
|
||||
|
||||
#[msh_cmd_export(name = "rust_queue_demo", desc = "Rust example app.")]
|
||||
fn main(_param: Param) {
|
||||
let send = Arc::new(Queue::new(2).unwrap());
|
||||
let recv = send.clone();
|
||||
|
||||
let _ = thread::Thread::new()
|
||||
.name("thread 1")
|
||||
.stack_size(1024)
|
||||
.start(move || {
|
||||
loop {
|
||||
time::sleep(Duration::new(1, 0));
|
||||
send.send(String::from("msg"), 0).unwrap();
|
||||
}
|
||||
});
|
||||
time::sleep(Duration::new(1, 0));
|
||||
let _ = thread::Thread::new()
|
||||
.name("thread 2")
|
||||
.stack_size(1024)
|
||||
.start(move || {
|
||||
loop {
|
||||
println!("waiting!");
|
||||
let a = recv.recv_wait_forever().unwrap();
|
||||
println!("recv {}", a);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "em_sem"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_sem"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
rt_macros = { path = "../../../rt_macros" }
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-10 foxglove semaphore test demo
|
||||
* 2025-10-29 foxglove Updated to demonstrate new modular macro interface
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use core::time::Duration;
|
||||
use rt_macros::msh_cmd_export;
|
||||
use rt_rust::sem::Semaphore;
|
||||
use rt_rust::param::Param;
|
||||
use rt_rust::println;
|
||||
use rt_rust::thread;
|
||||
use rt_rust::time;
|
||||
|
||||
#[msh_cmd_export(name = "rust_sem_demo", desc = "Rust example app.")]
|
||||
fn main(_param: Param) {
|
||||
let send = Arc::new(Semaphore::new().unwrap());
|
||||
let recv = send.clone();
|
||||
|
||||
let _ = thread::Thread::new()
|
||||
.name("thread 1")
|
||||
.stack_size(1024)
|
||||
.start(move || {
|
||||
loop {
|
||||
time::sleep(Duration::new(1, 0));
|
||||
send.release()
|
||||
}
|
||||
});
|
||||
time::sleep(Duration::new(1, 0));
|
||||
let _ = thread::Thread::new()
|
||||
.name("thread 2")
|
||||
.stack_size(1024)
|
||||
.start(move || {
|
||||
loop {
|
||||
println!("waiting!");
|
||||
recv.take_wait_forever().unwrap();
|
||||
println!("recv a sem!")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "em_thread"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_thread"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
rt_macros = { path = "../../../rt_macros" }
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-10 foxglove thread test demo
|
||||
* 2025-10-29 foxglove Updated to demonstrate new modular macro interface
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
use core::time::Duration;
|
||||
use rt_macros::msh_cmd_export;
|
||||
use rt_rust::param::Param;
|
||||
use rt_rust::println;
|
||||
use rt_rust::thread;
|
||||
use rt_rust::time;
|
||||
|
||||
#[msh_cmd_export(name = "rust_thread_demo", desc = "Rust example app.")]
|
||||
fn main(_param: Param) {
|
||||
let _ = thread::Thread::new()
|
||||
.name("thread 1")
|
||||
.stack_size(1024)
|
||||
.start(move || {
|
||||
loop {
|
||||
println!("thread a will sleep 1s");
|
||||
time::sleep(Duration::new(1, 0));
|
||||
}
|
||||
});
|
||||
|
||||
let _ = thread::Thread::new()
|
||||
.name("thread 2")
|
||||
.stack_size(1024)
|
||||
.start(move || {
|
||||
loop {
|
||||
println!("thread b will sleep 3s");
|
||||
time::sleep(Duration::new(3, 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import os
|
||||
import sys
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
|
||||
# Import component build module and build support
|
||||
sys.path.append(os.path.join(cwd, '../../tools'))
|
||||
from build_component import build_example_component
|
||||
from build_support import clean_rust_build
|
||||
|
||||
# Load feature configurations
|
||||
try:
|
||||
from feature_config_component import setup_all_component_features
|
||||
setup_all_component_features()
|
||||
except ImportError:
|
||||
print("Warning: Could not load component feature configurations")
|
||||
|
||||
|
||||
def _has(sym: str) -> bool:
|
||||
"""Helper function to check if a configuration symbol is enabled."""
|
||||
try:
|
||||
return bool(GetDepend([sym]))
|
||||
except Exception:
|
||||
return bool(GetDepend(sym))
|
||||
|
||||
|
||||
# Early return if Rust or log component is not enabled
|
||||
if not _has('RT_USING_RUST'):
|
||||
group = []
|
||||
Return('group')
|
||||
|
||||
if not _has('RUST_LOG_COMPONENT'):
|
||||
group = []
|
||||
Return('group')
|
||||
|
||||
# Source files – component glue code if needed
|
||||
src = []
|
||||
LIBS = []
|
||||
LIBPATH = []
|
||||
LINKFLAGS = ""
|
||||
|
||||
# Handle clean operation
|
||||
if GetOption('clean'):
|
||||
comp_build_dir = clean_rust_build(Dir('#').abspath, "example_component")
|
||||
if os.path.exists(comp_build_dir):
|
||||
print(f'Registering {comp_build_dir} for cleanup')
|
||||
Clean('.', comp_build_dir)
|
||||
else:
|
||||
print('No example_component build artifacts to clean')
|
||||
else:
|
||||
# Build the component using the extracted build module
|
||||
import rtconfig
|
||||
LIBS, LIBPATH, LINKFLAGS = build_example_component(
|
||||
cwd=cwd,
|
||||
has_func=_has,
|
||||
rtconfig=rtconfig,
|
||||
build_root=os.path.join(Dir('#').abspath, "build", "example_component")
|
||||
)
|
||||
|
||||
# Define component group for SCons
|
||||
group = DefineGroup(
|
||||
'example_component_log',
|
||||
src,
|
||||
depend=['RT_USING_RUST'],
|
||||
LIBS=LIBS,
|
||||
LIBPATH=LIBPATH,
|
||||
LINKFLAGS=LINKFLAGS
|
||||
)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "em_component_registry"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_component_registry"
|
||||
crate-type = ["staticlib"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
rt_macros = { path = "../../../rt_macros" }
|
||||
|
||||
# Optional dependencies - only included when features are enabled
|
||||
em_component_log = { path = "../log", optional = true }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enable-log = ["em_component_log", "em_component_log/enable-log"]
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-25 foxglove Component registry for unified component registration
|
||||
* 2025-10-29 foxglove Updated to demonstrate new modular macro interface
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
/* Demonstrate the new modular macro interface */
|
||||
use rt_macros::rt_component_export;
|
||||
use rt_rust::param::{Param, ParamItem};
|
||||
use rt_rust::println;
|
||||
|
||||
/* Re-export component functionality for other modules */
|
||||
#[cfg(feature = "enable-log")]
|
||||
pub use em_component_log::*;
|
||||
#[cfg(feature = "enable-log")]
|
||||
use em_component_log::logging::Level;
|
||||
|
||||
/** Unified component registration entrypoint */
|
||||
#[cfg(feature = "enable-log")]
|
||||
#[rt_component_export(name = "rust_component_registry")]
|
||||
fn init_registry_component() {
|
||||
println!("[logging component init] hello world");
|
||||
log!(Level::Info, "hello world");
|
||||
info!("hello world");
|
||||
warn!("hello world");
|
||||
error!("hello world");
|
||||
trace!("hello world");
|
||||
debug!("hello world");
|
||||
}
|
||||
|
||||
/** Provide a no-op implementation when no component feature is enabled */
|
||||
#[cfg(not(feature = "enable-log"))]
|
||||
pub extern "C" fn component_init() {
|
||||
/* Empty implementation to ensure the library still links */
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "em_component_log"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
name = "em_component_log"
|
||||
crate-type = ["rlib", "staticlib"]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
enable-log = []
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../../core" }
|
||||
@@ -0,0 +1,30 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-23 foxglove log component demo
|
||||
*/
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
/* When the `enable-log` feature is enabled, expose logging module and helpers */
|
||||
#[cfg(feature = "enable-log")]
|
||||
pub mod logging;
|
||||
#[cfg(feature = "enable-log")]
|
||||
use rt_rust::println;
|
||||
#[cfg(feature = "enable-log")]
|
||||
use crate::logging::Level;
|
||||
|
||||
/* Import panic handler parameters from rt_rust library */
|
||||
use rt_rust::param::{Param, ParamItem};
|
||||
|
||||
/* Provide a no-op implementation when the `enable-log` feature is disabled */
|
||||
#[cfg(not(feature = "enable-log"))]
|
||||
pub extern "C" fn component_init() {
|
||||
/* Empty implementation to ensure the library still links */
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-20 foxglove micro rust log component
|
||||
*/
|
||||
/* Basic logging primitives and console output helpers */
|
||||
use alloc::string::String;
|
||||
use rt_rust::println;
|
||||
|
||||
#[repr(usize)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Level {
|
||||
Error = 1,
|
||||
Warn = 2,
|
||||
Info = 3,
|
||||
Debug = 4,
|
||||
Trace = 5,
|
||||
}
|
||||
|
||||
/* Top-level logging macro */
|
||||
#[macro_export]
|
||||
macro_rules! log {
|
||||
($level:expr, $($arg:tt)*) => ({
|
||||
$crate::logging::_log($level, format_args!($($arg)*));
|
||||
});
|
||||
}
|
||||
|
||||
/* Error-level logging */
|
||||
#[macro_export]
|
||||
macro_rules! error {
|
||||
($($arg:tt)*) => ({
|
||||
$crate::logging::_log($crate::logging::Level::Error, format_args!($($arg)*));
|
||||
});
|
||||
}
|
||||
|
||||
/* Warning-level logging */
|
||||
#[macro_export]
|
||||
macro_rules! warn {
|
||||
($($arg:tt)*) => ({
|
||||
$crate::logging::_log($crate::logging::Level::Warn, format_args!($($arg)*));
|
||||
});
|
||||
}
|
||||
|
||||
/* Info-level logging */
|
||||
#[macro_export]
|
||||
macro_rules! info {
|
||||
($($arg:tt)*) => ({
|
||||
$crate::logging::_log($crate::logging::Level::Info, format_args!($($arg)*));
|
||||
});
|
||||
}
|
||||
|
||||
/* Debug-level logging */
|
||||
#[macro_export]
|
||||
macro_rules! debug {
|
||||
($($arg:tt)*) => ({
|
||||
$crate::logging::_log($crate::logging::Level::Debug, format_args!($($arg)*));
|
||||
});
|
||||
}
|
||||
|
||||
/* Trace-level logging */
|
||||
#[macro_export]
|
||||
macro_rules! trace {
|
||||
($($arg:tt)*) => ({
|
||||
$crate::logging::_log($crate::logging::Level::Trace, format_args!($($arg)*));
|
||||
});
|
||||
}
|
||||
|
||||
/* Internal logging handler: formats message and prints with color */
|
||||
pub fn _log(level: Level, args: core::fmt::Arguments) {
|
||||
use core::fmt::Write;
|
||||
use rt_rust::time;
|
||||
let mut s = String::new();
|
||||
write!(&mut s, "[{:?}][{:?}]", level, time::get_time()).unwrap();
|
||||
write!(&mut s, "{}", args).unwrap();
|
||||
match level {
|
||||
Level::Error => {
|
||||
println!("\x1b[1;31m{}\x1b[0m", s);
|
||||
}
|
||||
Level::Warn => {
|
||||
println!("\x1b[1;33m{}\x1b[0m", s);
|
||||
}
|
||||
Level::Info => {
|
||||
println!("\x1b[1;32m{}\x1b[0m", s);
|
||||
}
|
||||
Level::Debug => {
|
||||
println!("\x1b[1;34m{}\x1b[0m", s);
|
||||
}
|
||||
Level::Trace => {
|
||||
println!("\x1b[1;30m{}\x1b[0m", s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import toml
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
|
||||
RUSTC_FLAGS = {
|
||||
"linker": "-C linker=ld.lld",
|
||||
"panic": "-C panic=abort",
|
||||
}
|
||||
|
||||
CARGO_CMD = {
|
||||
"base": "cargo build",
|
||||
"build_std": "-Z build-std=core,alloc,panic_abort",
|
||||
"target_flag": "--target",
|
||||
"target_arch": "%s",
|
||||
"release_profile": "--release",
|
||||
"debug_profile": "", # No additional flag for debug mode
|
||||
}
|
||||
|
||||
tools_dir = os.path.join(cwd, '..', '..', 'tools')
|
||||
sys.path.insert(0, tools_dir)
|
||||
|
||||
from build_support import detect_rust_target, ensure_rust_target_installed, clean_rust_build
|
||||
|
||||
def _has(sym: str) -> bool:
|
||||
"""Helper function to check if a configuration symbol is enabled"""
|
||||
try:
|
||||
return bool(GetDepend([sym]))
|
||||
except Exception:
|
||||
return bool(GetDepend(sym))
|
||||
|
||||
def detect_target_for_dynamic_modules():
|
||||
"""
|
||||
Detect the appropriate Rust target for dynamic modules.
|
||||
For dynamic modules, we need Linux targets instead of bare-metal targets.
|
||||
"""
|
||||
if detect_rust_target is not None:
|
||||
try:
|
||||
import rtconfig
|
||||
bare_metal_target = detect_rust_target(_has, rtconfig)
|
||||
|
||||
if bare_metal_target:
|
||||
if "riscv64" in bare_metal_target:
|
||||
return "riscv64gc-unknown-linux-gnu"
|
||||
elif "riscv32" in bare_metal_target:
|
||||
return "riscv32gc-unknown-linux-gnu"
|
||||
elif "aarch64" in bare_metal_target:
|
||||
return "aarch64-unknown-linux-gnu"
|
||||
elif "arm" in bare_metal_target or "thumb" in bare_metal_target:
|
||||
return "armv7-unknown-linux-gnueabihf"
|
||||
except Exception as e:
|
||||
print(f"Error: Target detection failed: {e}")
|
||||
raise RuntimeError(f"Failed to detect Rust target for dynamic modules: {e}")
|
||||
|
||||
print("Error: Unable to detect appropriate Rust target for dynamic modules")
|
||||
raise RuntimeError("Target detection failed - no valid target found")
|
||||
|
||||
def build_rust_module(module_dir, build_root):
|
||||
"""Build a Rust dynamic module with automatic target detection"""
|
||||
cargo_toml_path = os.path.join(module_dir, 'Cargo.toml')
|
||||
if not os.path.exists(cargo_toml_path):
|
||||
return [], [], ""
|
||||
|
||||
with open(cargo_toml_path, 'r') as f:
|
||||
cargo_config = toml.load(f)
|
||||
|
||||
module_name = cargo_config['package']['name']
|
||||
|
||||
# Detect target automatically based on the current configuration
|
||||
target = detect_target_for_dynamic_modules()
|
||||
print(f"Building Rust module '{module_name}' for target: {target}")
|
||||
|
||||
# Detect debug mode from rtconfig (same as main rust/SConscript)
|
||||
debug = bool(_has('RUST_DEBUG_BUILD'))
|
||||
build_mode = "debug" if debug else "release"
|
||||
print(f"Building in {build_mode} mode")
|
||||
|
||||
# Use global RUSTFLAGS configuration for dynamic modules
|
||||
rustflags = " ".join(RUSTC_FLAGS.values())
|
||||
|
||||
# Verify that the target is installed
|
||||
if ensure_rust_target_installed is not None:
|
||||
if not ensure_rust_target_installed(target):
|
||||
print(f"Error: Rust target '{target}' is not installed")
|
||||
print(f"Please install it with: rustup target add {target}")
|
||||
return [], [], ""
|
||||
else:
|
||||
print(f"Warning: Cannot verify if target '{target}' is installed")
|
||||
|
||||
# Set up build environment
|
||||
env = os.environ.copy()
|
||||
env['RUSTFLAGS'] = rustflags
|
||||
env['CARGO_TARGET_DIR'] = build_root
|
||||
|
||||
# Build the module with configurable parameters using dictionary configuration
|
||||
build_cmd = [
|
||||
CARGO_CMD["base"].split()[0], # 'cargo'
|
||||
CARGO_CMD["base"].split()[1], # 'build'
|
||||
CARGO_CMD["target_flag"], # '--target'
|
||||
target, # actual target architecture
|
||||
]
|
||||
|
||||
# Add profile flag based on debug mode
|
||||
profile_flag = CARGO_CMD["debug_profile"] if debug else CARGO_CMD["release_profile"]
|
||||
if profile_flag:
|
||||
build_cmd.append(profile_flag)
|
||||
|
||||
# Add build-std flag if specified
|
||||
if CARGO_CMD["build_std"]:
|
||||
build_std_parts = CARGO_CMD["build_std"].split()
|
||||
build_cmd.extend(build_std_parts)
|
||||
|
||||
try:
|
||||
subprocess.run(build_cmd, cwd=module_dir, env=env, check=True, capture_output=True)
|
||||
lib_dir = os.path.join(build_root, target, build_mode)
|
||||
return [module_name], [lib_dir], ""
|
||||
except subprocess.CalledProcessError:
|
||||
return [], [], ""
|
||||
|
||||
# Check dependencies
|
||||
if not _has('RT_RUST_BUILD_MODULES'):
|
||||
Return([])
|
||||
|
||||
build_root = os.path.join(Dir('#').abspath, "build", "rust_modules")
|
||||
|
||||
# Handle clean operation
|
||||
if GetOption('clean'):
|
||||
if clean_rust_build is not None:
|
||||
modules_build_dir = clean_rust_build(Dir('#').abspath, "rust_modules")
|
||||
if os.path.exists(modules_build_dir):
|
||||
print(f'Registering {modules_build_dir} for cleanup')
|
||||
Clean('.', modules_build_dir)
|
||||
else:
|
||||
print('No rust_modules build artifacts to clean')
|
||||
else:
|
||||
print('Warning: clean_rust_build function not available')
|
||||
else:
|
||||
# Build all Rust modules in subdirectories
|
||||
modules_built = []
|
||||
for item in os.listdir(cwd):
|
||||
item_path = os.path.join(cwd, item)
|
||||
if os.path.isdir(item_path) and os.path.exists(os.path.join(item_path, 'Cargo.toml')):
|
||||
result = build_rust_module(item_path, build_root)
|
||||
if result[0]:
|
||||
modules_built.extend(result[0])
|
||||
|
||||
if modules_built:
|
||||
print(f"Successfully built {len(modules_built)} Rust dynamic module(s): {', '.join(modules_built)}")
|
||||
|
||||
group = DefineGroup(
|
||||
'rust_modules',
|
||||
[],
|
||||
depend=['RT_RUST_BUILD_MODULES']
|
||||
)
|
||||
|
||||
Return('group')
|
||||
@@ -0,0 +1,37 @@
|
||||
# Rust build artifacts (now in build/rust)
|
||||
/target/
|
||||
**/*.rs.bk
|
||||
*.pdb
|
||||
|
||||
# Cargo lock file (optional - uncomment if you want to exclude it)
|
||||
# Cargo.lock
|
||||
|
||||
# Build directories
|
||||
/build/
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# IDE specific files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.DS_Store
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Backup files
|
||||
*.bak
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
@@ -0,0 +1,12 @@
|
||||
[workspace]
|
||||
|
||||
[package]
|
||||
name = "examplelib"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
rt-rust = { path = "../../.." }
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author notes
|
||||
* 2025-10-10 foxglove Basic library module template
|
||||
*/
|
||||
#![no_std]
|
||||
/* Bring rt-rust's println! macro into scope */
|
||||
use rt_rust::println;
|
||||
use core::ffi::{c_char, CStr};
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn rust_mylib_println(s: *const c_char) {
|
||||
if s.is_null() {
|
||||
println!("");
|
||||
} else {
|
||||
let cs = unsafe {CStr::from_ptr(s)};
|
||||
match cs.to_str() {
|
||||
Ok(msg) => println!("{}", msg),
|
||||
Err(_) => println!("[invalid UTF-8]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn rust_mylib_add(a: usize, b: usize) -> usize {
|
||||
a + b
|
||||
}
|
||||
Reference in New Issue
Block a user