陈天 · Rust 编程第一课
陈天
Tubi TV 研发副总裁
23195 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 65 讲
基础篇 (21讲)
陈天 · Rust 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

31|FFI:Rust如何和你的语言架起沟通桥梁?

使用Rust的reqwest构建REST API客户端
Rust提供rocksDB的绑定
Vec和HashMap<K,V>如何传递给C
Rust受到各个高级语言的青睐
Rust的安全性
FFI是Rust的领先领域
使用protobuf
使用REST API、gRPC
Kotlin/Swift
C++
Erlang/Elixir
Python和Node.js
如何进行错误处理
谁来释放内存
处理数据结构的差异
Rust shim层
Rust调用JavaScript/Python
Rust调用Golang的代码
使用C ABI
处理FFI的注意事项
生成xxx-sys crate和xxx crate
使用bindgen生成Rust FFI代码
能力越大,责任越大
大部分语言都在和C打造的生态系统打交道
语言交互接口
外部函数接口
思考题
小结
FFI的其他方式
和其他语言的互操作
把Rust代码编译成C库
Rust调用其他语言
Rust调用C的库
FFI的重要性
FFI(Foreign Function Interface)
FFI: Rust如何和你的语言架起沟通桥梁?

该思维导图由 AI 生成,仅供参考

你好,我是陈天。
FFI(Foreign Function Interface),也就是外部函数接口,或者说语言交互接口,对于大部分开发者来说,是一个神秘的存在,平时可能几乎不会接触到它,更别说撰写 FFI 代码了。
其实你用的语言生态有很大一部分是由 FFI 构建的。比如你在 Python 下使用着 NumPy 愉快地做着数值计算,殊不知 NumPy 的底层细节都是由 C 构建的;当你用 Rust 时,能开心地使用着 OpenSSL 为你的 HTTP 服务保驾护航,其实底下也是 C 在处理着一切协议算法。
我们现在所处的软件世界,几乎所有的编程语言都在和 C 打造出来的生态系统打交道,所以,一门语言,如果能跟 C ABI(Application Binary Interface)处理好关系,那么就几乎可以和任何语言互通
当然,对于大部分其他语言的使用者来说,不知道如何和 C 互通也无所谓,因为开源世界里总有“前辈”们替我们铺好路让我们前进;但对于 Rust 语言的使用者来说,在别人铺好的路上前进之余,偶尔,我们自己也需要为自己、为别人铺一铺路。谁让 Rust 是一门系统级别的语言呢。所谓,能力越大,责任越大嘛。
也正因为此,当大部分语言都还在吸血 C 的生态时,Rust 在大大方方地极尽所能反哺生态。比如 cloudflare 和百度的 mesalink 就分别把纯 Rust 的 HTTP/3 实现 quiche 和 TLS 实现 Rustls,引入到 C/C++ 的生态里,让 C/C++ 的生态更美好、更安全。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Rust FFI(Foreign Function Interface)是如何与其他语言建立通信桥梁的?本文介绍了Rust与C/C++的互操作,以及如何使用bindgen工具生成Rust FFI代码。通过示例展示了如何调用C库,包括创建shim代码、生成Rust FFI代码、封装低层代码以提供更Rusty的接口。文章还提到了处理FFI的注意事项,包括处理数据结构差异、内存释放和错误处理。总的来说,Rust FFI能够方便地集成C库,为读者展示了Rust在处理FFI方面的便利性和贴心性。 此外,文章还介绍了Rust与Python、Node.js、Erlang/Elixir、C++、Kotlin/Swift等语言的互操作方式,以及uniffi工具的使用。通过使用uniffi,读者可以方便地生成各种语言的FFI代码,展示了Rust在多语言互操作方面的灵活性和便利性。 最后,文章提到了除了FFI外,还可以使用REST API、gRPC和protobuf等方式进行跨语言共享。并强调了Rust在提供底层支持时的安全性和高性能,以及在开发跨越多个端的公共库时的优势。 总的来说,本文全面介绍了Rust FFI与其他语言的互操作方式,展示了Rust在处理跨语言通信方面的优势和便利性。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《陈天 · Rust 编程第一课》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(8)

  • 最新
  • 精选
  • 卷王之王
    你好,我想用c语言调用rust,rust代码中用到了tokio。tokio的main函数中有 #[tokio::main] 的标记。这种情况不知道怎么提供给c语言接口了。 #[tokio::main] async fn main() -> Result<()> { // Open a connection to the mini-redis address. let mut client = client::connect("127.0.0.1:6379").await?;

    作者回复: 宏只不过是对 runtime 的包装。参见:https://docs.rs/tokio/latest/tokio/runtime/index.html

    2022-01-15
    2
  • Marvichov
    私以为对FFI的理解, 重点还是对ABI的理解; C-ABI就像英语一样…不同母语的人可以通过英语交流…数据转换就相当于翻译的过程…中文 → 英文 → 法文; 目前很多机器翻译AI也是把target lang翻译成英语…英语有点像一个MIR了 ABI里面最重要的, 估计就是calling convention了: https://flint.cs.yale.edu/cs421/papers/x86-asm/asm.html; - 阅读 std::ffi 的文档,想想 Vec 如何传递给 C?再想想 HashMap 该如何传递?有必要传递一个 HashMap 到 C 那一侧么? 如果用std::ffi的话, 需要把Vec<T>转成Vec<u8>再转成CString…能不能传, 还有个关键是T必须要有C representation和bindings, 不然到了C里面, 也不知道怎么用T… HashMap没必要, 也需要做类似的serialization, 但是, 怎么做deserialization就没那么容易了; 毕竟从一个nul-terminated 的char*里面还原HashMap是不可能的 - 阅读 rocksdb 的代码,看看 Rust 如何提供 rocksDB 的绑定。 https://github.com/rust-rocksdb/rust-rocksdb/blob/master/librocksdb-sys/build.rs; librocksdb-sys提供C bindings → unsafe crate → 挺复杂的, bind了很多库… 整个rocksdb crate提供safe rust api;

    作者回复: 对于 HashMap 这样的结构,我们只需要传一个简单的 wrapper,而不是尝试在两端去 serialize/deserialize。因为你用到的是它的功能,其实并不关心它数据存了些什么,怎么存储的。做 FFI 切忌过于纠结数据结构如何 mapping,大部分时候,我们需要的是另一侧提供的功能。所以,只要输入输出有合适的 mapping 或者 ser/de,具体另一侧怎么实现的,完全不要去关心。在我用 pyo3 封装 xunmi 时,给出了很好的示范。

    2021-11-14
    2
    1
  • Marvichov
    Q: 有个小问题, 为啥bindings.h不需要以下这些header, 咋一build就自动添加这些header呢? 难道是ffi的scaffolding的代码需要? #include <cstdarg> #include <cstdint> #include <cstdlib> #include <ostream> #include <new> Q: Swift call rust FFI 代码的时候, 发生了什么呢? 我猜想是: `dlopen` 找到rust代码编译成的dylib, 然后用dlsym 找到函数 `math::hello`; `math_6c3d_hello` 封装好了这个流程. public func hello(name: String) -> String { let _retval = try! rustCall { math_6c3d_hello(name.lower(), $0) } return try! String.lift(_retval) } ... private func makeRustCall<T>(_ callback: (UnsafeMutablePointer<RustCallStatus>) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T { var callStatus = RustCallStatus() let returnedVal = **callback(&callStatus)** // ... }

    作者回复: 1. 对,自动生成的 2. 对

    2021-11-14
    1
  • overheat
    "正常情况下应该创建另一个 crate 来撰写这样的接口",如果发布到crates.io上,“另一个crate”需要单独发布吗?也就是说在使用时会有两个dependences需要加入toml吗?(一个abc-sys,还有一个abc-interface)

    作者回复: 需要单独发布,如果你是在不想单独发布,就需要通过在 dependency 里用 git 的方式引入

    2021-11-23
    2
  • Marvichov
    > The ABI for C is platform-specific (OS, processor) - it covers issues such as register allocation and calling conventions, which are obviously specific to a particular processor. https://stackoverflow.com/questions/4489012/does-c-have-a-standard-abi 这样的话, 在之前评论里, 英语的那个类比就不恰当了...英语有很多dialect, 大家是可以用**标准**英语交流...和普通话一样的道理, 有个公认的标准... 那么问题来了, 既然C-abi并没有标准, 为什么大家喜欢选择它作为中间的bridge呢? 难道是因为它最简单通用, 没有标准也可以 (实现不用platform agonostic)?

    作者回复: C ABI 是有标准的(主要就是寄存器和栈如何使用),只不过不同 CPU 和 OS 有不同的标准。比如 arm 哪个寄存器用作返回值和 x64/powerpc/mips 就不同,这非常正常。但在同一个 CPU/OS 下,C ABI 是一致的。而且所有系统的 library 都是用 C ABI,所以使用它做中间媒介再合适不过。

    2021-11-16
  • 罗杰
    如何在 build.rs 断点调试呢?

    作者回复: 没有试过,需要找到 build binary 对应的 process,然后想办法 gdb attach 进去。这里有个讨论:https://www.reddit.com/r/rust/comments/72ip1h/attach_gdb_to_buildrs/

    2021-11-08
  • 沈畅
    thread 'main' panicked at 'Unable to find libclang: "the `libclang` shared library at /home/dev12/llvm/lib/libclang.so.9 could not be opened: /lib64/libc.so.6: version `GLIBC_2.18' not found (required by /home/dev12/llvm/lib/../lib/libc++abi.so.1)"', /home/dev12/.cargo/registry/src/mirrors.zte.com.cn-e61ca787596def60/bindgen-0.59.2/src/lib.rs:2144:31 这个问题大家遇见过吗?难道clang版本太低了?
    2022-09-17归属地:江苏
    1
    1
  • Edwin
    目前我们正在做3的事情
    2022-02-27
收起评论
显示
设置
留言
8
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部