Skip to content

Commit 9aaf761

Browse files
committed
Implement universal dlopen-style API
This adds `external_library_universal!`, a new entrypoint to the crate. It's very similar to `external_library!` but the generated bindings are universal for both dlopen and non-dlopen builds. This fixes #12. Of course, this does not address the concern about structure size - but this is why this feature is optional.
1 parent bc1466a commit 9aaf761

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

src/lib.rs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,26 @@
127127
//! #[cfg(not(feature = "dlopen-foo"))]
128128
//! use ffi::*;
129129
//! ```
130+
//!
131+
//! Alternatively to using `ffi_dispatch!` and `ffi_dispatch_static!` or directly calling
132+
//! module-level functions in non-dlopen code, you can use the dlopen-style API (ie. `Foo::open`)
133+
//! on non-dlopen builds. This allows using the same API regardless of whether the `dlopen-foo`
134+
//! feature flag is set. To enable this, use `external_library_universal!` instead of
135+
//! `external_library!`.
136+
//!
137+
//! ```rust
138+
//! external_library_universal!(feature="dlopen-foo", Foo, "foo",
139+
//! functions:
140+
//! fn foo() -> c_int,
141+
//! );
142+
//!
143+
//! // This works both with and without dlopen-foo. The argument to `File::open` is ignored in
144+
//! // non-dlopen builds, and the function can fail only on dlopen builds.
145+
//! lazy_static::lazy_static! {
146+
//! pub static ref FOO_STATIC: Foo =
147+
//! Foo::open("libfoo.so").ok().expect("couldn ot find libfoo");
148+
//! }
149+
//! ```
130150
#![warn(missing_docs)]
131151

132152
extern crate libloading;
@@ -228,6 +248,71 @@ macro_rules! link_external_library(
228248
);
229249
);
230250

251+
#[doc(hidden)]
252+
#[macro_export]
253+
macro_rules! link_external_library_dlopen_compat(
254+
(__struct, $structname: ident,
255+
$(statics: $($sname: ident: $stype: ty),+,)|*
256+
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
257+
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
258+
) => (
259+
pub struct $structname {
260+
$($(
261+
pub $sname: &'static $stype,
262+
)+)*
263+
$($(
264+
pub $fname: unsafe extern "C" fn($($farg),*) -> $fret,
265+
)+)*
266+
$($(
267+
pub $vname: unsafe extern "C" fn($($vargs),+ , ...) -> $vret,
268+
)+)*
269+
}
270+
);
271+
(__impl, $structname: ident,
272+
$(statics: $($sname: ident: $stype: ty),+,)|*
273+
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
274+
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
275+
) => (
276+
impl $structname {
277+
pub unsafe fn open(_name: &str) -> Result<$structname, $crate::DlError> {
278+
// we use it to ensure the 'static lifetime
279+
use std::mem::transmute;
280+
Ok($structname {
281+
$($($sname: {
282+
$sname
283+
},
284+
)+)*
285+
$($($fname: {
286+
$fname
287+
},
288+
)+)*
289+
$($($vname: {
290+
transmute($vname)
291+
},
292+
)+)*
293+
})
294+
}
295+
}
296+
);
297+
($structname: ident,
298+
$(statics: $($sname: ident: $stype: ty),+,)|*
299+
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
300+
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
301+
) => (
302+
$crate::link_external_library_dlopen_compat!(__struct,
303+
$structname, $(statics: $($sname: $stype),+,)|*
304+
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
305+
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
306+
);
307+
$crate::link_external_library_dlopen_compat!(__impl,
308+
$structname, $(statics: $($sname: $stype),+,)|*
309+
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
310+
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
311+
);
312+
unsafe impl Sync for $structname { }
313+
);
314+
);
315+
231316
/// An error generated when failing to load a library
232317
#[derive(Debug)]
233318
pub enum DlError {
@@ -371,6 +456,59 @@ macro_rules! external_library(
371456
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
372457
);
373458
);
459+
($structname: ident, $link: expr,
460+
$(statics: $($sname: ident: $stype: ty),+,)|*
461+
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
462+
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
463+
) => (
464+
$crate::external_library!( feature="dlopen", $structname, $link,
465+
$(statics: $($sname: $stype),+,)|*
466+
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
467+
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
468+
);
469+
);
470+
);
471+
472+
/// Main macro of this library, used to generate the the FFI bindings that are universal in both
473+
/// dlopen and non-dlopen form.
474+
///
475+
/// The expected arguments are, in order:
476+
/// - (Optional) The name of the cargo feature conditioning the usage of dlopen, in the form
477+
/// `feature="feature-name"`. If ommited, the feature `"dlopen"` will be used.
478+
/// - The name of the struct that will be generated when the dlopen-controlling feature is
479+
/// enabled
480+
/// - The link name of the target library
481+
/// - The desctription of the statics, functions, and vararg functions that should be linked
482+
///
483+
/// See crate-level documentation for a detailed example of use.
484+
#[macro_export]
485+
macro_rules! external_library_universal(
486+
(feature=$feature: expr, $structname: ident, $link: expr,
487+
$(statics: $($sname: ident: $stype: ty),+,)|*
488+
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
489+
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
490+
) => (
491+
#[cfg(feature = $feature)]
492+
$crate::dlopen_external_library!(
493+
$structname, $(statics: $($sname: $stype),+,)|*
494+
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
495+
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
496+
);
497+
498+
#[cfg(not(feature = $feature))]
499+
$crate::link_external_library!(
500+
$link, $(statics: $($sname: $stype),+,)|*
501+
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
502+
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
503+
);
504+
505+
#[cfg(not(feature = $feature))]
506+
$crate::link_external_library_dlopen_compat!(
507+
$structname, $(statics: $($sname: $stype),+,)|*
508+
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
509+
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
510+
);
511+
);
374512
($structname: ident, $link: expr,
375513
$(statics: $($sname: ident: $stype: ty),+,)|*
376514
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*

0 commit comments

Comments
 (0)