Rust : 与C多种交互尝试

news2024/11/28 10:41:41

rust调用C端的库函数,有很多方法,场景也有所不同。包括windows还是linux,内置库还是自定义库,还是三方库等等。

一、rust调用其内置的C库
这个很简单,直接把extern "C"引入即可:
比如,在rust端main.rs中:

use std::os::raw::c_int;//f32
use std::os::raw:c_double;// f64
extern "C" {
	fn abs(num:c_int) ->c_int;
	fn sqrt(num:c_double) ->c_double;
}
fn main{
	println!("call c->abs :{}",unsafe{abs(-32)});
	println!("call c -> sqrt:{}",unsafe{sqrt(36.0)});
}

不需要做其它的处理,直接cargo run 就可以运行。

二、自定义的C库-以windows平台为例

如果rust要调用自建的C库中的函数,情况会较上面复杂一些。今天介绍通过cc库,通过build生成脚本的方式,实现rust调用c端库函数。

1、相关准备:
在这里插入图片描述
在ffi目录下,创建了c_part和rust_ffi文件夹。 c_part下放了ctools.c文件,里面有一些库函数,需要让rust调用。当然,ctools.c也可以放在其它地方,只需要后面的地址一致即可以。

2、cargo toml部分
在这里插入图片描述这里需要注意:

build="build.rs"
libc ="0.2"
cc ="1.0"

有一些依赖和说明。
3、ctools.c

// ctools.c 代码
int add(int i,int j){
    return i+j;
}
int two_times(int input){
    return input*2;
}
int three_times(int input){
    return input*3;
}

4、build.rs文件

extern crate cc;

fn main(){
    cc::Build::new().file("../c_part/ctools.c").compile("libctools.a");

}

cc::Build::new().file(“…/c_part/ctools.c”).compile(“libctools.a”);的作用是使用 cc crate 编译 …/c_part/ctools.c文件,并将生成的静态库命名为 libctools.a。

(1)需要注意的是,生成的静态库或动态库的命名和文件格式可能会因操作系统和编译器的不同而有所区别。例如,在 Windows 系统上,静态库的命名通常是 libctools.a,而动态库的命名通常是 ctools.dll。生成静态库或动态库后,就可以使用 Rust 的 #[link(name = “ctools”)] 属性来链接库文件并在 Rust 代码中调用 C 函数了。
如果没有在 Rust 代码中使用 #[link(name = “ctools”)] 属性来指定链接的库的名称,Rust 编译器会默认按照一定的规则搜索系统默认的库文件路径来查找库文件。具体来说,Rust 编译器会按照以下顺序搜索库文件:

在系统默认的库搜索路径中查找:Rust 编译器会搜索系统默认的库文件路径,例如 /usr/lib 和 /usr/local/lib 等目录。
在 Rust 代码所在的目录中查找:如果 Rust 代码和库文件在同一个目录中,Rust 编译器会在该目录中查找库文件。
在指定的搜索路径中查找:如果在编译 Rust 代码时使用了 -L 参数指定了库文件搜索路径,Rust 编译器会在这些路径中查找库文件。

注:此部分内容来源以下链接,在此特别说明。

https://vincebye.github.io/posts/rust%E8%B0%83%E7%94%A8c%E4%BB%A3%E7%A0%81/

(2 )需要注意的是,file中ctool.c文件地址一定要准确,否则会有如下报错信息(但没有明示说路径不对,找不到文件之类)。报错可能如下(下面标红处路径是故意写错路径的情况):
在这里插入图片描述5、rust端:main.rs

extern crate libc;
use libc::c_int;
extern "C" {
    fn add(i:c_int,j:c_int)  ->c_int;
    fn two_times(input:c_int) ->c_int;
    fn three_times(input:c_int) ->c_int; 
}

fn main() {
    println!("Hi guys, welcome rust ffi !");
    let twotimes_value:i32 = unsafe{two_times(-8)};
    println!("twotimes_value  : {:?}",twotimes_value);
    let add_value = unsafe{add(2,3)};
    println!("add_value       : {:?}",add_value);
    let threetimes_value = unsafe{three_times(3)};
    println!("threetimes_value: {:?}",threetimes_value);
}

引入libc库,以及c_int类型。

6、cargo build
如果配置正确,在rust_ffi目录下(build.rs所在目录),运行cargo build:在这里插入图片描述可见build成功。

7、cargo run

在这里插入图片描述相关结果表明,rust端已经正确调用了ctools.c中几个库函数。
注意的是,因为已经是ffi调用,均需要加unsafe。

三、rust调用C封装好的静态库

(一)、linux平台
总体物料安排和上面windows平台自定义库类似,不再详述。
在这里插入图片描述

1、toml文件 , 其实只需要加“build”项,不需要cc库。

[package]
name = "myffi"
version = "0.1.0"
edition = "2021"
build   ="build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

2、准备生成相应的静态库供调用
在cpart目录下,有ctools.c文件
在这里插入图片描述
在cpart目录下,运行以下命令,生成了libcrust.a静态链接库。

gcc -c ctools.c -o crust.o
ar -cr libcrust.a crust.o

如果发现在对应目录下,已经生成libcrust.a文件,证明已经成功。

3、build.rs
build.rs中,主要一个是rustc-link-lib和rustc-link-search(此处我用了绝对地址)两项即可。具体如下:

fn main(){
    println!("cargo:rustc-link-lib=crust");
    println!(r"cargo:rustc-link-search=native=/home/songroom/ffi/cpart");
}

值得说明一下,build.rs中println!中"cargo:"的输出,是一种类“告示”通信方式,并不是一种简单的常规的打印。这个是告诉编译器,你去帮我这么干,没有这些,链接就不会成功,绝对不是或有或无的。

4、main.rs

加注了一个#[link=(name=“crust”,kind=“static”)]。
注意,尽管静态库名是libcurst,但在链接属性这,crust前面不要加lib。

extern crate libc;
use libc::c_int;
#[link=(name="crust",kind="static")]
extern "C" {
    fn add(i:c_int,j:c_int)  ->c_int;
    fn two_times(input:c_int) ->c_int;
    fn three_times(input:c_int) ->c_int; 
}

fn main() {
    println!("Hi guys, welcome rust ffi !");
    let twotimes_value:i32 = unsafe{two_times(-8)};
    println!("twotimes_value  : {:?}",twotimes_value);
    let add_value = unsafe{add(2,3)};
    println!("add_value       : {:?}",add_value);
    let threetimes_value = unsafe{three_times(3)};
    println!("threetimes_value: {:?}",threetimes_value);
}

5、配置路径

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:pwd

6、在build.rs的目录下cargo build

root@DESKTOP-MEDPUTU:/home/songroom/ffi/myffi/src# cargo build
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s

7、cargo run

root@DESKTOP-MEDPUTU:/home/songroom/ffi/myffi/src# cargo run
   Compiling myffi v0.1.0 (/home/songroom/ffi/myffi)
    Finished dev [unoptimized + debuginfo] target(s) in 0.44s
     Running `/home/songroom/ffi/myffi/target/debug/myffi`
Hi guys, welcome rust ffi !
twotimes_value  : -16
add_value       : 5
threetimes_value: 9

(二)、在windows平台
上面的方式,在windows还未成功,待续。

此外,动态库应差不多,有机会待尝试。

四、C调rust:以linux平台为例
在windows平台操作,不如linux平台方便。
1、结构
建立两个平行目录,c_call下放.c文件;另一个就是rustoc工程(通过cargo new rustoc --lib建立) ,是一个rust lib文件。
在这里插入图片描述2、rustoc文件夹下lib.rs

use std::os::raw::{c_int,c_double};
extern "C"{
    fn abs(num:c_int) ->c_int;
    fn sqrt(x:c_double) ->c_double;
}
#[no_mangle]
pub extern "C" fn rfn_for_c(){
    println!("call from rust fn abs :{}",unsafe{abs(-6)});
    println!("call from rust fn sqrt :{}",unsafe{sqrt(36.0)});
}

这个lib.rs中一方面引用了C库中 的两个函数,另一方面, rfn_for_c函数也输出给C调用。
3、rustoc下toml文件
在这里,lib项选择了dylib(动态链接库方式),当然也可以选择staticlib(静态链接库)项。

[package]
name = "rusttoc"
version = "0.1.0"
authors = ["songroom <sognroom@qq.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type =["dylib"]
[dependencies]

4、在rusttoc文件夹下,cargo build
查看一下,是否生成相关的.so文件。这个文件后面需要被.c文件调用。

5、c_call文件夹下,建立一个callrust.c文件

#include <stdio.h>
extern void rfn_for_c(void);
int main(){
    printf("hello,c call rust !\n");
    rfn_for_c();
    return 0;
}

6、c_call文件夹下gcc,并设置.so文件相应的路径临时变量

songroom@staff-NB-146:~/myffi/c_call$ gcc callrust.c -o callrust -lrusttoc -L../rusttoc/target/debug
songroom@staff-NB-146:~/myffi/c_call$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../rusttoc/target/debug

关于“-lrusttoc -L…/rusttoc/target/debug”:
(1)-lrusttoc:是指链接rustoc.so
(2)-L…/rusttoc/target/debug:是在“…/rusttoc/target/debug”路径上搜索相应的文件。
可以看到,相应的文件callrust文件已经生成。
LD_LIBRARY_PATH临时设置变量,如果需要设置永久路径, ~/.bashrc 或者 ~/.bash_profile下进行设置。

7、在c_call文件夹下,运行

songroom@staff-NB-146:~/myffi/c_call$ ./callrust
hello,c call rust !
call from rust fn abs :6
call from rust fn sqrt :6

可见,在linux平台下,c调用rust中的库代码成功。
在这里插入图片描述
五、用cbindgen实现rust与c类型交互类型,并实现互调
此外,还有一些场景,有待深入:
1、上面主要讲的rust调C,并没有涉及C如何调Rust。如何实现C和Rust之间的互调?
2、此外,C类库中头文件中有各种不同的复杂自定义类型,且内容很多,如果没有一个自动化的工具来实现对应转换,两者的交互会很困难。
当然,cbindgen 不但可以生成 C 头文件,也可以针对C头文件生成rust的类型,便于交互。
待续。

六、总结及提示
1、和linux相比,windows平台之间RUST与C调用不太友好;如果可以尽可能在linux平台下,windows for linux也是可以的。
2、build.rs要放在main.rs同一个目录,否则可以无效。
3、build.rs中的库的路径指定是关键之一。具体见build.rs内容。
4、如果多次调用,还是把临时路径变量设置为永久,否则另一次运行仍可能还是找不到相应的库文件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1028515.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

dvwa靶场通关(十二)

第十二关&#xff1a;Stored Cross Site Scripting (XSS)&#xff08;存储型xss&#xff09; low 这一关没有任何防护&#xff0c;直接输入弹窗代码 弹窗成功 medium 先试试上面的代码看看&#xff0c;有没有什么防护 发现我们的script标签不见了&#xff0c;应该是被过滤掉…

CentOS7下制作OpenSSH 9.4p1 RPM包,并验证升级

1、准备条件 1&#xff09;openssh-8.4p1.tar.gz源码包 https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.4p1.tar.gz wget https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-9.4p1.tar.gz --no-check-certificate 2&#xff09;x11-ssh-askp…

Django实现音乐网站 ⒅

使用Python Django框架做一个音乐网站&#xff0c; 本篇主要为歌单列表、歌单详情及推荐页-歌单内容改动。 目录 歌单列表 设置路由 视图处理 模板渲染 歌单-单曲列表 设置路由 视图处理 模板渲染 推荐页-歌单列表 模板渲染修改 总结 歌单列表 可通过导航>歌单或…

如何批量将长视频分割成短视频?详细操作步骤一目了然

如果你需要将一个长视频分割成多个短视频&#xff0c;你可以使用固乔智剪软件来实现这一目标。以下是详细步骤&#xff1a; 1. 在浏览器中搜索并下载"固乔智剪软件"。这个软件是专门用于视频剪辑和处理的&#xff0c;它提供了许多实用的功能。 2. 进入软件主页&#…

外贸独立站哪家好?推荐的独立站建站平台?

如何选外贸独立站搭建系统&#xff1f;创建贸易网站的工具有哪些&#xff1f; 在如今全球贸易不断蓬勃发展的背景下&#xff0c;外贸独立站成为许多企业拓展国际市场的首选之一。然而&#xff0c;要想在竞争激烈的市场中脱颖而出&#xff0c;选择一家合适的外贸独立站服务提供…

error:03000086:digital envelope routines::initialization error问题解决

目录 问题描述&#xff1a;error:03000086:digital envelope routines::initialization error 问题原因&#xff1a;nodejs V17 版本发布了 OpenSSL3.0 对算法和秘钥大小增加了更为严格的限制&#xff0c;nodeJs v17 之前版本没影响&#xff0c;但 V17 和之后版本会出现这个错…

Learn Prompt-基础用法

基本法则​ 相比于搜索引擎&#xff0c;ChatGPT的优势在于其高效的想法关联和信息归纳能力。在进一步讲解提示的构建思路前&#xff0c;我希望你可以了解到两点通用的经验法则&#xff0c;用来提高生成AI模型的输出质量。其中包括 尝试提示的多种表述以获得最佳结果使用清晰简…

良好的测试环境应该怎么搭建?对软件产品起到什么作用?

为了确保软件产品的高质量&#xff0c;搭建一个良好的测试环境是至关重要的。在本文中&#xff0c;我们将从多个角度出发&#xff0c;详细描述良好的测试环境的搭建方法、注意事项以及对软件产品的作用。    一、软件测试环境的搭建   1、从硬件设备的选择与配置开始。对于…

大数据导论 四、JDK安装部署

1、下载JDK 官网 https://www.oracle.com/java/technologies/downloads/archive/ 下载 jdk-8u333-linux-x64.tar.gz 上传 2、解压 解压 3、配置环境变量 编辑文件 追加内容 保存并退出 刷新环境变量 4、验证

10分钟带你初步了解 Service Worker

是什么&#xff1f; 服务器与浏览器的中介持久的浏览器离线缓存 有什么用&#xff1f; 解放主线程&#xff0c;节省资源加载&#xff0c;提高浏览体验 其他描述 基于web worker&#xff0c;并在其基础上&#xff0c;增加了离线缓存的功能独立于当前网页线程&#xff08;后台…

3-D HANet:一种用于目标检测的柔性三维 HeatMap 辅助网络

论文背景 室外场景感知使用 Lidar&#xff1a; 1.点云数据不受天气(雾、风暴、雨和雪)的影响&#xff0c;支持稳定的环境感知&#xff1b; 2.点云数据在很大程度上保留了原来中物体的空间结构特征。 3D 目标检测是室外场景感知的重要组成部分。 从一个不完整的点云空间结构中…

如何快速在 Apache DolphinScheduler 新扩展一个任务插件?

作者 | 代立冬 编辑 | Debra Chen Apache DolphinScheduler 是现代数据工作流编排平台&#xff0c;具有非常强大的可视化能力&#xff0c;DolphinScheduler 致力于使数据工程师、分析师、数据科学家等数据工作者都可以简单轻松地搭建各种数据工作流&#xff0c;让数据处理流程…

使用Python绘制多个股票的K线图

K线图是金融领域常用的技术分析工具&#xff0c;可以洞察地展示股票的开盘价、收盘价、最高价和最低价等信息。在投资决策中&#xff0c;对多个股票的走势进行对比分析是非常重要的。随着金融市场的发展&#xff0c;投资者对于多种股票的对比分析需求越来越高。传统的方式是通过…

tokio::net学习

tokio::net 该模块包含TCP/UDP/Unix网络类型,类似于标准库,可用于实现网络协议。 networking protocols Organization TcpListener and TcpStream provide functionality for communication over TCP UdpSocket provides functionality for communication over UDP UnixLi…

信创办公–基于WPS的PPT最佳实践系列 (项目8创建电子相册)

信创办公–基于WPS的PPT最佳实践系列 &#xff08;项目8创建电子相册&#xff09; 目录 应用背景操作步骤 应用背景 如果我们想把图片弄成相册&#xff0c;或者弄成一段有音乐的视频分享给朋友。我们可以利用PPT来制作。那我们如何用PPT制作电子相册或视频呢&#xff1f;可以跟…

21天学会C++:Day13----动态内存管理

CSDN的uu们&#xff0c;大家好。这里是C入门的第十三讲。 座右铭&#xff1a;前路坎坷&#xff0c;披荆斩棘&#xff0c;扶摇直上。 博客主页&#xff1a; 姬如祎 收录专栏&#xff1a;C专题 目录 1. 加深对内存四区的理解 2. new-delete 与 malloc-free 2.1 能否用 fre…

Django:一、创建项目、APP及启动Django

一、准备工具 Pycharm企业版 二、创建项目 打开Pycharm企业版&#xff0c;创建Django项目。 注意&#xff1a;①删除项目下的templates文件夹&#xff1b;②删除setting.py文件中的一行代码 默认文件介绍&#xff1a; 三、创建APP 点击Pycharm左下角Terminal&#xff0c;打…

基于Android+OpenCV+CNN+Keras的智能手语数字实时翻译——深度学习算法应用(含Python、ipynb工程源码)+数据集(四)

目录 前言总体设计系统整体结构图系统流程图 运行环境模块实现1. 数据预处理2. 数据增强3. 模型构建4. 模型训练及保存5. 模型评估6. 模型测试1&#xff09;权限注册2&#xff09;模型导入3&#xff09;总体模型构建4&#xff09;处理视频中的预览帧数据5&#xff09;处理图片数…

区块链技术:解密去中心化的革命

文章目录 区块链的基础概念什么是区块链&#xff1f;区块链的核心原理1. 分布式账本2. 区块3. 加密技术4. 共识机制 区块链的工作原理区块链的交易过程区块链的安全性共识机制的作用 区块链的应用领域1. 金融服务2. 供应链管理3. 物联网4. 医疗保健5. 政府与公共服务 区块链的未…

图像练习OpenCV(01)

提取出里面最大矩形的四个顶点坐标 源图像 结果展示 代码 void getLine(std::vector<int>& data, int threshold) {for (int x 0; x < data.size(); x){if (0 data[x]){continue;}int maxValue 0, maxLoc -1, i -1;for (i x; i < data.size(); i){if …