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练习】12.枚举

练习题来自:https://practice-zh.course.rs/compound-types/enum.html 1 // 修复错误enum Number {Zero,One,Two,}enum Number1 {Zero = 0,One,Two,}// C语言风格的枚举定义enum Number2 {Zero = 0.0,One = 1.0,Two = 2.0,}fn m

linux中使用rust语言在不同进程之间通信

第一种:使用mmap映射相同文件 fn main() {let pid = std::process::id();println!(

第二十四章 rust中的运算符重载

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust中的运算符重载 目录 注意一、前言二、基本使用三、常用运算符四、通用约束 一、前言 C/C++中有运算符重载这一概念,它的目的是让即使含不相干的内容也能通过我们自定义的方法进行运算符操作运算。 比如字符串本身是不能相加的,但由于C++中的String重载了运算符+,所以我们就可以将两个字符串进行相加、但实际

【Rust光年纪】Rust 机器人学库全景:功能、安装与API概览

机器人学+Rust语言=无限可能:六款库带你开启创新之旅! 前言 随着机器人技术的快速发展,对于机器人学领域的高效、可靠的编程语言和库的需求也日益增加。本文将探讨一些用于 Rust 语言的机器人学库,以及它们的核心功能、使用场景、安装配置和 API 概览,旨在为机器人学爱好者和开发人员提供参考和指导。 欢迎订阅专栏:Rust光年纪 文章目录 机器人学+Rust语言=无限可能:

第二十二章 rust数据库使用:sea-orm详解

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust数据库使用:sea-orm详解 目录 注意一、前言二、项目管理三、迁移文件四、实体文件五、业务使用 一、前言 只要开发稍微大型一点的项目,数据库都是离不开的。 rust目前并没有特别成熟的数据库框架,sea-orm这个框架是我目前所看到的成熟度最高的一个,并且仍在积极开发中。 所以本文将以sea-orm框

Rust使用之【宏】

一、简单使用clap clap = { version = "4.5.17", features = ["derive"] } 其中,什么是features = ["derive"]:表示你希望在添加 clap 依赖时启用 derive 特性。这通常意味着你希望使用 clap 的派生(derive)宏功能,这些功能可以简化创建命令行接口的代码。例如,derive 特性可以让你使用 #[der

第二十一章 rust与动静态库的结合使用

注意 本系列文章已升级、转移至我的自建站点中,本章原文为:rust与动静态库的结合使用 目录 注意一、前言二、库生成三、库使用四、总结 一、前言 rust中多了很多类型的库,比如前面章节中我们提到基本的bin与lib这两种crate类型库。 如果你在命令行执行下列语句: rustc --help 那么你将能找到这样的内容: --crate-type [bin|li

Rust的常数、作用域与所有权

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学,之一  -CSDN博客 Rust到底值不值得学,之二-CSDN博客 Rust的数据类型-CSDN博客 3.7  常数的数据类型 在Rust语言中,变量有类型,常量也有类型。我们知道,在定义const常量的时候,就要

搭建Rust的开发环境

目标 我没有使用过Rust,但我听说它是一个可靠的语言,可以保证内存安全和线程安全。我对此很有兴趣,就想试一试这个语言。 在官网上有介绍他们所推荐的编辑器: 我将选择 Visual Studio Code (关于 【Visual Studio】和【Visual Studio Code】的区别:【VS】是完整的集成开发环境,而【VSCode】只算的上是一个相对轻量级的文本编辑器,并附带一些便捷

Rust的数据类型

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学,之一  -CSDN博客 Rust到底值不值得学,之二-CSDN博客 3.5  数据类型的定义和分类 在Rust编程中,所谓数据类型,就是对数据存储的安排,包括存储单元的长度(占多少字节)以及数据的存储形式。不同的