Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
rust
换个rust的使用方式:C调用rust
发布于 2020-12-27 13:00:50 浏览:2180
订阅该版
[tocm] ## 引言 工作中的嵌入式项目,基本都是C语言。 一直想在项目中引入一个略高级的语言,来填补C语言的一些不足。 之前有用过[MicroPython](http://www.micropython.org/)和javascript,但除了性能和体积外,都有些要把主要工作转到新语言的感觉,要做不少的对接工作。 也用过Lua,感觉也差不多。 ## 评估 学习评估[Rust](https://www.rust-lang.org/zh-CN/)语言时,感觉性能和体积应该都不会有太大的问题。加上语言本身主打的安全性,再结合一些库,用来做一些C语言不擅长的动态操作感觉比较合适。 但如果把主要工作切过来,感觉Rust目前又太荒芜了,而且上面的问题也同样存在。 ## 尝试 了解到Rust可以编译成静态库,于是动了只用Rust实现其中一小部分功能的想法。 随手一搜,找到这篇文章: [c语言调用rust库函数](https://zhuanlan.zhihu.com/p/269624929) 按步骤做完,倒是挺顺利,增强了信心。 ### 编译arm版静态库 上面测试都是在x86上面进行的,嵌入式基本是使用arm和riscv等芯片。 考虑到上手门槛,我这里选择了[qemu-vexpress-a9](https://gitee.com/rtthread/rt-thread/tree/master/bsp/qemu-vexpress-a9)这个bsp做为我们的目标平台。 这样不用开发板就可以测试了。 先要安装目标环境,可以参考这个链接:[Rust 嵌入式开发 STM32 和 RISC-V](https://club.rt-thread.org/ask/question/424079.html) ``` rustup target list rustup target add armv7a-none-eabi rustup target list | grep installed ``` 安装好目标环境后,开始尝试编译arm版的静态库 ``` $ cat src/lib.rs #[no_mangle] pub extern "C" fn foo(a: i32, b: i32) { println!("hello : a + b = {}", a + b); } $ cargo build --target=armv7a-none-eabi warning: unused manifest key: build Compiling foo v0.1.0 (/home/aozima/work/rust_study/foo) error[E0463]: can't find crate for `std` | = note: the `armv7a-none-eabi` target may not be installed error: aborting due to previous error For more information about this error, try `rustc --explain E0463`. error: could not compile `foo` To learn more, run the command again with --verbose. ``` 查了一些资料 * https://forge.rust-lang.org/release/platform-support.html * https://blog.csdn.net/readlnh/article/details/88899586 对于没有移植标准库的目标环境,需要添加 `#![no_std]` ``` $ cat src/lib.rs #![no_std] #[no_mangle] pub extern "C" fn foo(a: i32, b: i32) { println!("hello : a + b = {}", a + b); } ``` 这下错误提示变成了 `cannot find macro `println` in this scope` 考虑到先简单做测试,于是先注释掉打印,改为纯运算。 ```rust $ cat src/lib.rs #![no_std] #[no_mangle] pub extern "C" fn foo(a: i32, b: i32) -> i32 { //println!("hello : a + b = {}", a + b); return a+b; } ``` 这下错误提示变成了 `error: `#[panic_handler]` function required, but not found` 参考资料[独立式可执行程序](https://learningos.github.io/rcore_step_by_step_webdoc/docs/%E7%8B%AC%E7%AB%8B%E5%BC%8F%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F.html),添加必要的 `panic` ``` $ cat src/lib.rs #![no_std] use core::panic::PanicInfo; #[no_mangle] pub extern "C" fn foo(a: i32, b: i32) -> i32 { //println!("hello : a + b = {}", a + b); return a+b; } #[panic_handler] fn panic(_info:&PanicInfo) -> !{ loop{} } ``` 终于成功编译 ``` $ cargo build --target=armv7a-none-eabi warning: unused manifest key: build Compiling foo v0.1.0 (/home/aozima/work/rust_study/foo) Finished dev [unoptimized + debuginfo] target(s) in 0.10s $ ls target/armv7a-none-eabi/debug/libfoo.a ``` ## 使用静态库 把编译出来的 libfoo.a 复制到 qemu-vexpress-a9的`applications/libs`目录下, 并更新 `applications/SConscript` ```patch -group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH) +LIBS = ["libfoo.a"] # 添加静态库文件 +LIBPATH = [os.path.join(GetCurrentDir(), 'libs')] # 添加静态库搜索路径 + +group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH, LIBS = LIBS, LIBPATH = LIBPATH) ``` ### C中引用静态库中的函数 ``` #include
#include
#include
extern int foo(int a, int b); // 声明一个函数 int main(void) { int tmp; printf("hello rt-thread\n"); tmp = foo(1, 2); printf("call rust fn: foo(1, 2) == %d\n", tmp); return 0; } ``` 在链接时发生报了错误 ``` $ scons --verbose ... -Lapplications\libs -lfoo -lc -lm /armv7-ar/thumb\libgcc.a(_arm_addsubdf3.o): In function `__aeabi_ul2d': (.text+0x304): multiple definition of `__aeabi_ul2d' applications\libs\libfoo.a(compiler_builtins-9b744f6fddf5e719.compiler_builtins.20m0qzjq-cgu.117.rcgu.o): /cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.35/src/float/conv.rs:143: first defined here ``` 提示在rust的静态库libfoo.a中也有__aeabi_ul2d的实现,与libgcc.a中冲突。 这点暂时没理解得太清楚,不过release版本编译的库没有引入这个实现 ``` $ cargo build --target=armv7a-none-eabi --release $ ls target/armv7a-none-eabi/release/libfoo.a ``` 把release版的libfoo.a复制到`applications/libs`目录下, 再次编译链接通过 ``` $ scons --verbose ... -Lapplications\libs -lfoo -lc -lm arm-none-eabi-objcopy -O binary rtthread.elf rtthread.bin arm-none-eabi-size rtthread.elf text data bss dec hex filename 593317 5212 85056 683585 a6e41 rtthread.elf scons: done building targets. ``` 在qemu中运行成功 ``` \ | / - RT - Thread Operating System / | \ 4.0.3 build Dec 26 2020 2006 - 2020 Copyright by rt-thread team lwIP-2.0.2 initialized! hello rt-thread call rust fn: foo(1, 2) == 3 msh /> ``` ## 体积与性能分析 把生成的elf进行反汇编 ```asm 60010040
: 60010054: fa01f69b blx 6008dac8
60010058: e3a01002 mov r1, #2 6001005c: e3a00001 mov r0, #1 60010060: eb01f2ea bl 6008cc10
6008cc10
: 6008cc10: e0810000 add r0, r1, r0 6008cc14: e12fff1e bx lr ``` 可以看到,纯运算类的体积与性能,与C版本完全一致, 其它高级特性可能会对堆的使用较多,但只要遵守rust的规范,写穿溢出的可能性应该极小。 纯运算和对栈的使用,应该不会有太大的差异。
2
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
aozima
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
文章
28
回答
4480
被采纳
381
关注TA
发私信
相关文章
1
Rust 嵌入式开发 STM32 和 RISC-V
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部