• rust
  • notes
发布于

Rust 笔记


与 c++ 互操作

1. C++ 转 Rust (在 Rust 中调用 C++)

这是最常见的场景,通常用于复用现有的 C++ 库。

  • 传统方式 (bindgen + build.rs)bindgen 会解析 C/C++ 头文件,自动生成 Rust 的 FFI 绑定代码。

    • 步骤

      1. 编写 C++ 头文件 (example.h) 和源文件。
      2. 在 Rust 项目的 build.rs 中使用 bindgen 生成 bindings.rs
      3. main.rs 中引入生成的绑定。
    • 代码示例

      // build.rs
      fn main() {
          // 告诉 cargo 链接 C++ 库
          println!("cargo:rustc-link-lib=static=my_cpp_lib");
          // 生成绑定
          let bindings = bindgen::Builder::default()
              .header("wrapper.h")
              .parse_callbacks(Box::new(bindgen::CargoCallbacks))
              .generate()
              .expect("Unable to generate bindings");
          bindings.write_to_file("src/bindings.rs").expect("Couldn't write bindings");
      }
  • 现代方式 (autocxx): 如果你觉得 bindgen 生成的代码太底层且不安全(全是 unsafe 块),Google 开发的 autocxx 是一个更好的选择。它在 bindgen 之上提供了一层安全封装,能自动处理 C++ 的构造函数、析构函数和方法调用。

2. Rust 转 C++ (在 C++ 中调用 Rust)

这通常用于将 Rust 编写的高性能或安全模块集成到现有的 C++ 项目中。

  • 基础方式 (C-ABI): 这是最稳健的方法。Rust 导出 extern "C" 接口,C++ 直接调用。

    • Rust 端:使用 #[no_mangle]extern "C" 防止名称修饰,并使用 #[repr(C)] 确保结构体内存布局一致。
    • C++ 端:声明对应的 extern "C" 函数原型。
    // Rust 代码
    #[no_mangle]
    pub extern "C" fn add_numbers(a: i32, b: i32) -> i32 {
        a + b
    }
    
    #[repr(C)]
    pub struct Point {
        x: f64,
        y: f64,
    }
    
  • 现代方式 (cxx-rs)

      
    // Rust 端 (src/lib.rs)
    // 需要添加依赖: cxx = "1.0"
    
    #[cxx::bridge]
    mod ffi {
        // 声明我们要调用的 C++ 函数
        extern "C++" {
            // 包含 C++ 头文件
            include!("example.h");
    
            // 声明 C++ 函数原型
            fn do_cpp_thing(x: i32) -> i32;
        }
    
        // 声明我们要暴露给 C++ 的 Rust 函数
        extern "Rust" {
            fn do_rust_thing(input: &str) -> i32;
        }
    }
    
    // 实现 Rust 函数
    fn do_rust_thing(input: &str) -> i32 {
        println!("Rust received: {}", input);
        42
    }