极客油画

Rust 虽然没有类似 C/C++ 的头文件(.h),但通过其 FFI(Foreign Function Interface)机制和编译工具链,可以高效地引用动态链接库(.so.dll.dylib)。以下是 Rust 引用动态链接库的核心机制和步骤:


1. 声明外部函数:extern "C"

Rust 通过 extern "C" 块声明动态链接库中的函数,明确函数签名(参数类型、返回类型)和调用约定(C ABI)。

  • 示例:调用动态库 libexample.so 中的函数 add
    1
    2
    3
    
    extern "C" {
        fn add(a: i32, b: i32) -> i32;
    }
    
    • extern "C" 表示使用 C 语言的调用约定,确保 ABI 兼容性。
    • 函数需在 unsafe 块中调用,因为 Rust 无法验证外部代码的安全性。

Rust 通过以下两种方式指定动态库的链接信息:

  • #[link] 属性:直接在代码中声明库名称:
    1
    2
    3
    4
    
    #[link(name = "example")]  // 链接 libexample.so 或 example.dll
    extern "C" {
        fn add(a: i32, b: i32) -> i32;
    }
    
  • 构建脚本 build.rs:动态配置库路径和链接方式:
    1
    2
    3
    4
    5
    
    // build.rs
    fn main() {
        println!("cargo:rustc-link-search=native=/path/to/libs"); // 库搜索路径
        println!("cargo:rustc-link-lib=dylib=example");          // 链接动态库
    }
    
    这种方式更灵活,支持跨平台路径配置。

3. 类型兼容性与内存布局

  • 基础类型映射:Rust 的 i32f64 等与 C 的 intdouble 直接对应。
  • 复杂类型:使用 #[repr(C)] 保证结构体内存布局与 C 兼容:
    1
    2
    3
    4
    5
    
    #[repr(C)]
    struct Point {
        x: i32,
        y: i32,
    }
    
  • 字符串处理:通过 std::ffi::CStringCStr 转换 Rust 字符串与 C 风格字符串(*const c_char)。

4. 动态加载运行时库(可选)

若需运行时动态加载库(如插件系统),可使用 libloadingrust-dlopen 等库:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
use dlopen::wrapper::{Container, WrapperApi};

#[derive(WrapperApi)]
struct Api {
    add: extern "C" fn(i32, i32) -> i32,
}

fn main() {
    let lib: Container<Api> = unsafe { Container::load("libexample.so") }.unwrap();
    let result = lib.add(2, 3); // 直接调用
}

这种方式避免了静态链接的编译依赖。


5. 工具链支持

  • bindgen:自动从 C 头文件生成 Rust 绑定代码,适用于复杂库接口:
    1
    2
    3
    4
    5
    6
    
    // build.rs
    bindgen::Builder::default()
        .header("path/to/header.h")
        .generate()
        .unwrap()
        .write_to_file("bindings.rs");
    
    生成的 bindings.rs 包含所有必要的 extern 声明和类型定义。
  • cbindgen:反向生成 C 头文件(当 Rust 库被 C 调用时)。

6. 运行时环境配置

动态库需在运行时能被系统找到:

  • Linux/macOS:设置 LD_LIBRARY_PATHDYLD_LIBRARY_PATH
    1
    
    export LD_LIBRARY_PATH=/path/to/libs:$LD_LIBRARY_PATH
    
  • Windows:将 .dll 文件放在可执行文件同级目录或 PATH 环境变量中。

总结

Rust 通过以下机制替代头文件的作用:

  1. 函数声明extern "C" 块明确接口。
  2. 类型安全#[repr(C)]std::ffi 模块处理兼容性。
  3. 工具链支持bindgencbindgen 自动化绑定生成。
  4. 动态链接配置:构建脚本和运行时路径管理。

这种设计既保留了灵活性(如动态加载),又通过编译时检查(如类型和链接验证)确保了安全性。


本文发表于 0001-01-01,最后修改于 0001-01-01。

本站永久域名「 jiavvc.top 」,也可搜索「 极客油画 」找到我。


上一篇 « 下一篇 »

赞赏支持

请我吃鸡腿 =^_^=

i ysf

云闪付

i wechat

微信

推荐阅读

Big Image