Rust ffi 以跨平台方式包含动态库

Rust ffi include dynamic library in cross platform fashion

我想在带有 FFI 的 Rust 中包含一个动态 C 库。

该库实际上也是用 Rust 构建的,但公开了一个 C 接口,因此它也可以从其他语言中使用。当我用 cargo 构建库(类型:cdylib)时,我在 MacOS 上得到一个 .dylib 和一个 .dll 以及一个 .dll.lib windows 上的文件。这些库也有不同的名称,源自项目名称(libmy_lib.dylib on MacOS and my_lib.dll as well as my_lib.dll.lib on Windows) .

我想以跨平台的方式引用这些文件。因为目前我必须使用

#[link(name = "my_lib.dll", kind = "dylib")]

在windows,而在MacOS我需要使用

#[link(name = "my_lib", kind = "dylib")]

我已经尝试将 my_lib.dll.lib 重命名为 my_lib.lib,但我仍然遇到链接器错误,说

LINK : fatal error LNK1181: cannot open input file 'my_lib.lib'

如何引用这些文件,以便我可以将我的代码用于 Mac 和 Windows?如果只能使用 cfg_attr 标签,我也会接受。 理想情况下,如果可能的话,我还想摆脱 windows 的 .lib 文件。

你可以使用 crate libloading

示例:

let lib = unsafe {
    #[cfg(unix)]
    let path = "mylib.so";
    #[cfg(windows)]
    let path = "mylib.dll";
    libloading::Library::new(path).expect("Failed to load library")
};
let func: libloading::Symbol<unsafe extern fn() -> u32> = unsafe {
     lib.get(b"my_func").expect("Failed to load function `my_func`")
};
// Can call func later while `lib` in scope

无论如何,我现在找到了一个临时解决方案。

我使用了这个模式:

#[cfg(windows)]
#[link(name = "my_lib.dll", kind = "dylib")]
extern {
    // Reference the exported functions
}

#[cfg(unix)]
#[link(name = "my_lib", kind = "dylib")]
extern {
    // Reference the exported functions
}

我不是很喜欢它,因为我必须两次定义完全相同的 extern{} 块,但它有效,我也可以扩展这个模式,例如使用 #[cfg(target_os = "macos")] 如果需要...

编辑:感谢@Angelicos Phosphoros,我通过使用这样的宏改进了代码:

/// Import native functions with the Rust FFI
macro_rules! import_native_functions {
    () => {
        // Reference the exported functions
    };
}

#[cfg(windows)]
#[link(name = "my_lib.dll", kind = "dylib")]
extern {
    import_native_functions!();
}


#[cfg(unix)]
#[link(name = "my_lib", kind = "dylib")]
extern {
    import_native_functions!();
}