Rust : 与C交互动态库和静态库的尝试

这篇具有很好参考价值的文章主要介绍了Rust : 与C交互动态库和静态库的尝试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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、相关准备:
rust使用c代码,Rust,C,rust,c语言,交互
在ffi目录下,创建了c_part和rust_ffi文件夹。 c_part下放了ctools.c文件,里面有一些库函数,需要让rust调用。当然,ctools.c也可以放在其它地方,只需要后面的地址一致即可以。

2、cargo toml部分
rust使用c代码,Rust,C,rust,c语言,交互这里需要注意:

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文件地址一定要准确,否则会有如下报错信息(但没有明示说路径不对,找不到文件之类)。报错可能如下(下面标红处路径是故意写错路径的情况):
rust使用c代码,Rust,C,rust,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:rust使用c代码,Rust,C,rust,c语言,交互可见build成功。

7、cargo run

rust使用c代码,Rust,C,rust,c语言,交互相关结果表明,rust端已经正确调用了ctools.c中几个库函数。
注意的是,因为已经是ffi调用,均需要加unsafe。

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

(一)、linux平台
总体物料安排和上面windows平台自定义库类似,不再详述。
rust使用c代码,Rust,C,rust,c语言,交互

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文件
rust使用c代码,Rust,C,rust,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文件。
rust使用c代码,Rust,C,rust,c语言,交互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中的库代码成功。
rust使用c代码,Rust,C,rust,c语言,交互
五、用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在工程中的路径:如果程序入口在rust侧,build.rs则放在rust入口程序同一文件夹下;
3、build.rs中的库中println!中cargo:路径指定是关键之一。具体见build.rs内容。
4、如果多次调用,还是把临时路径变量设置为永久,否则另一次运行仍可能还是找不到相应的库文件。文章来源地址https://www.toymoban.com/news/detail-763923.html

到了这里,关于Rust : 与C交互动态库和静态库的尝试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于静态库和动态库的操作

    目录 静态库 动态库 1.增加.o文件: 2.删除.o文件: 查看静态库和动态库中的函数名 1.查看静态库中的函数名(以libexample.a为例): 2. 查看动态库中的函数名(以libexample.so为例): 查看动态库和静态库是32位,还是64位 1.  如果是动态库,可以使用: file *.so   2. 如果是静态库,可

    2024年02月07日
    浏览(27)
  • 静态链接库和动态链接库的区别

    在编译时将库的代码( .lib文件 )和应用程序的代码合并在一起,生成一个单独的可执行文件。 发布时非常方便,直接一个.exe文件即可 库的代码在编译时和链接时与应用程序分开。应用程序包含对库的引用( .lib文件 ,在这里被称为导入库),但不包含库的实际代码。 在 运行

    2024年02月11日
    浏览(29)
  • 【Linux系统编程】Linux下的编译器——gcc/g++的使用 及 动态库和静态库的认识

    这篇文章我们继续学习Linux中的开发工具,今天要学的是: Linux下的编译器——gcc/g++ 我们先来简单了解一下它们的概念: gcc (GNU Compiler Collection) 和 g++ 是 Linux 系统上最常用的编译器。它们是 GNU 组织开发的一套开源编译器工具集。 gcc: gcc 是 GNU 编译器集合中的 C 语言编译器。

    2024年02月16日
    浏览(34)
  • 20天学会rust(四)常见系统库的使用

    前面已经学习了rust的基础知识,今天我们来学习rust强大的系统库,从此coding事半功倍。 在 Rust 中,有两种主要的数组类型:固定长度数组(Fixed-size Arrays)和可变长度数组(Dynamic-size Arrays)。 固定长度数组(Fixed-size Arrays): 固定长度数组的长度在编译时就确定,并且长度

    2024年02月13日
    浏览(22)
  • cmake-动态库和静态库及使用OpenCV第三方库

     项目中会有单个源文件构建的多个可执行文件的可能。项目中有多个源文件,通常分布在不同子目录中。这种实践有助于项目的源代码结构,而且支持模块化、代码重用和关注点分离。同时,这种分离可以简化并加速项目的重新编译。 add.h add.cpp main.cpp  首先这是我们的目

    2024年01月24日
    浏览(29)
  • 动态库、静态库的构建与使用

    所谓静态、动态是指 链接 。回顾一下,将一个程序编译成可执行程序的步骤: 链接 : 把外部函数的代码(通常是后缀名为.lib和.a的文件),添加到可执行文件中。这就叫做连接(linking)。这种通过拷贝,将外部函数库添加到可执行文件的方式,叫做静态连接(static linki

    2024年02月06日
    浏览(34)
  • 【嵌入式学习笔记-02】什么是库文件,静态库的制作和使用,动态库的制作和使用,动态库的动态加载

    【嵌入式学习笔记-02】什么是库文件,静态库的制作和使用,动态库的制作和使用,动态库的动态加载 单一模型: 将程序中所有功能全部实现于一个单一的源文件内部。编译时间长,不易于维护和升级不易于协作开发。 分离模型 将程序中的不同功能模块划分到不同的源文件

    2024年01月15日
    浏览(41)
  • 【linux深入剖析】动态库的使用(续) | 动静态库的链接

    🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 回顾上节,我们在创建了动态库libmymath.so 我们使用指令 gcc main.c -L. -lmymath -L . (-L + 路径表示myc这个库在哪

    2024年04月15日
    浏览(30)
  • 尝试以语法对照表格形式学习新语言:c,rust

    以语法对照表格形式学习新语言,以rust为例。 关于rust的个人看法: 能否替代c?部分场景可以,长远看并不会。如果c再扩一些,类似cpp的吸星大法式扩充,rust并不具备优势。 解决了c的内存管理问题?部分解决。所有权概念是将c中内存管理模式加了约束,并在编译期

    2024年02月19日
    浏览(23)
  • Rust:使用libloader调用动态链接库 (DLL)

    掘金为同人创作:掘金 最近需要使用Rust 动态调用 动态链接库,本来打算是使用 libloading 的,但是 libloading 在调用dll中的函数的时,是必须要在编译时确定参数和return的类型的。但后来发现了 libloader 这个包包, libloader 是基于 libloading 的,但是操作起来却比 libloader 方便。

    2023年04月10日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包