FEATURED · 精选文章

ScyllaDB Rust × C++ 互操作实战:基于 cxx::bridge 编写 Rust 包并接入构建系统

发布时间 / 2026/9/14 6:19:57
来源 / 创域科博编辑部
栏目 / 资讯中心
ScyllaDB Rust × C++ 互操作实战:基于 cxx::bridge 编写 Rust 包并接入构建系统 ScyllaDB Rust × C 互操作实战基于 cxx::bridge 编写 Rust 包并接入构建系统【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb本文基于 ScyllaDB 官方开发文档《Rust and C》docs/dev/rust.md完整讲解如何在以 Seastar 框架编写的 C 代码库中引入 Rust 模块包括用cxx::bridge宏导出 Rust 函数的写法、新包的 7 步接入流程、Cargo.lock 提交规范以及构建系统configure.py / CMake / cxxbridge / cargo如何把 Rust 静态库与 C 侧生成的头文件、源文件拼装起来。读完后你能独立创建一个可被 C 调用的 Rust 包并理解两侧 ABI 的衔接原理。1. 为什么 Scylla 要混用 RustScylla 的核心是 C但 Rust 提供了一些 C 中缺失的有用特性文档原文即以此开篇。Scylla 的实际做法是把 Rust 与 C 通过 FFI 桥接起来Rust 代码编译为采用 C ABI 的静态库C 代码则通过工具生成的头文件以“原生命名”调用 Rust 方法。仓库中已有两个真实案例测试用的inc包和 wasm 引擎绑定包wasmtime_bindings它们分别对应rust/inc/与rust/wasmtime_bindings/后者被lang/wasm相关功能使用见 rust/src/lib.rs 中的extern crate声明与 configure.py 第 1400 行附近的依赖登记。2. 互操作实现原理CXX crate 与 cxxbridge 代码生成文档“Rust interoperability implementation”一节给出了完整机制结合源码可以还原成如下链条Rust 侧声明Rust 代码使用#[cxx::bridge(namespace ...)]宏配合mod ffi与extern Rust块标记需要导出到 C 的项。例如 rust/inc/src/lib.rs 中#[cxx::bridge(namespace rust)] mod ffi { extern Rust { fn inc(x: i32) - i32; } } fn inc(x: i32) - i32 { x 1 }编译产物Rust 文件编译时生成一个采用 C ABI 的静态库Rust 方法以特殊符号名导出。C 侧生成cxxbridge命令行工具从同一份 Rust 源码生成 C 头文件*.hh与源文件*.cc。头文件以“原始命名”暴露所有导出项可以像普通 C 头文件一样#include*.cc中的 C 方法实现内部再转调那些特殊符号名对应的 Rust 实现。链接方式所有 Rust 模块统一编译为单一静态库。文档明确指出这是 Rust 链接到 C 目前唯一官方支持的方式未来可能借助rlibRust library文件支持更多链接方法。这一机制在构建系统中的落点见 rust/CMakeLists.txtgenerate_cxxbridge()函数第 42-59 行对给定的.rs输入运行cxxbridge --header --output ${header}与cxxbridge --output ${source}两条命令分别产出头文件与源文件add_rust_library()函数第 11-37 行则调用cargo build --locked --profilerust-${mode}编译出lib${name}.a再包装成 CMake 的Rust::${name}imported target。最终wasmtime_bindings与inc两个 CMake 静态库都由生成代码 链接Rust::rust_combined组成第 79-114 行。3. 实操指南创建一个被 C 调用的 Rust 包7 步流程文档给出了以新建包new_pkg、导出fn inc(x: i32) - i32到命名空间xyz为例的完整流程。以下步骤全部保留并逐一对照仓库中的实际文件补充说明创建包在rust目录下执行cargo new new_pkg --lib登记依赖在 rust/Cargo.toml 的[dependencies]列表中追加new_pkg { path new_pkg, version 0.1.0 }参考现有条目inc { path inc, version 0.1.0 }与wasmtime_bindings { path wasmtime_bindings, version 0.1.0 }。注意该文件顶部还声明了crate-type [staticlib]这正是第 2 节所说的“编译为单一静态库”的配置来源。加入工作区入口在 rust/src/lib.rs 中追加extern crate new_pkg;。该文件当前内容为extern crate inc;与extern crate wasmtime_bindings;是三个包汇入同一个rust_combined静态库的汇集点。编写包代码在new_pkg/Cargo.toml中配置依赖尤其是cxxcrate在new_pkg/src/lib.rs及其他new_pkg/src/*.rs中编写 Rust 代码。声明 FFI 导出在new_pkg/src/lib.rs中添加#[cxx::bridge(namespace xyz)] mod ffi { extern Rust { fn inc(x: i32) - i32; } }namespace参数决定 C 侧的调用命名空间即 C 里写成xyz::inc(...)。注意extern Rust块只是声明真正的函数体仍需定义见 rust/inc/src/lib.rs 中fn inc的实现。登记构建依赖在 configure.py 中把new_pkg/src/lib.rs添加到需要使用该 Rust 导出的 C 目标的依赖列表。configure.py 生成的 ninja 规则会把rust/下的每个.rs文件映射到对应的gen/rust/*.o编译产物见 configure.py 第 2736-2737 行obj dep[:idx].replace(rust/,) .o。在 C 中使用#include rust/new_pkg.hh然后调用xyz::foo()。以测试包为例test/boost/rust_test.cc 正是这样写的#include rust/inc.hh BOOST_AUTO_TEST_CASE(test_inc) { int k 1; BOOST_REQUIRE(rust::inc(k) 2); }其构建依赖在 configure.py 第 1837 行登记deps[test/boost/rust_test] [rust/inc/src/lib.rs]——即第 6 步在真实项目中的形态。3.1 cxx::bridge 可以放在 lib.rs 之外文档还说明cxx::bridge段不必非要放在lib.rs也可以放在例如abc.rs中。此时必须注意两点在lib.rs中添加mod abc;确保该 bridge 与整个包一起参与编译被导出函数的定义必须在abc.rs的可见范围内——可以直接写在同一文件也可以通过mod/use引入。最后configure.py的依赖登记要用这个文件abc.rs所在包路径替代lib.rs。4. 构建系统如何串联 Rustconfigure.py、CMake 与 cargo从源码结构看Scylla 同时存在两套构建路径configure.py 生成的 Ninja 构建与 CMake 构建二者的 Rust 处理逻辑一致。Ninja 路径configure.pycxxbridge 规则cxxbridge --include rust/cxx.h对输入.rs生成头文件或源文件configure.py 第 2562-2565 行--include rust/cxx.h参数把 cxx crate 的通用头cxx.h并入生成头。静态库规则cargo build --locked --manifest-pathrust/Cargo.toml --target-dir... --profilerust-{mode}configure.py 第 2682 行产物为librust_combined.a其规则声明了对rust/Cargo.lock的依赖第 2898 行保证依赖锁定生效。所有需要 FFI 头文件的 C 目标会把$builddir/{mode}/gen/rust/cxx.h加入生成头依赖第 2863 行。CMake 路径rust/CMakeLists.txtadd_rust_library(rust_combined)先按 CMake 的 build type 选出rust-dev/rust-debug/rust-release等 profile再执行cargo build --locked --target-dir... --profilerust-${build_mode}把librust_combined.a拷贝到构建目录并注册为Rust::rust_combined。generate_cxxbridge(wasmtime_bindings ...)与generate_cxxbridge(inc ...)分别对 rust/wasmtime_bindings/src/lib.rs 和 rust/inc/src/lib.rs 执行代码生成并各自建一个 CMake 静态库链接到Rust::rust_combined。构建时还支持通过Scylla_RUSTC_WRAPPER注入RUSTC_WRAPPER环境变量以启用 sccacheCMakeLists.txt 第 4-9 行启用预编译头时绑定库还会复用scylla-precompiled-header且注释解释了 PCH 的 sanitizer 编译标志必须与目标一致的原因第 89-96 行。Cargo profile 与构建模式对齐rust/Cargo.toml 定义了五个 Scylla 专属 profile——rust-devopt-level2、去符号、关 overflow-checks、rust-debugopt-level1、禁增量、rust-sanitizeopt-levels、rust-release保留 debug 信息、rust-coverage。注释明确说明cargo profilerust-xyz要与 ninja 的xyzmode 配套使用从而保证 Rust 部分的优化/调试级别与 C 侧同一构建模式匹配。5. 版本锁定cxx crate 与 cxxbridge CLI 必须严格同步这是一个容易被忽视但决定能否链接成功的关键约束仓库中有两处强注释相互印证rust/inc/Cargo.tomlcxx { version 1.0.83, features [c20] }用精确钉死版本注释说明 cxx crate 生成 FFI 的 Rust 侧cxxbridge CLI 生成 C 侧两者版本不一致会导致生成的 cxxbridge 符号在链接期无法解析升级 cxx 必须同步升级 install-dependencies.sh 中的 cxxbridge-cmd 并重建工具链镜像。install-dependencies.sh 第 482 行cargo install cxxbridge-cmd --version 1.83 --root /usr/local之前的注释第 477-481 行重申了同样的 lockstep 要求当前版本为 1.0.83。因此在给新包添加cxx依赖时务必沿用1.0.83这类精确版本写法而不是1.x之类的宽松区间。6. 提交变更Cargo.lock 的提交规范文档“Submitting changes”一节规定Scylla 跟踪rust/Cargo.lock文件它记录最近一次成功构建所使用的精确依赖版本。以下三类依赖变更发生后必须提交更新后的 Cargo.lock添加新的本地包作为 Scylla 的依赖使用更新已有包中某个依赖的版本给某个包添加新依赖。Cargo.lock 可通过cargo update命令再生。这一规范之所以严格是因为构建时cargo build全程带--locked标志见第 4 节两条规则锁文件与Cargo.toml不一致会直接导致构建失败。7. 要点回顾互操作核心是cxxcrate#[cxx::bridge(namespace ...)]mod ffiextern Rust标记导出项Rust 侧编译为 C ABI 静态库C 侧由cxxbridgeCLI 从同一份.rs生成*.hh/*.cc头文件可像普通 C 头一样包含。新包接入共 7 步cargo new→ 登记rust/Cargo.toml→rust/src/lib.rs加extern crate→ 编写包代码 →cxx::bridge声明 →configure.py登记依赖 → C 中#include生成头文件并调用。cxx::bridge可放在lib.rs之外的文件中但必须在lib.rs中声明mod且函数定义对该文件可见。当前唯一官方支持的链接方式是统一静态库crate-type [staticlib]→librust_combined.a未来可能支持rlib。升级cxx必须与cxxbridge-cmdinstall-dependencies.sh当前 1.0.83版本锁定同步否则链接期符号解析失败。任何 Cargo 依赖变更都要提交由cargo update生成的新Cargo.lock构建以--locked模式强制执行。参考路径docs/dev/rust.md、rust/Cargo.toml、rust/src/lib.rs、rust/inc/src/lib.rs、rust/CMakeLists.txt、test/boost/rust_test.cc、configure.py、install-dependencies.sh。【免费下载链接】scylladbNoSQL data store using the Seastar framework, compatible with Apache Cassandra and Amazon DynamoDB项目地址: https://gitcode.com/GitHub_Trending/sc/scylladb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻