服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

Rust学习资料

日期: 来源:程序喵大人收集编辑:程序喵大人

最近在研究Rust,目前大多数项目都可以使用Rust开发,但是涉及到和其他语言交互,比如用Rust开发一个SDK,一般还是需要导出C接口。


那如何将Rust导出C接口?

Rust的FFI就是专门做这件事的。一个正常的Rust public接口长这样:

pub fn hello_world() -> i32 {    20}

如果要把一个Rust函数导出为C接口,需要对它进行改造:

#[no_mangle]pub extern "C" fn hello_world() -> i32 {    20}

它相比于纯Rust函数有两点不同:

一个是extern "C":表示导出C接口

一个是#[no_mangle]:正常一个C++或者Rust函数相关的符号都特别长且难以理解,使用它表示导出的符号是C符号,即没有任何多余的修饰,函数名是啥样,相关的符号大概就是啥样,如图:

如何导出C的动态库或者静态库?

如果想要编译出动态库或者静态库,可以在Cargo.toml中配置crate-type:

[lib]crate-type = ["cdylib"] # Creates dynamic lib# crate-type = ["staticlib"] # Creates static lib

cylib表示导出动态库,staticlib表示导出静态库。


如何生成对应的C头文件?

一个C库一般都有个头文件,那Rust怎么生成一个C的头文件呢?可以使用cbindgen:

cbindgen --config cbindgen.toml --crate hello_world --output hello_world.h

其中cbindgen.toml是一个template文件,我后面链接中列了具体地址。


上面的hello_world函数,我使用cbindgen就可以自动生成一个头文件:

#pragma once
#include <stdarg.h>#include <stdbool.h>#include <stddef.h>#include <stdint.h>#include <stdlib.h>
#ifdef __cplusplusextern "C" {#endif // __cplusplus
int32_t hello_world(void);
#ifdef __cplusplus} // extern "C"#endif // __cplusplus

至于如何使用更复杂的类型和C交互,比如我想导出和传入一个结构体的指针,比如我想设置const char*,以及怎么管理对应的内存?


可以直接看这段代码:

use std::boxed::Box;use std::ffi::CStr;use std::ffi::CString;use std::os::raw::c_char;
pub struct Manager { path: CString,}
fn get_default_cstring() -> CString { CString::new("").expect("new string failed")}
#[no_mangle]pub extern "C" fn manager_create() -> *mut Manager { println!("{}", "create_manager().".to_string()); Box::into_raw(Box::new(Manager { path: get_default_cstring(), }))}
#[no_mangle]pub extern "C" fn manager_destroy(ptr: *mut Manager) { if ptr.is_null() { return; }
// safe unsafe { let _b = Box::from_raw(ptr); }}
impl Manager { #[no_mangle] pub extern "C" fn manager_set_path(&mut self, p: *const c_char) { unsafe { self.path = CString::from(CStr::from_ptr(p)); } }
#[no_mangle] pub extern "C" fn manager_get_function(&self) -> *const c_char { self.path.as_ptr() }}
#[no_mangle]pub extern "C" fn hello_world() -> i32 { 20}

也许有人不太理解Rust代码的含义,那可以直接看它对应的C Header:

#pragma once
#include <stdarg.h>#include <stdbool.h>#include <stddef.h>#include <stdint.h>#include <stdlib.h>
typedef struct Manager Manager;
#ifdef __cplusplusextern "C" {#endif // __cplusplus
int32_t hello_world(void);
struct Manager *manager_create(void);
void manager_destroy(struct Manager *ptr);
const char *manager_get_function(const struct Manager *self);
void manager_set_path(struct Manager *self, const char *p);
#ifdef __cplusplus} // extern "C"#endif // __cplusplus

通过manager_create创建的内存,需要通过manager_destroy销毁。


但是在对应的Rust代码没有用到申请或者销毁内存相关的代码,而是使用Box来管理内存,它可以理解为C++中的unique_ptr。


内存都通过对象来管理,避免Rust申请的内存,让C这边来释放,违反代码的开发准则。


当然,如果你非要在Rust层想malloc和free内存,可以使用libc的crate。


如果想在Rust中调用C或者C++代码,可以使用cxx crate,也很方便,比如Rust中的String、Vec都在cxx中有对应的类型。


但是我的目的是使用Rust开发一个C的动态库的SDK,两种方法都尝试了下,感觉还是直接使用FFI更方便些。


我这里特意整理了一些Rust FFI相关资料,感兴趣的可以看看

  • Rust如何调用C接口、Rust如何导出C接口、C的callback如何传给Rust:https://doc.rust-lang.org/nomicon/ffi.html

  • The Embedded Rust Book FFI:https://docs.rust-embedded.org/book/interoperability/rust-with-c.html

  • 使用cbindgen可以自动分析,将Rust接口导出为C接口:https://github.com/eqrion/cbindgen

  • cbindgen的default template:https://github.com/eqrion/cbindgen/blob/master/template.toml

  • cbindgen的doc:https://github.com/eqrion/cbindgen/blob/master/docs.md

  • Rust FFI的 example blog,主要是string如何传出去并销毁相关内存:https://snacky.blog/en/string-ffi-rust.html

  • cxx专用于Rust和C++之间的桥梁:https://github.com/dtolnay/cxx

  • cxx:https://cxx.rs/

  • Complex data types and Rust FFI blog:http://kmdouglass.github.io/posts/complex-data-types-and-the-rust-ffi/

  • Rust std ffi:https://doc.rust-lang.org/std/ffi/index.html

  • 与C交互时,可以使用libc在Rust层做C的malloc和free

  • 涉及ptr的地方需要了解:https://doc.rust-lang.org/std/ptr/index.html


还有些Rust入门资料

  • https://www.zhihu.com/question/31038569 

  • https://doc.rust-lang.org/rust-by-example/ 

  • https://doc.rust-lang.org/cargo/getting-started/installation.html 

  • https://github.com/rustlang-cn/Rustt 

  • https://github.com/sunface/rust-course 


更多内容在 一个优质的C++学习圈 里,来一起钻研C++和Rust吧。

相关阅读

  • 百度工程师带你探秘C++内存管理(ptmalloc篇)

  • 作者 | daydreamer前篇《探秘C++内存管理(理论篇)》主要介绍了Linux C++程序内存管理的理论基础,本文作为系列文章《探秘C++内存管理》的第二篇,将会探讨经典内存管理器ptmalloc
  • Google为Chromium引入Rust?

  • 今天的文章外部link比较多我特意整理了link的汇总需要的朋友可以在后台回复:“rust ”即可收到自动回复,更加方便观看-----------------------------------------------------
  • constexpr

  • 前面介绍了模板这种编译期动作,关于编译期动作,有必要介绍下constexpr。在这之前有必要简单提一下constexpr与const的关系,两者字面上都表达常量的意思。主要的区别是:const修饰
  • 20230217【外交部例行记者会】文字版

  • 此条是每日外交部例行记者会的全文,三弄解读完每日新闻联播已经没有余力解读外交部例行记者会的内容了,弄友们可以自行查看学习。欢迎关注
  • 谁还记得元宇宙?

  • 作为科技圈的“新贵”,ChatGPT的出圈几乎“复制”了元宇宙的路径,它会步元宇宙的后尘吗?文 | 于惠如编辑 | 罗丽娟两天前,手握5000万美元的美团联合创始人王慧文在社交App即刻上
  • 稳定的前70%,真的很容易吗?

  • 以下文章来源于猫头鹰研究小分队,作者猫头鹰 Niko前70%,看似是一个并不起眼的排名,但是如果是每季度都排在前70%呢?我们整理了近三年(2020Q1至2022Q4)连续十二个季度都稳居同类前7
  • 2023 ABCA-7(The Second Announcement)

  • 2023 ABCA-7The Seventh International Forum on Cathode & Anode Materialsfor Advanced Batteries and The First Independent Sodium Battery Technology and Market Dev

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • Rust学习资料

  • 最近在研究Rust,目前大多数项目都可以使用Rust开发,但是涉及到和其他语言交互,比如用Rust开发一个SDK,一般还是需要导出C接口。那如何将Rust导出C接口?Rust的FFI就是专门做这件事
  • 《计算机网络:自顶向下方法》全新第8版

  • 20多年持续打磨,国际经典教材计算机网络:自顶向下方法 文末送书!Kurose和他的自顶向下方法就在最近,Kurose和Ross教授合著的《计算机网络:自顶向下方法》中文版也刚刚升级到了第8
  • 百度工程师带你探秘C++内存管理(ptmalloc篇)

  • 作者 | daydreamer前篇《探秘C++内存管理(理论篇)》主要介绍了Linux C++程序内存管理的理论基础,本文作为系列文章《探秘C++内存管理》的第二篇,将会探讨经典内存管理器ptmalloc
  • Google为Chromium引入Rust?

  • 今天的文章外部link比较多我特意整理了link的汇总需要的朋友可以在后台回复:“rust ”即可收到自动回复,更加方便观看-----------------------------------------------------
  • constexpr

  • 前面介绍了模板这种编译期动作,关于编译期动作,有必要介绍下constexpr。在这之前有必要简单提一下constexpr与const的关系,两者字面上都表达常量的意思。主要的区别是:const修饰
  • 操作系统:文件系统的实现

  • 一、文件系统结构磁盘的逻辑单元为块,内存和磁盘之间的I/O传输以块为单位执行。磁盘的特点1可以原地重写,可以从磁盘上读一块儿,修改该块,并将它写回到原来的位置可以直接访问磁