Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
strategy:
fail-fast: false
matrix:
rust: ['1.40.0', 'stable', 'beta']
rust: ['1.56.0', 'stable', 'beta']

runs-on: ubuntu-latest

Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ exclude = ["/dlib-test", "README.tpl"]
readme = "README.md"
keywords = ["dylib", "dlopen"]
categories = ["api-bindings"]
edition = "2021"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this specifically needed for this change?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be necessary, no. It just seems a bit unusual at this point for a crate to be using the default edition.

I don't think there's any need to support Rust versions too old for the 2021 edition at this point.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, could you also update the CI accordingly? It's currently failing because of that change.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated CI to the first version of Rust that supports the 2021 edition.


[dependencies]
libloading = ">=0.7, <0.9"
5 changes: 4 additions & 1 deletion dlib-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ dlib = { path = "../" }
lazy_static = { version = "1.0", optional = true }

[features]
"dlopen" = ["lazy_static"]
default = ["sin"]
sin = []
nonexistant = []
dlopen = ["lazy_static"]
23 changes: 23 additions & 0 deletions dlib-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
use dlib::external_library;

external_library!(Mlib, "m",
/* TODO: local ambiguity when calling macro
statics:
#[cfg(feature = "nonexistant")]
non_existant_static: f64,
*/
functions:
fn cos(f64) -> f64,
#[cfg(feature = "sin")]
fn sin(f64) -> f64,
#[cfg(feature = "nonexistant")]
fn nonexistant_function(f64) -> f64,
/* TODO: no rules expected this token in macro call
varargs:
#[cfg(feature = "nonexistant")]
fn nonexistant_varargs(f64 ...) -> f64,
*/
);

#[cfg(feature = "dlopen")]
Expand All @@ -20,5 +34,14 @@ mod tests {
let angle = 1.8;
let cosinus = unsafe { ffi_dispatch!(M_STATIC, cos, angle) };
assert_eq!(cosinus, angle.cos());

}

#[cfg(feature = "sin")]
#[test]
fn invoke_sin() {
let angle = 1.8;
let sine = unsafe { ffi_dispatch!(M_STATIC, sin, angle) };
assert_eq!(sine, angle.sin());
}
}
103 changes: 63 additions & 40 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
//! dlib defines the `external_library!` macro, which can be invoked in this way:
//!
//! ```rust
//! # use dlib::external_library;
//! # use std::ffi::{c_float, c_int};
//! external_library!(feature="dlopen-foo", Foo, "foo",
//! statics:
//! me: c_int,
Expand All @@ -28,7 +30,8 @@
//! this macro will expand to an extern block defining each of the items, using the third argument
//! of the macro as a link name:
//!
//! ```rust
//! ```rust no_run
//! # use std::ffi::{c_float, c_int, c_void};
//! #[link(name = "foo")]
//! extern "C" {
//! pub static me: c_int;
Expand All @@ -47,6 +50,8 @@
//! and a method `open`, which tries to load the library from the name or path given as an argument.
//!
//! ```rust
//! # use dlib::DlError;
//! # use std::ffi::{c_float, c_int, c_void};
//! pub struct Foo {
//! pub me: &'static c_int,
//! pub you: &'static c_float,
Expand All @@ -59,7 +64,10 @@
//!
//!
//! impl Foo {
//! pub unsafe fn open(name: &str) -> Result<Foo, DlError> { /* ... */ }
//! pub unsafe fn open(name: &str) -> Result<Foo, DlError> {
//! /* ... */
//! # todo!()
//! }
//! }
//! ```
//!
Expand Down Expand Up @@ -90,7 +98,9 @@
//!
//! Then give the name of that feature as the `feature` argument to dlib's macros:
//!
//! ```rust
//! ```rust no_run
//! # use dlib::external_library;
//! # use std::ffi::c_int;
//! external_library!(feature="dlopen-foo", Foo, "foo",
//! functions:
//! fn foo() -> c_int,
Expand All @@ -99,7 +109,12 @@
//!
//! `dlib` provides helper macros to dispatch the access to foreign symbols:
//!
//! ```rust
//! ```rust no_run
//! # use dlib::{ffi_dispatch, ffi_dispatch_static};
//! # let arg1 = todo!();
//! # let arg2 = todo!();
//! # let function: fn(u32, u32) = todo!();
//! # let my_static_var = todo!();
//! ffi_dispatch!(feature="dlopen-foo", Foo, function, arg1, arg2);
//! ffi_dispatch_static!(feature="dlopen-foo", Foo, my_static_var);
//! ```
Expand All @@ -122,6 +137,8 @@
//! Then, it can become as simple as putting this on top of all modules using the FFI:
//!
//! ```rust
//! # #![allow(unexpected_cfgs)]
//! # mod ffi {}
//! #[cfg(feature = "dlopen-foo")]
//! use ffi::FOO_STATIC;
//! #[cfg(not(feature = "dlopen-foo"))]
Expand Down Expand Up @@ -209,19 +226,22 @@ macro_rules! ffi_dispatch_static(
#[macro_export]
macro_rules! link_external_library(
($link: expr,
$(statics: $($sname: ident: $stype: ty),+,)|*
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
$(statics: $($(#[$sattr:meta])* $sname: ident: $stype: ty),+,)|*
$(functions: $($(#[$fattr:meta])* fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $($(#[$vattr:meta])* fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
) => (
#[link(name = $link)]
extern "C" {
$($(
$(#[$sattr])*
pub static $sname: $stype;
)+)*
$($(
$(#[$fattr])*
pub fn $fname($(_: $farg),*) -> $fret;
)+)*
$($(
$(#[$vattr])*
pub fn $vname($(_: $vargs),+ , ...) -> $vret;
)+)*
}
Expand Down Expand Up @@ -262,51 +282,54 @@ impl std::fmt::Display for DlError {
#[macro_export]
macro_rules! dlopen_external_library(
(__struct, $structname: ident,
$(statics: $($sname: ident: $stype: ty),+,)|*
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
$(statics: $($(#[$sattr:meta])* $sname: ident: $stype: ty),+,)|*
$(functions: $($(#[$fattr:meta])* fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $($(#[$vattr:meta])* fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
) => (
pub struct $structname {
__lib: $crate::Library,
$($(
$(#[$sattr])*
pub $sname: $crate::Symbol<'static, &'static $stype>,
)+)*
$($(
$(#[$fattr])*
pub $fname: $crate::Symbol<'static, unsafe extern "C" fn($($farg),*) -> $fret>,
)+)*
$($(
$(#[$vattr])*
pub $vname: $crate::Symbol<'static, unsafe extern "C" fn($($vargs),+ , ...) -> $vret>,
)+)*
}
);
(__impl, $structname: ident,
$(statics: $($sname: ident: $stype: ty),+,)|*
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
$(statics: $($(#[$sattr:meta])* $sname: ident: $stype: ty),+,)|*
$(functions: $($(#[$fattr:meta])* fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $($(#[$vattr:meta])* fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
) => (
impl $structname {
pub unsafe fn open(name: &str) -> Result<$structname, $crate::DlError> {
// we use it to ensure the 'static lifetime
use std::mem::transmute;
let lib = $crate::Library::new(name).map_err($crate::DlError::CantOpen)?;
let s = $structname {
$($($sname: {
$($($(#[$sattr])* $sname: {
let s_name = concat!(stringify!($sname), "\0");
transmute(match lib.get::<&'static $stype>(s_name.as_bytes()) {
Ok(s) => s,
Err(_) => return Err($crate::DlError::MissingSymbol(s_name))
})
},
)+)*
$($($fname: {
$($($(#[$fattr])* $fname: {
let s_name = concat!(stringify!($fname), "\0");
transmute(match lib.get::<unsafe extern "C" fn($($farg),*) -> $fret>(s_name.as_bytes()) {
Ok(s) => s,
Err(_) => return Err($crate::DlError::MissingSymbol(s_name))
})
},
)+)*
$($($vname: {
$($($(#[$vattr])* $vname: {
let s_name = concat!(stringify!($vname), "\0");
transmute(match lib.get::<unsafe extern "C" fn($($vargs),+ , ...) -> $vret>(s_name.as_bytes()) {
Ok(s) => s,
Expand All @@ -321,19 +344,19 @@ macro_rules! dlopen_external_library(
}
);
($structname: ident,
$(statics: $($sname: ident: $stype: ty),+,)|*
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
$(statics: $($(#[$sattr:meta])* $sname: ident: $stype: ty),+,)|*
$(functions: $($(#[$fattr:meta])* fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $($(#[$vattr:meta])* fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
) => (
$crate::dlopen_external_library!(__struct,
$structname, $(statics: $($sname: $stype),+,)|*
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
$structname, $(statics: $($(#[$sattr])* $sname: $stype),+,)|*
$(functions: $($(#[$fattr])* fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $($(#[$vattr])* fn $vname($($vargs),+) -> $vret),+,)|*
);
$crate::dlopen_external_library!(__impl,
$structname, $(statics: $($sname: $stype),+,)|*
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
$structname, $(statics: $($(#[$sattr])* $sname: $stype),+,)|*
$(functions: $($(#[$fattr])* fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $($(#[$vattr])* fn $vname($($vargs),+) -> $vret),+,)|*
);
unsafe impl Sync for $structname { }
);
Expand All @@ -353,34 +376,34 @@ macro_rules! dlopen_external_library(
#[macro_export]
macro_rules! external_library(
(feature=$feature: expr, $structname: ident, $link: expr,
$(statics: $($sname: ident: $stype: ty),+,)|*
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
$(statics: $($(#[$sattr:meta])* $sname: ident: $stype: ty),+,)|*
$(functions: $($(#[$fattr:meta])* fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $($(#[$vattr:meta])* fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
) => (
#[cfg(feature = $feature)]
$crate::dlopen_external_library!(
$structname, $(statics: $($sname: $stype),+,)|*
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
$structname, $(statics: $($(#[$sattr])* $sname: $stype),+,)|*
$(functions: $($(#[$fattr])* fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $($(#[$vattr])* fn $vname($($vargs),+) -> $vret),+,)|*
);

#[cfg(not(feature = $feature))]
$crate::link_external_library!(
$link, $(statics: $($sname: $stype),+,)|*
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
$link, $(statics: $($(#[$sattr])* $sname: $stype),+,)|*
$(functions: $($(#[$fattr])* fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $($(#[$vattr])* fn $vname($($vargs),+) -> $vret),+,)|*
);
);
($structname: ident, $link: expr,
$(statics: $($sname: ident: $stype: ty),+,)|*
$(functions: $(fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $(fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
$(statics: $($(#[$sattr:meta])* $sname: ident: $stype: ty),+,)|*
$(functions: $($(#[$fattr:meta])* fn $fname: ident($($farg: ty),*) -> $fret:ty),+,)|*
$(varargs: $($(#[$vattr:meta])* fn $vname: ident($($vargs: ty),+) -> $vret: ty),+,)|*
) => (
$crate::external_library!(
feature="dlopen", $structname, $link,
$(statics: $($sname: $stype),+,)|*
$(functions: $(fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $(fn $vname($($vargs),+) -> $vret),+,)|*
$(statics: $($(#[$sattr])* $sname: $stype),+,)|*
$(functions: $($(#[$fattr])* fn $fname($($farg),*) -> $fret),+,)|*
$(varargs: $($(#[$vattr])* fn $vname($($vargs),+) -> $vret),+,)|*
);
);
);