与 C++ 的互操作性

Rust 社区提供了多种 C++/Rust 互操作选项,并且一直在不断开发新工具。目前,Chromium 使用一种名为 CXX 的工具。

您可以使用接口定义语言(与 Rust 极为相似)描述整个语言边界,然后 CXX 工具会据此生成 Rust 和 C++ 函数及类型的声明。

Overview diagram of cxx, showing that the same interface definition is used to create both C++ and Rust side code which then communicate via a lowest common denominator C API

See the CXX tutorial for a full example of using this.

请仔细研究这个图表。解释背后的原理和您之前所做的完全相同。说明自动执行这一流程具有以下好处:

  • 使用该工具可保证 C++ 端和 Rust 端相匹配(例如,如果 #[cxx::bridge] 与实际的 C++ 或 Rust 定义不匹配,则会出现编译错误。但使用不同步的手动绑定,可能会导致未定义行为)
  • 该工具还可自动生成 FFI thunk(即小型但可兼容 C-ABI 的自由函数),以便适应非 C 语言特性(例如,启用对 Rust 或 C++ 方法的 FFI 调用;而手动实现绑定一般需要自行编写这种顶级的自由函数)
  • 该工具和库可以处理一系列核心类型,例如:
    • &[T] 可以跨 FFI 边界进行传递,即使它无法保证任何特定的 ABI 或内存布局一致无误。进行手动绑定时,必须手动解构 std::span<T> / &[T],并根据指针和长度进行重新构建,但这很容易出错,因为每种语言对于空 slice 的表示方式略有不同
    • 系统对 std::unique_ptr<T>std::shared_ptr<T> 和/或 Box 等智能指针提供原生支持。如果使用手动绑定,则必须传递可兼容 C-ABI 的原始指针,这会增加生命周期和内存安全风险。
    • rust::StringCxxString 类型能够识别并处理不同语言之间在字符串表示方面的差异(例如,rust::String::lossy 可以通过非 UTF8 输入构建 Rust 字符串;rust::String::c_str 可以为字符串加上 NUL 终止符)。