11 个版本
使用旧的 Rust 2015
0.5.2 | 2023 年 6 月 5 日 |
---|---|
0.5.0 | 2021 年 2 月 25 日 |
0.4.2 | 2020 年 5 月 28 日 |
0.4.1 | 2018 年 3 月 13 日 |
0.2.0 | 2015 年 11 月 9 日 |
#109 in Rust 模式
495,732 每月下载量
在 1,781 个crate中使用 (8 个直接使用)
21KB
190 行
dlib
dlib 是一个小型crate,提供宏来简化外部系统库的使用,这些库可以在运行时根据是否启用了某个特性而选择性地加载。
用法
dlib 定义了 external_library!
宏,可以通过以下方式调用
external_library!(feature="dlopen-foo", Foo, "foo",
statics:
me: c_int,
you: c_float,
functions:
fn foo() -> c_int,
fn bar(c_int, c_float) -> (),
fn baz(*const c_int) -> c_int,
varargs:
fn blah(c_int, c_int ...) -> *const c_void,
fn bleh(c_int ...) -> (),
);
如你所见,需要将静态值与函数以及带有可变参数的函数分开。这三类都是可选的,但使用的必须按照这个顺序出现。函数的返回类型必须都是显式的(因此对于空函数是 -> ()
)。
如果 feature
参数(在这个例子中,dlopen-foo
)指定的特性在你的crate中不存在,这个宏将展开为一个extern块,定义每个项,使用宏的第三个参数作为链接名称
#[link(name = "foo")]
extern "C" {
pub static me: c_int;
pub static you: c_float;
pub fn foo() -> c_int;
pub fn bar(_: c_int, _: c_float) -> ();
pub fn baz(_: *const c_int) -> c_int;
pub fn blah(_: c_int, _: c_int, ...) -> *const c_void;
pub fn bleh(_: c_int, ...) -> ();
}
如果 feature
参数指定的特性在你的crate中存在,它将展开为宏的第二个参数命名的 struct
,其中每个字段对应于定义的每个符号;以及一个名为 open
的方法,该方法尝试根据给定的名称或路径加载库。
pub struct Foo {
pub me: &'static c_int,
pub you: &'static c_float,
pub foo: unsafe extern "C" fn() -> c_int,
pub bar: unsafe extern "C" fn(c_int, c_float) -> (),
pub baz: unsafe extern "C" fn(*const c_int) -> c_int,
pub blah: unsafe extern "C" fn(c_int, c_int, ...) -> *const c_void,
pub bleh: unsafe extern "C" fn(c_int, ...) -> (),
}
impl Foo {
pub unsafe fn open(name: &str) -> Result<Foo, DlError> { /* ... */ }
}
此方法在加载成功时返回 Ok(..)
。它包含一个具有所有字段指向相应符号的指定结构的实例。
如果 name
指定的库无法打开,它返回 Err(DlError::CantOpen(e))
,其中 e
是 libloading
报告的错误(见 [LibLoadingError]);
它还会在第一个缺失的符号上失败,错误信息为:Err(DlError::MissingSymbol(symb))
,其中 symb
是一个包含缺失符号名称的 &str
。
请注意,这种方法是不安全的,因为加载(和卸载)外部C库可能会运行任意代码。因此,您需要确保您想加载的特定库在您想要加载的上下文中是安全的。
在您的crate中保持泛型
如果您想让您的crate在dlopen与链接之间保持泛型,只需在您的 Cargo.toml
中添加一个特性。
[dependencies]
dlib = "0.5"
[features]
dlopen-foo = []
然后,将那个特性的名称作为 feature
参数传递给dlib的宏。
external_library!(feature="dlopen-foo", Foo, "foo",
functions:
fn foo() -> c_int,
);
dlib
提供了辅助宏来分发对外部符号的访问。
ffi_dispatch!(feature="dlopen-foo", Foo, function, arg1, arg2);
ffi_dispatch_static!(feature="dlopen-foo", Foo, my_static_var);
这些宏会根据您的crate中是否存在 dlopen-foo
特性来展开为相应的值或函数调用。
您仍然需要确保函数/静态变量或包装结构体 Foo
在作用域内。例如,您可以使用 lazy_static
crate 进行初始化,并将包装结构体存储在静态变量中,您可以在需要的地方导入该变量
#[cfg(feature = "dlopen-foo")]
lazy_static::lazy_static! {
pub static ref FOO_STATIC: Foo =
Foo::open("libfoo.so").ok().expect("could not find libfoo");
}
然后,它可以使用如下方式在所有使用FFI的模块顶部使用
#[cfg(feature = "dlopen-foo")]
use ffi::FOO_STATIC;
#[cfg(not(feature = "dlopen-foo"))]
use ffi::*;
许可证:MIT
依赖项
~0–5MB