rust ffi bindgen wrapper

2023-10-22 05:50
文章标签 rust wrapper ffi bindgen

本文主要是介绍rust ffi bindgen wrapper,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

rust ffi

  • rust ffi
    • rust 调用c库
    • c 调用rust库
    • C库封装给rust调用示例

rust ffi

参考
https://github.com/GzhuFlyer/rustLearn/tree/main/ffi
源代码进行文档讲解说明。

rust 调用c库

1,ffi/rust_call_c/use_snappy_lib 示例:
1.1 安装snappy库,在Cargo.toml 文件添加 [dependencies] libc = “0.2.0”
1.2 main.rs里面的 #[link(name = “snappy”)] 表示 需要链接的动态库。
1.3 extern {
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}
声明作为rust的使用
2,ffi/rust_call_c/use_callback_from_c 示例:
2.1 自己生成使用编写C库,编译后供给rust使用。
gcc -shared -fPIC extern.c -o libext.so 生成libext.so供给rust使用
在use_callback_from_c目录下执行 LIBRARY_PATH=. cargo run,运行rust程序
3, ffi/rust_call_c/show_data_type
3.1:自定义类型的使用
4, ffi/rust_call_c/call_cpp
调用c++接口函数,运行时候用下面命令
LD_LIBRARY_PATH=./target/debug ./call_rust

c 调用rust库

1,ffi/c_call_rust/share_static
执行 make static 或者 make share可以看到生成对应的动态和静态程序
2,使用rust的rust-bindgen工具生成C对应的rust接口
官方参考文档。
如果系统是centos且没有bzlib.h文件,可以执行下面命令
sudo yum whatprovides */bzlib.h
找到有 Libraries and header files for apps which will use bzip2字眼的包
然后安装一下:yum install -y bzip2-devel-1.0.6-13.el7.i686

C库封装给rust调用示例

1,cargo 创建库

 cargo new --lib rust_ffi

2修改Cargo.toml文件

[package]
name = "rust_ffi"
version = "0.1.0"
edition = "2021"
build = "build.rs"[dependencies]
[build-dependencies]
bindgen = "0.60"

2,修改rust_ffi/src/lib.rs内容为如下

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]#[cfg(test)]
mod tests {use super::*;use std::mem;include!("../bindings.rs");#[test]fn round_trip_compression_decompression() {unsafe {let input = include_str!("../futurama-quotes.txt").as_bytes();let mut compressed_output: Vec<u8> = vec![0; input.len()];let mut decompressed_output: Vec<u8> = vec![0; input.len()];// Construct a compression stream.let mut stream: bz_stream = mem::zeroed();let result = BZ2_bzCompressInit(&mut stream as *mut _,1,   // 1 x 100000 block size4,   // verbosity (4 = most verbose)0);  // default work factormatch result {r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"),r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),r if r == (BZ_OK as _) => {},r => panic!("Unknown return value = {}", r),}// Compress `input` into `compressed_output`.stream.next_in = input.as_ptr() as *mut _;stream.avail_in = input.len() as _;stream.next_out = compressed_output.as_mut_ptr() as *mut _;stream.avail_out = compressed_output.len() as _;let result = BZ2_bzCompress(&mut stream as *mut _, BZ_FINISH as _);match result {r if r == (BZ_RUN_OK as _) => panic!("BZ_RUN_OK"),r if r == (BZ_FLUSH_OK as _) => panic!("BZ_FLUSH_OK"),r if r == (BZ_FINISH_OK as _) => panic!("BZ_FINISH_OK"),r if r == (BZ_SEQUENCE_ERROR as _) => panic!("BZ_SEQUENCE_ERROR"),r if r == (BZ_STREAM_END as _) => {},r => panic!("Unknown return value = {}", r),}// Finish the compression stream.let result = BZ2_bzCompressEnd(&mut stream as *mut _);match result {r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),r if r == (BZ_OK as _) => {},r => panic!("Unknown return value = {}", r),}// Construct a decompression stream.let mut stream: bz_stream = mem::zeroed();let result = BZ2_bzDecompressInit(&mut stream as *mut _,4,   // verbosity (4 = most verbose)0);  // default small factormatch result {r if r == (BZ_CONFIG_ERROR as _) => panic!("BZ_CONFIG_ERROR"),r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),r if r == (BZ_OK as _) => {},r => panic!("Unknown return value = {}", r),}// Decompress `compressed_output` into `decompressed_output`.stream.next_in = compressed_output.as_ptr() as *mut _;stream.avail_in = compressed_output.len() as _;stream.next_out = decompressed_output.as_mut_ptr() as *mut _;stream.avail_out = decompressed_output.len() as _;let result = BZ2_bzDecompress(&mut stream as *mut _);match result {r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),r if r == (BZ_DATA_ERROR as _) => panic!("BZ_DATA_ERROR"),r if r == (BZ_DATA_ERROR_MAGIC as _) => panic!("BZ_DATA_ERROR"),r if r == (BZ_MEM_ERROR as _) => panic!("BZ_MEM_ERROR"),r if r == (BZ_OK as _) => panic!("BZ_OK"),r if r == (BZ_STREAM_END as _) => {},r => panic!("Unknown return value = {}", r),}// Close the decompression stream.let result = BZ2_bzDecompressEnd(&mut stream as *mut _);match result {r if r == (BZ_PARAM_ERROR as _) => panic!("BZ_PARAM_ERROR"),r if r == (BZ_OK as _) => {},r => panic!("Unknown return value = {}", r),}assert_eq!(input, &decompressed_output[..]);}}
}

3,创建wrapper.h文件
touch wrapper.h,并写入希望封装给rust使用的函数头文件

#include <bzlib.h>

4,在rust_ffi目录下,创建build.rs文件
touch build.rs
将下面内容复制到build.rs里面

extern crate bindgen;use std::env;
use std::path::PathBuf;fn main() {// Tell cargo to tell rustc to link the system bzip2// shared library.println!("cargo:rustc-link-lib=bz2");// The bindgen::Builder is the main entry point// to bindgen, and lets you build up options for// the resulting bindings.let bindings = bindgen::Builder::default()// Do not generate unstable Rust code that// requires a nightly rustc and enabling// unstable features.// .no_unstable_rust()// The input header we would like to generate// bindings for..header("wrapper.h")// Finish the builder and generate the bindings..generate()// Unwrap the Result and panic on failure..expect("Unable to generate bindings");// Write the bindings to the $OUT_DIR/bindings.rs file.// let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());let out_path = PathBuf::from(".");bindings.write_to_file(out_path.join("bindings.rs")).expect("Couldn't write bindings!");
}

5,编译生成rust接口文件
cargo b
在rust_ffi目录下可以查看到生成bindgens.rs文件,bindgens.rs文件的路径由下面函数指定。

//.表示当前目录
let out_path = PathBuf::from(".");

6,bindgens.rs测试
新增self.txt文件,在文件中加入以下内容

《尘曲》凡心所向,素履所往,生如逆旅,一苇以航。三月桃花,四月欢唱,两人一马,明日故乡。流浪陌路,暖然绯凉,写意人生,相识一场。不关此世,不负己心,我自倾杯,且君随意。

运行命令 cargo test 可以查看到所有测试都已通过。
在这里插入图片描述

这篇关于rust ffi bindgen wrapper的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/259464

相关文章

Rust:Future、async 异步代码机制示例与分析

0. 异步、并发、并行、进程、协程概念梳理 Rust 的异步机制不是多线程或多进程,而是基于协程(或称为轻量级线程、微线程)的模型,这些协程可以在单个线程内并发执行。这种模型允许在单个线程中通过非阻塞的方式处理多个任务,从而实现高效的并发。 关于“并发”和“并行”的区别,这是两个经常被提及但含义不同的概念: 并发(Concurrency):指的是同时处理多个任务的能力,这些任务可能在同一时

【Rust日报】 2019-04-06

Arenas vs. Indices:為型別寫函數要寫在型別裡還是外面? 作者舉了一些例子 下面簡單說明他討論的這個問題 他想為MVPArena寫一個add的函數 那把add這個函數從 impl MVPArena 移到外面 那首先就要解決生命週期的問題 struct MVPArena<T>(Vec<T>);impl<T> MVPArena<T> {fn add(&mut self, T valu

【Rust日报】 2019-04-05

「系列文章」审阅Sled源码 Part I #CodeReview #sled Sled项目是一个用Rust编写的嵌入式数据库。该文作者在日程工作中用到了它,为了掌握它的工作原理,准备开始写这个系列的博客。也可以通过学习此文,掌握一些阅读开源项目源码的技巧或其他启示,比如: 先找你擅长领域的项目去阅读,事半功倍。从整体上先把握代码组织结构、依赖库,从所获得的信息中去推测更多信息。携带某个主要的问

【Rust日报】 2019-04-04

成功故事:Rust在企业领域的应用 #zalando 本文描述了zalando公司从Scala转向Rust的成功故事。 缘起: 2016年该文作者作为Scala开发者加入了Zalando公司。半年后,他们打算开始做一个新的应用,与此同时,团队内商量该使用什么新技术,Rust就在这时被提及,同时他们也用Rust快速实现了原型,但是最后这个新应用被取消了。但Rust却成为了该团队的一门候选语言。 碰

【Rust日报】 2019-04-02

愚人节 RFCs 提议整个Rust项目由bors机器人管理。 https://github.com/rust-lang/rfcs/pull/2671 提议将Cow来默认导出 (这个我真信了) https://github.com/rust-lang/rfcs/pull/2672 信了你就瓜了。:) 台湾 COSCUP 開源人年會 COSCUP 2019 - Aug 17th-18th. NTUS

【Rust日报】 2019-04-01

Rust算法俱乐部 #algo 台湾同胞搞的Rust学习算法的教程 rust-algo.club cnx:用Rust实现的X11状态栏 #x11 cnx rustsim 报告 #5 #rustsim 简要: alga 0.9 和 nalgebra 0.18开始支持复数并且与#[no-std]保持兼容nalgebra开始在几何代数上添加对三角函数和卷积的支持等等。 Read More Rus

【Rust日报】 2019-03-31

Rust日报小组成立 从下周开始将由ChaosBot、Mike和Damody三位轮流发布日报,其中Damody为台湾同胞,如果大家看到中文繁体日报,就是他发布的。 发日报有什么好处?我来给大家透露一下。至少有三点好处: 了解Rust生态最新动态锻炼自己的总结能力。对于感兴趣的文章,可以快速汲取其主要观点。为自己的提升和学习铺垫了资料库。 所以,也欢迎大家参与Rust日报的内容建设中。 Ocyp

【Rust日报】 2019-03-30

使用rust與tensor來做臉部辨識 Read more Ocypod: 一個用Redis來備份的工作佇列 基於actix來實作,目前看起來功能還沒有 beanstalkd 之類的老牌 job queue 完整 不過效能應該是可以期待的,使用json來溝通 如果之後能直接支援 protobuff 就好了 畢竟json比protobuff慢多了 Read more sgx sdk 1.0了 In

【Rust日报】 2019-03-29

重磅:Fastly 发布 Lucet:本地 WebAssembly 编译器和运行时 昨天,Mozilla 发布了 WASI 规范,今天,Fastly(一个云基础设施服务商)就发布了 WASI 的一个实现 Lucet。 Fastly 把 Lucet 用在边缘计算上,Lucet 具有极小 runtime,可以在几 us 内加载,只占用几 K 的内存,这样就特别适合用在他们的云服务边缘计算上。 Web

【Rust日报】 2019-03-27

重磅:MeiliES - 事件源数据库 一个事件源数据库跟 Kafka 或 Rabbit MQ 类似,但是会把事件存储在磁盘上,没有上限。这个数据库服务的一个作用是,把一个流的所有事件发布给所有订阅客户端(事件按接收顺序存储)。一个客户端可以指定从哪一个编号的事件开始读取,这样就可以仅仅通过读取新事件消息来从崩溃状态中恢复。 不过,MeiliES 也可以做消息队列使用? MeiliES 内部用了