diff --git a/Cargo.toml b/Cargo.toml index 5cd0e16..721bab1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,69 +1,7 @@ -[package] -name = "dlopen2" -version = "0.5.0" -authors = [ - "Szymon Wieloch ", - "Ahmed Masud ", - "OpenByte "] -description = "Library for opening and operating on dynamic link libraries (also known as shared objects or shared libraries)." -keywords = [ - #common functions - "dlopen", "dll", "so", "dylib", "shared"] -license = "MIT" -repository = "https://github.com/OpenByteDev/dlopen2" -edition = "2021" - -[dependencies] -dlopen2_derive = { path = "dlopen2-derive", version = "0.3", optional = true } -once_cell = "1.18" - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["winnt", "minwindef", "winerror", "libloaderapi", "errhandlingapi", "dbghelp", "processthreadsapi", "basetsd"] } - -[target.'cfg(unix)'.dependencies] -libc = "0.2" - -[dev-dependencies] -const-cstr = "0.3" -regex = "1.8" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -example_dylib = { path = "example-dylib" } -current_platform = "0.2" - - -[features] -default = ["wrapper", "symbor", "derive"] -wrapper = [] -symbor = [] -derive = ["dlopen2_derive"] -doc_cfg = [] - - -[[example]] -name = "raw" -crate-type = ["bin"] - -[[example]] -name = "symbor" -crate-type = ["bin"] - -[[example]] -name = "symbor_api" -crate-type = ["bin"] - -[[example]] -name = "wrapper_api" -crate-type = ["bin"] - -[[example]] -name = "raw_addr_info" -crate-type = ["bin"] - -[[example]] -name = "wrapper_multi_api" -crate-type = ["bin"] - - -[package.metadata.docs.rs] -all-features = true +[workspace] +members = [ + "dlopen2", + "dlopen2-derive", + "example-dylib", +] +resolver = "2" diff --git a/dlopen2-derive/Cargo.toml b/dlopen2-derive/Cargo.toml index c52caa2..4dc3f85 100644 --- a/dlopen2-derive/Cargo.toml +++ b/dlopen2-derive/Cargo.toml @@ -5,11 +5,12 @@ authors = ["Szymon Wieloch ", "OpenByte "] description = "Derive macros for the dlopen2 crate." license = "MIT" +edition = "2021" [lib] proc-macro = true [dependencies] -syn = "2.0" +syn = { version = "2.0", features = ["extra-traits"] } quote = "1.0" proc-macro2 = "1.0" diff --git a/dlopen2/Cargo.toml b/dlopen2/Cargo.toml new file mode 100644 index 0000000..b803e4d --- /dev/null +++ b/dlopen2/Cargo.toml @@ -0,0 +1,68 @@ +[package] +name = "dlopen2" +version = "0.5.0" +authors = [ + "Szymon Wieloch ", + "Ahmed Masud ", + "OpenByte "] +description = "Library for opening and operating on dynamic link libraries (also known as shared objects or shared libraries)." +keywords = [ + "dlopen", "dll", "so", "dylib", "shared"] +license = "MIT" +repository = "https://github.com/OpenByteDev/dlopen2" +edition = "2021" + +[dependencies] +dlopen2_derive = { path = "../dlopen2-derive", version = "0.3", optional = true } +once_cell = "1.18" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["winnt", "minwindef", "winerror", "libloaderapi", "errhandlingapi", "dbghelp", "processthreadsapi", "basetsd"] } + +[target.'cfg(unix)'.dependencies] +libc = "0.2" + +[dev-dependencies] +const-cstr = "0.3" +regex = "1.8" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +example_dylib = { path = "../example-dylib" } +current_platform = "0.2" + + +[features] +default = ["wrapper", "symbor", "derive"] +wrapper = [] +symbor = [] +derive = ["dlopen2_derive"] +doc_cfg = [] + + +[[example]] +name = "raw" +crate-type = ["bin"] + +[[example]] +name = "symbor" +crate-type = ["bin"] + +[[example]] +name = "symbor_api" +crate-type = ["bin"] + +[[example]] +name = "wrapper_api" +crate-type = ["bin"] + +[[example]] +name = "raw_addr_info" +crate-type = ["bin"] + +[[example]] +name = "wrapper_multi_api" +crate-type = ["bin"] + + +[package.metadata.docs.rs] +all-features = true diff --git a/examples/README.md b/dlopen2/examples/README.md similarity index 100% rename from examples/README.md rename to dlopen2/examples/README.md diff --git a/examples/commons/mod.rs b/dlopen2/examples/commons/mod.rs similarity index 100% rename from examples/commons/mod.rs rename to dlopen2/examples/commons/mod.rs diff --git a/examples/raw.rs b/dlopen2/examples/raw.rs similarity index 100% rename from examples/raw.rs rename to dlopen2/examples/raw.rs diff --git a/examples/raw_addr_info.rs b/dlopen2/examples/raw_addr_info.rs similarity index 100% rename from examples/raw_addr_info.rs rename to dlopen2/examples/raw_addr_info.rs diff --git a/examples/symbor.rs b/dlopen2/examples/symbor.rs similarity index 100% rename from examples/symbor.rs rename to dlopen2/examples/symbor.rs diff --git a/examples/symbor_api.rs b/dlopen2/examples/symbor_api.rs similarity index 100% rename from examples/symbor_api.rs rename to dlopen2/examples/symbor_api.rs diff --git a/examples/wrapper_api.rs b/dlopen2/examples/wrapper_api.rs similarity index 100% rename from examples/wrapper_api.rs rename to dlopen2/examples/wrapper_api.rs diff --git a/examples/wrapper_multi_api.rs b/dlopen2/examples/wrapper_multi_api.rs similarity index 96% rename from examples/wrapper_multi_api.rs rename to dlopen2/examples/wrapper_multi_api.rs index fa89b56..47b819b 100644 --- a/examples/wrapper_multi_api.rs +++ b/dlopen2/examples/wrapper_multi_api.rs @@ -1,68 +1,68 @@ -mod commons; -use commons::example_lib_path; - -use dlopen2::wrapper::{Container, WrapperApi, WrapperMultiApi}; -use std::os::raw::c_int; - -//Define 3 APIs: - -#[derive(WrapperApi)] -struct Working1<'a> { - rust_fun_print_something: fn(), - c_fun_add_two: unsafe extern "C" fn(arg: c_int) -> c_int, - rust_i32_mut: &'a mut i32, -} - -#[derive(WrapperApi)] -struct Working2<'a> { - rust_fun_add_one: fn(arg: i32) -> i32, - c_fun_print_something_else: extern "C" fn(), - rust_i32: &'a i32, -} - -//this one wont' work in the example -#[derive(WrapperApi)] -struct NotWorking<'a> { - some_rust_fun: fn(arg: i32) -> i32, - some_c_fun: extern "C" fn(), - some_rust_num: &'a u32, -} - -//Now define a multi wrapper that wraps sub APIs into one bigger API. -//This example assumes that the first API is obligatory and the other two are optional. - -#[derive(WrapperMultiApi)] -struct Api<'a> { - pub obligatory: Working1<'a>, - pub optional1: Option>, - pub optional2: Option>, -} - -fn main() { - let lib_path = example_lib_path(); - let api: Container = unsafe { Container::load(lib_path) }.expect("Could not open library"); - //use obligatory API: - api.obligatory.rust_fun_print_something(); - println!("4+2={}", unsafe { api.obligatory.c_fun_add_two(4) }); - println!("static i32={}", api.obligatory.rust_i32_mut()); - - match api.optional1 { - Some(ref opt) => { - println!("First optional API loaded!"); - println!("3+1={}", opt.rust_fun_add_one(3)); - opt.c_fun_print_something_else(); - println!("static value is {}", opt.rust_i32()) - } - None => println!("Could not load the first optional API"), - } - - match api.optional2 { - Some(ref opt) => { - opt.some_c_fun(); - println!("Second optional API loaded"); - println!("result of some function: {}", opt.some_rust_fun(3)); - println!("static value is {}", opt.some_rust_num()); - } - None => println!("Could not load the second optional API"), - } -} +mod commons; +use commons::example_lib_path; + +use dlopen2::wrapper::{Container, WrapperApi, WrapperMultiApi}; +use std::os::raw::c_int; + +//Define 3 APIs: + +#[derive(WrapperApi)] +struct Working1<'a> { + rust_fun_print_something: fn(), + c_fun_add_two: unsafe extern "C" fn(arg: c_int) -> c_int, + rust_i32_mut: &'a mut i32, +} + +#[derive(WrapperApi)] +struct Working2<'a> { + rust_fun_add_one: fn(arg: i32) -> i32, + c_fun_print_something_else: extern "C" fn(), + rust_i32: &'a i32, +} + +//this one wont' work in the example +#[derive(WrapperApi)] +struct NotWorking<'a> { + some_rust_fun: fn(arg: i32) -> i32, + some_c_fun: extern "C" fn(), + some_rust_num: &'a u32, +} + +//Now define a multi wrapper that wraps sub APIs into one bigger API. +//This example assumes that the first API is obligatory and the other two are optional. + +#[derive(WrapperMultiApi)] +struct Api<'a> { + pub obligatory: Working1<'a>, + pub optional1: Option>, + pub optional2: Option>, +} + +fn main() { + let lib_path = example_lib_path(); + let api: Container = unsafe { Container::load(lib_path) }.expect("Could not open library"); + //use obligatory API: + api.obligatory.rust_fun_print_something(); + println!("4+2={}", unsafe { api.obligatory.c_fun_add_two(4) }); + println!("static i32={}", api.obligatory.rust_i32_mut()); + + match api.optional1 { + Some(ref opt) => { + println!("First optional API loaded!"); + println!("3+1={}", opt.rust_fun_add_one(3)); + opt.c_fun_print_something_else(); + println!("static value is {}", opt.rust_i32()) + } + None => println!("Could not load the first optional API"), + } + + match api.optional2 { + Some(ref opt) => { + opt.some_c_fun(); + println!("Second optional API loaded"); + println!("result of some function: {}", opt.some_rust_fun(3)); + println!("static value is {}", opt.some_rust_num()); + } + None => println!("Could not load the second optional API"), + } +} diff --git a/src/err.rs b/dlopen2/src/err.rs similarity index 100% rename from src/err.rs rename to dlopen2/src/err.rs diff --git a/src/lib.rs b/dlopen2/src/lib.rs similarity index 100% rename from src/lib.rs rename to dlopen2/src/lib.rs diff --git a/src/raw/common.rs b/dlopen2/src/raw/common.rs similarity index 100% rename from src/raw/common.rs rename to dlopen2/src/raw/common.rs diff --git a/src/raw/mod.rs b/dlopen2/src/raw/mod.rs similarity index 100% rename from src/raw/mod.rs rename to dlopen2/src/raw/mod.rs diff --git a/src/raw/tests.rs b/dlopen2/src/raw/tests.rs similarity index 100% rename from src/raw/tests.rs rename to dlopen2/src/raw/tests.rs diff --git a/src/raw/unix.rs b/dlopen2/src/raw/unix.rs similarity index 100% rename from src/raw/unix.rs rename to dlopen2/src/raw/unix.rs diff --git a/src/raw/windows.rs b/dlopen2/src/raw/windows.rs similarity index 100% rename from src/raw/windows.rs rename to dlopen2/src/raw/windows.rs diff --git a/src/symbor/api.rs b/dlopen2/src/symbor/api.rs similarity index 100% rename from src/symbor/api.rs rename to dlopen2/src/symbor/api.rs diff --git a/src/symbor/container.rs b/dlopen2/src/symbor/container.rs similarity index 100% rename from src/symbor/container.rs rename to dlopen2/src/symbor/container.rs diff --git a/src/symbor/from_raw.rs b/dlopen2/src/symbor/from_raw.rs similarity index 100% rename from src/symbor/from_raw.rs rename to dlopen2/src/symbor/from_raw.rs diff --git a/src/symbor/library.rs b/dlopen2/src/symbor/library.rs similarity index 100% rename from src/symbor/library.rs rename to dlopen2/src/symbor/library.rs diff --git a/src/symbor/mod.rs b/dlopen2/src/symbor/mod.rs similarity index 97% rename from src/symbor/mod.rs rename to dlopen2/src/symbor/mod.rs index f5d1043..7d812de 100644 --- a/src/symbor/mod.rs +++ b/dlopen2/src/symbor/mod.rs @@ -1,110 +1,110 @@ -/*! -High-level and safe API for opening and getting symbols from dynamic libraries. -It is based on symbol borrowing mechanism and supports automatic loading of symbols into structures. - -This API uses Rust borrowing mechanism to prevent problems with dangling symbols -that take place when the library gets closed but the symbols still exist and are used. - -#Example of a dangling symbol prevention -```no_run -use dlopen2::symbor::Library; -fn main(){ - let lib = Library::open("libexample.dylib").unwrap(); - let fun = unsafe{lib.symbol::f64>("some_symbol_name")}.unwrap(); - println!("fun(1.0) = {}", unsafe{fun(1.0)}); - - //this would not compile because fun is a symbol borrowed from lib - //drop(lib); -} -``` -**Note:** All kind of objects from the `symbor` module implement the Deref or DerefMut trait. -This means that you can use them as if you would use primitive types that they wrap. - -It also allows automatic loading of symbols into a structure. -This is especially handy if you have a huge API with multiple symbols: - -# Example of automatic symbol loading - -```no_run -use dlopen2::symbor::{Library, Symbol, Ref, PtrOrNull, SymBorApi}; - - #[derive(SymBorApi)] - struct ExampleApi<'a> { - pub fun: Symbol<'a, unsafe extern "C" fn(i32) -> i32>, - pub glob_i32: Ref<'a, i32>, - pub maybe_c_str: PtrOrNull<'a, u8>, - pub opt_fun: Option> - } - -fn main(){ - let lib = Library::open("example.dll").expect("Could not open library"); - let api = unsafe{ExampleApi::load(&lib)}.expect("Could not load symbols"); - println!("fun(4)={}", unsafe{(api.fun)(4)}); - println!("glob_i32={}", *api.glob_i32); - println!("The pointer is null={}", api.maybe_c_str.is_null()); - match api.opt_fun { - Some(fun) => fun(), - None => println!("Optional function not found in the library") - } - - //this would not compile: - //drop(lib); -} -``` - -**Note:** You can obtain optional symbols (`Option>`). -This is very useful when you are dealing with - different versions of libraries and the newer versions support more functions. - If it is not possible to obtain the given symbol, the option is set to `None', - otherwise it contains the obtained symbol. - -Unfortunately in Rust it is not possible to create an API for dynamic link libraries that would -be 100% safe. This API aims to be 99% safe by providing zero cost wrappers around raw symbols. -However it is possible to make a mistake if you dereference safe wrappers into raw symbols. - -#Example of a mistake - dangling symbol - -```no_run -use dlopen2::symbor::Library; -fn main(){ - let raw_fun = { - let lib = Library::open("libexample.dylib").unwrap(); - let safe_fun = unsafe{ - lib.symbol::f64>("some_symbol_name") - }.unwrap(); - *safe_fun - }; - - //raw_fun is now a dangling symbol -} -``` - -Original idea for this solution comes from Simonas Kazlauskas and his crate -[libloading](https://github.com/nagisa/rust_libloading). -Many improvements were added to solve several issues. - -*/ - -mod api; -mod container; -mod from_raw; -mod library; -mod option; -mod ptr_or_null; -mod ptr_or_null_mut; -mod reference; -mod reference_mut; -mod symbol; - -pub use self::api::SymBorApi; -pub use self::container::Container; -pub use self::from_raw::FromRawResult; -pub use self::library::Library; -pub use self::ptr_or_null::PtrOrNull; -pub use self::ptr_or_null_mut::PtrOrNullMut; -pub use self::reference::Ref; -pub use self::reference_mut::RefMut; -pub use self::symbol::Symbol; - -#[cfg(feature = "derive")] -pub use dlopen2_derive::SymBorApi; +/*! +High-level and safe API for opening and getting symbols from dynamic libraries. +It is based on symbol borrowing mechanism and supports automatic loading of symbols into structures. + +This API uses Rust borrowing mechanism to prevent problems with dangling symbols +that take place when the library gets closed but the symbols still exist and are used. + +#Example of a dangling symbol prevention +```no_run +use dlopen2::symbor::Library; +fn main(){ + let lib = Library::open("libexample.dylib").unwrap(); + let fun = unsafe{lib.symbol::f64>("some_symbol_name")}.unwrap(); + println!("fun(1.0) = {}", unsafe{fun(1.0)}); + + //this would not compile because fun is a symbol borrowed from lib + //drop(lib); +} +``` +**Note:** All kind of objects from the `symbor` module implement the Deref or DerefMut trait. +This means that you can use them as if you would use primitive types that they wrap. + +It also allows automatic loading of symbols into a structure. +This is especially handy if you have a huge API with multiple symbols: + +# Example of automatic symbol loading + +```no_run +use dlopen2::symbor::{Library, Symbol, Ref, PtrOrNull, SymBorApi}; + + #[derive(SymBorApi)] + struct ExampleApi<'a> { + pub fun: Symbol<'a, unsafe extern "C" fn(i32) -> i32>, + pub glob_i32: Ref<'a, i32>, + pub maybe_c_str: PtrOrNull<'a, u8>, + pub opt_fun: Option> + } + +fn main(){ + let lib = Library::open("example.dll").expect("Could not open library"); + let api = unsafe{ExampleApi::load(&lib)}.expect("Could not load symbols"); + println!("fun(4)={}", unsafe{(api.fun)(4)}); + println!("glob_i32={}", *api.glob_i32); + println!("The pointer is null={}", api.maybe_c_str.is_null()); + match api.opt_fun { + Some(fun) => fun(), + None => println!("Optional function not found in the library") + } + + //this would not compile: + //drop(lib); +} +``` + +**Note:** You can obtain optional symbols (`Option>`). +This is very useful when you are dealing with + different versions of libraries and the newer versions support more functions. + If it is not possible to obtain the given symbol, the option is set to `None', + otherwise it contains the obtained symbol. + +Unfortunately in Rust it is not possible to create an API for dynamic link libraries that would +be 100% safe. This API aims to be 99% safe by providing zero cost wrappers around raw symbols. +However it is possible to make a mistake if you dereference safe wrappers into raw symbols. + +#Example of a mistake - dangling symbol + +```no_run +use dlopen2::symbor::Library; +fn main(){ + let raw_fun = { + let lib = Library::open("libexample.dylib").unwrap(); + let safe_fun = unsafe{ + lib.symbol::f64>("some_symbol_name") + }.unwrap(); + *safe_fun + }; + + //raw_fun is now a dangling symbol +} +``` + +Original idea for this solution comes from Simonas Kazlauskas and his crate +[libloading](https://github.com/nagisa/rust_libloading). +Many improvements were added to solve several issues. + +*/ + +mod api; +mod container; +mod from_raw; +mod library; +mod option; +mod ptr_or_null; +mod ptr_or_null_mut; +mod reference; +mod reference_mut; +mod symbol; + +pub use self::api::SymBorApi; +pub use self::container::Container; +pub use self::from_raw::FromRawResult; +pub use self::library::Library; +pub use self::ptr_or_null::PtrOrNull; +pub use self::ptr_or_null_mut::PtrOrNullMut; +pub use self::reference::Ref; +pub use self::reference_mut::RefMut; +pub use self::symbol::Symbol; + +#[cfg(feature = "derive")] +pub use dlopen2_derive::SymBorApi; diff --git a/src/symbor/option.rs b/dlopen2/src/symbor/option.rs similarity index 100% rename from src/symbor/option.rs rename to dlopen2/src/symbor/option.rs diff --git a/src/symbor/ptr_or_null.rs b/dlopen2/src/symbor/ptr_or_null.rs similarity index 100% rename from src/symbor/ptr_or_null.rs rename to dlopen2/src/symbor/ptr_or_null.rs diff --git a/src/symbor/ptr_or_null_mut.rs b/dlopen2/src/symbor/ptr_or_null_mut.rs similarity index 100% rename from src/symbor/ptr_or_null_mut.rs rename to dlopen2/src/symbor/ptr_or_null_mut.rs diff --git a/src/symbor/reference.rs b/dlopen2/src/symbor/reference.rs similarity index 100% rename from src/symbor/reference.rs rename to dlopen2/src/symbor/reference.rs diff --git a/src/symbor/reference_mut.rs b/dlopen2/src/symbor/reference_mut.rs similarity index 100% rename from src/symbor/reference_mut.rs rename to dlopen2/src/symbor/reference_mut.rs diff --git a/src/symbor/symbol.rs b/dlopen2/src/symbor/symbol.rs similarity index 100% rename from src/symbor/symbol.rs rename to dlopen2/src/symbor/symbol.rs diff --git a/src/utils.rs b/dlopen2/src/utils.rs similarity index 100% rename from src/utils.rs rename to dlopen2/src/utils.rs diff --git a/src/wrapper/api.rs b/dlopen2/src/wrapper/api.rs similarity index 100% rename from src/wrapper/api.rs rename to dlopen2/src/wrapper/api.rs diff --git a/src/wrapper/container.rs b/dlopen2/src/wrapper/container.rs similarity index 100% rename from src/wrapper/container.rs rename to dlopen2/src/wrapper/container.rs diff --git a/src/wrapper/mod.rs b/dlopen2/src/wrapper/mod.rs similarity index 96% rename from src/wrapper/mod.rs rename to dlopen2/src/wrapper/mod.rs index cff198d..8bcd0d1 100644 --- a/src/wrapper/mod.rs +++ b/dlopen2/src/wrapper/mod.rs @@ -1,85 +1,85 @@ -/*! -High-level and safe API for opening and getting symbols from dynamic link libraries. -It is based on wrapping private symbols with public functions to prevent direct access -and supports automatic loading of symbols into structures. - -This API solves the problem with dangling symbols by wrapping raw symbols with public functions. -User of API does not have direct access to raw symbols and therefore symbols cannot be copied. -Symbols and library handle are kept in one `Container` structure and therefore both the the library -and symbols get released at the same time. - -#Example - -```no_run -use dlopen2::wrapper::{Container, WrapperApi}; - -#[derive(WrapperApi)] -struct Example<'a> { - do_something: extern "C" fn(), - add_one: unsafe extern "C" fn (arg: i32) -> i32, - global_count: &'a mut u32, -} - -fn main () { -let mut container: Container = unsafe { Container::load("libexample.dylib")}.unwrap(); -container.do_something(); -let _result = unsafe { container.add_one(5) }; -*container.global_count_mut() += 1; - -//symbols are released together with library handle -//this prevents dangling symbols -drop(container); -} -``` - -Unfortunately in Rust it is not possible to create an API for dynamic link libraries that would -be 100% safe. This API aims to be 99% safe by providing zero cost functional wrappers around -raw symbols. However it is possible to make a mistake if you create API as a standalone object -(not in container): - -#Example of a mistake - dangling symbol - -```no_run -use dlopen2::wrapper::{Container, WrapperApi}; -use dlopen2::raw::Library; - -#[derive(WrapperApi)] -struct Example<'a> { - do_something: extern "C" fn(), - add_one: unsafe extern "C" fn (arg: i32) -> i32, - global_count: &'a mut u32, -} - -fn main () { -let lib = Library::open("libexample.dylib").unwrap(); -let mut api = unsafe{Example::load(&lib)}; -drop(lib); - -//api has now dangling symbols - -} -``` - -To prevent this mistake don't use structures implementing `WrapperApi` directly, but rather use -`Container` as in the first example. - -**Note:** This API has a broad support for optional symbols (this solves the issue with multiple -versions of one dynamic link library that have different sets of symbols). Please refer to the -documentation of -[`OptionalContainer`](./struct.OptionalContainer.html) -and -[`WrapperMultiApi`](./trait.WrapperMultiApi.html). -*/ - -mod api; -mod container; -mod multi_api; -mod option; -mod optional; -pub use self::api::WrapperApi; -pub use self::container::Container; -pub use self::multi_api::WrapperMultiApi; -pub use self::optional::OptionalContainer; - -#[cfg(feature = "derive")] -pub use dlopen2_derive::{WrapperApi, WrapperMultiApi}; +/*! +High-level and safe API for opening and getting symbols from dynamic link libraries. +It is based on wrapping private symbols with public functions to prevent direct access +and supports automatic loading of symbols into structures. + +This API solves the problem with dangling symbols by wrapping raw symbols with public functions. +User of API does not have direct access to raw symbols and therefore symbols cannot be copied. +Symbols and library handle are kept in one `Container` structure and therefore both the the library +and symbols get released at the same time. + +#Example + +```no_run +use dlopen2::wrapper::{Container, WrapperApi}; + +#[derive(WrapperApi)] +struct Example<'a> { + do_something: extern "C" fn(), + add_one: unsafe extern "C" fn (arg: i32) -> i32, + global_count: &'a mut u32, +} + +fn main () { +let mut container: Container = unsafe { Container::load("libexample.dylib")}.unwrap(); +container.do_something(); +let _result = unsafe { container.add_one(5) }; +*container.global_count_mut() += 1; + +//symbols are released together with library handle +//this prevents dangling symbols +drop(container); +} +``` + +Unfortunately in Rust it is not possible to create an API for dynamic link libraries that would +be 100% safe. This API aims to be 99% safe by providing zero cost functional wrappers around +raw symbols. However it is possible to make a mistake if you create API as a standalone object +(not in container): + +#Example of a mistake - dangling symbol + +```no_run +use dlopen2::wrapper::{Container, WrapperApi}; +use dlopen2::raw::Library; + +#[derive(WrapperApi)] +struct Example<'a> { + do_something: extern "C" fn(), + add_one: unsafe extern "C" fn (arg: i32) -> i32, + global_count: &'a mut u32, +} + +fn main () { +let lib = Library::open("libexample.dylib").unwrap(); +let mut api = unsafe{Example::load(&lib)}; +drop(lib); + +//api has now dangling symbols + +} +``` + +To prevent this mistake don't use structures implementing `WrapperApi` directly, but rather use +`Container` as in the first example. + +**Note:** This API has a broad support for optional symbols (this solves the issue with multiple +versions of one dynamic link library that have different sets of symbols). Please refer to the +documentation of +[`OptionalContainer`](./struct.OptionalContainer.html) +and +[`WrapperMultiApi`](./trait.WrapperMultiApi.html). +*/ + +mod api; +mod container; +mod multi_api; +mod option; +mod optional; +pub use self::api::WrapperApi; +pub use self::container::Container; +pub use self::multi_api::WrapperMultiApi; +pub use self::optional::OptionalContainer; + +#[cfg(feature = "derive")] +pub use dlopen2_derive::{WrapperApi, WrapperMultiApi}; diff --git a/src/wrapper/multi_api.rs b/dlopen2/src/wrapper/multi_api.rs similarity index 100% rename from src/wrapper/multi_api.rs rename to dlopen2/src/wrapper/multi_api.rs diff --git a/src/wrapper/option.rs b/dlopen2/src/wrapper/option.rs similarity index 100% rename from src/wrapper/option.rs rename to dlopen2/src/wrapper/option.rs diff --git a/src/wrapper/optional.rs b/dlopen2/src/wrapper/optional.rs similarity index 100% rename from src/wrapper/optional.rs rename to dlopen2/src/wrapper/optional.rs diff --git a/tests/commons/mod.rs b/dlopen2/tests/commons/mod.rs similarity index 100% rename from tests/commons/mod.rs rename to dlopen2/tests/commons/mod.rs diff --git a/tests/raw.rs b/dlopen2/tests/raw.rs similarity index 100% rename from tests/raw.rs rename to dlopen2/tests/raw.rs diff --git a/tests/symbor.rs b/dlopen2/tests/symbor.rs similarity index 100% rename from tests/symbor.rs rename to dlopen2/tests/symbor.rs diff --git a/tests/symbor_api.rs b/dlopen2/tests/symbor_api.rs similarity index 100% rename from tests/symbor_api.rs rename to dlopen2/tests/symbor_api.rs diff --git a/tests/wrapper_api.rs b/dlopen2/tests/wrapper_api.rs similarity index 100% rename from tests/wrapper_api.rs rename to dlopen2/tests/wrapper_api.rs diff --git a/example-dylib/Cargo.toml b/example-dylib/Cargo.toml index 9df2ebf..f7ee022 100644 --- a/example-dylib/Cargo.toml +++ b/example-dylib/Cargo.toml @@ -3,8 +3,9 @@ name = "example_dylib" version = "0.2.0" authors = ["Szymon Wieloch ", "OpenByte "] -license = "MIT" description = "Example dynamic link library for executing tests of libraries that load and operate on dynamic link libraries" +license = "MIT" +edition = "2021" [lib] name = "example"