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!();
}
我想在带有 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!();
}