信息发布→ 登录 注册 退出

c++项目如何安全地调用Rust代码? (cxx库入门指南)

发布时间:2026-01-09

点击量:
不能直接用 extern "C" 调用 Rust,因其仅解决函数名和调用约定,不处理跨语言类型传递、panic 穿透、所有权边界等问题;cxx 通过自动生成双向绑定胶水代码并强制显式类型标注来解决这些缺陷。

为什么不能直接用 extern "C" 调用 Rust?

很多人试过在 C++ 里写 extern "C" void rust_func();,再链接 libmyrust.a,结果遇到符号未定义、ABI 不兼容、panic 崩溃或内存泄漏。根本原因是:Rust 的 #[no_mangle] + extern "C" 只解决函数名导出和调用约定,不处理:字符串/Vec/Result/Option 等类型跨语言传递Rust panic 穿透到 C++所有权边界模糊导致 double-free。cxx 就是为堵住这些洞而生的。

用 cxx::bridge 生成双向绑定胶水代码

核心不是手写头文件,而是声明一个 extern "C++" 模块,让 cxx 自动生成 C++ 头文件和 Rust FFI stub。关键点:

  • 所有跨语言类型必须显式标注:C++ 侧用 cxx::UniquePtrcxx::Strcxx::Vector;Rust 侧对应 UniquePtr&CxxStringVec
  • 函数不能返回裸指针或引用,必须包装成 cxx::UniquePtr 或传入可变引用参数
  • panic 必须用 std::panic::catch_unwind 拦截,否则直接 abort
// src/lib.rs
#[cxx::bridge]
mod ffi {
    unsafe extern "C++" {
        include!("include/my_api.h");
        type MyData;
        fn process_data(data: &MyData) -> i32;
    }
#[namespace = "rustlib"]
extern "Rust" {
    fn rust_process(data: &[u8]) -youjiankuohaophpcn ResultzuojiankuohaophpcnVeczuojiankuohaophpcnu8youjiankuohaophpcn, Stringyoujiankuohaophpcn;
}

}

fn rust_process(data: &[u8]) -> Result, String> { std::panic::catch_unwind(|| { // 实际逻辑 Ok(data.to_vec()) }).unwrap_or_else(|| Err("panic in rust_process".to_owned())) }

CMake 中正确集成 cxx 构建流程

不能把 Rust crate 当普通静态库链接。cxx 要求 Rust 编译产物是 cdylib(带完整符号表的动态库),且 C++ 编译器必须能读取 cxx 生成的头文件。常见错误:

  • 忘记在 Cargo.toml 里设 crate-type = ["cdylib"]
  • CMake 没通过 find_package(cxx) 加载 cxx 提供的 CXXTargets.cmake
  • add_subdirectory 引入 cxx 后,没用 cxx_add_crate 而是手动 add_library
# CMakeLists.txt
find_package(cxx REQUIRED)
cxx_add_crate(
  NAME myrustlib
  TYPE cdylib
  CARGO_TARGET_DIR ${CMAKE_BINARY_DIR}/rust
)
target_include_directories(myrustlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE myrustlib)

内存与异常:谁负责释放?panic 怎么转成 C++ 异常?

cxx 默认不抛 C++ 异常,panic 会终止进程。若要转成 std::runtime_error,得在 Rust 层手动封装:

  • 所有对外函数入口加 catch_unwind,失败时返回 Result
  • C++ 侧检查返回值,手动 throw:if (res.err()) throw std::runtime_error(res.err().to_string());
  • cxx::UniquePtr 的析构由 C++ 控制,Rust 不参与;但 cxx::Stringcxx::Vector 在 C++ 侧析构时会自动调用 Rust 的 drop 实现

最易忽略的是:Rust 返回的 cxx::String 如果被 C++ 多次 move,第二次 move 会触发空指针解引用 —— 因为底层 Box 已被移交。务必保证单次所有权转移。

标签:# double  # 因其  # 试过  # 能把  # 已被  # 很多人  # 的是  # 转成  # 自动生成  # 绑定  # 头文件  # 空指针  # 引用参数  # 指针  # void  # go  # int  # 字符串  # extern  # throw  # 封装  # if  # String  # rust  # red  # 为什么  # win  # c++  # ai  # app  
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!