tyleo / sharedlib Goto Github PK
View Code? Open in Web Editor NEWThis project forked from nagisa/rust_libloading
A cross-platform shared library loader.
Home Page: https://tyleo.github.io/sharedlib/
License: ISC License
This project forked from nagisa/rust_libloading
A cross-platform shared library loader.
Home Page: https://tyleo.github.io/sharedlib/
License: ISC License
Is it possible to make any of the Lib structs safely implement Send trait ?
I would have a working test for this. It is an important use-case.
I would like to have tests which load a freshly compiled shared library. I have an msbuild project which does this but I would like to convert it into gradle. Since the whole point of this code is to be able to load your own compiled shared libraries, we should have at least one test which does exactly that.
Since I want to load dynamic libraries manually at runtime, I might also first know about the function types at runtime, so doing it like in the example code, where you cast the functions found by a name functions to a specific function type, won't work.
Specifically, I'm working on a scripting language, and want to add support for calling extern functions. This would be the best way to call it.
What I basically want is something method, which takes the name and the byte representations of arguments, and returns the byte representation of the return value.
Is something like this possible as well?
This might also help for calling variadic functions like printf, where I don't know a real dynamic way yet.
I am facing strange behavior: when I am passing the absolute path to Lib::new
method, it returns an error saying that it cannot find the file. However, calling canonicalize
on the passed Path
removes the problem. I wouldn't call it weird if the original path wouldn't be absolute, but it is
I've used this code to check if my suspicions are correct. I've used sharedlib
and libloading
crates as alternatives. The second test passes, and the first one fails on the third assert
use sharedlib::Lib;
use libloading::Library;
use std::path::Path;
static LIB_PATH: &str = "/tmp/libgetset.so";
#[test]
fn test_not_canonical_path() {
let path = Path::new(LIB_PATH);
println!("{:?}", &path);
assert!(path.exists());
let library = unsafe { Library::new(&path) };
assert!(library.is_ok());
let library = unsafe { Lib::new(&path) };
assert!(library.is_ok());
}
#[test]
fn test_canonical_path() {
let path = Path::new(LIB_PATH).canonicalize().unwrap();
println!("{:?}", &path);
assert!(path.exists());
let library = unsafe { Library::new(&path) };
assert!(library.is_ok());
let library = unsafe { Lib::new(&path) };
assert!(library.is_ok());
}
fn main() {
}
I am using Linux machine with Ubuntu 16.04
The dynamic library I am using is compiled getset
procedural macro, but I think it doesn't really matter and you can replace it with what you have at hand
I was trying to hack around dlopen
and then I found sharedlib
. Looks like I finally found an answer to developing a plugin system for my application :-) So, first of all, thanks!
My requirement is kind of a classic use case for sharedlib
. My application will have multiple layers (protocols and APIs) of plugins, with the eventual goal of making these plugins composable. These plugins need to be loaded at runtime by the main binary (named unicorn
), depending on runtime arguments and configuration.
The core application is written in Rust and, for now, all the plugins will be in Rust as well. I'm compiling them using crate_type
as dylib
. Each of these plugins expose a set of known symbols. They are stored in a known location, like this:
- plugins/
-- libx.so
-- liby.so
To make things simple, consider this example: When the main binary is run with unicorn run x
, it loads libx
with Lib::new("plugins/libx.so")
, tries to find a function symbol called run\0
and executes it.
Now, my question is, pardon the noobness: Will sharedlib
load the entire .so
file in memory when I try to load one of the plugins? So, if the .so
file is 5MB in size, does that mean 5MB of memory is used to open the lib?
(Edit) P.S. AFAIK Dynamic loading is supposed to load the library in memory, get pointers, execute them and unload. My question is to know whether sharedlib
does the same for the libraries it loads.
I can't figure out the lifetimes. As far as I can tell, this should be valid:
use winapi::{HANDLE, DWORD, PCHAR, BOOL};
use winapi::{HMODULE, FARPROC};
use kernel32::{LoadLibraryA, FreeLibrary};
use sharedlib::{Lib, Func, Symbol, Result};
static path: &'static str = "winsta.dll\0";
type connect_a = extern "system" fn (hServer: HANDLE, SessionID: DWORD, TargetSessionID: DWORD, pPassword: *const u8, bWait: BOOL) -> BOOL;
pub struct Dll<'a> {
lib: Lib,
connect_a: Func<'a, connect_a>,
}
impl<'a> Dll<'a> {
pub fn WinStationConnectA(&self, h: HANDLE, sid: DWORD, tsid: DWORD, pw: *const u8, wait: BOOL) -> BOOL {
unsafe {
self.connect_a.get()(h, sid, tsid, pw, wait)
}
}
}
pub fn load<'a>() -> Result<Dll<'a>> {
let lib0: Lib = try!(unsafe {Lib::new(path)} );
let sym = try!(unsafe {lib0.find_func("WinStationConnectA\0")});
let dll: Dll<'a> = Dll {
lib: lib0,
connect_a: sym,
};
return Ok(dll)
}
It should be possible to put a Lib and a Func into a struct that's parameterized by a lifetime, since the Lib will outlive the Func. But the compiler claims that lib0
only lives until the end of the function, even though I move it into .lib
. Clearly I intend it to live as long as the Dll
struct lives, but I see the problem that interior mutability in Dll could result in assignment to .lib
.
I imagine this use case isn't unique, and I couldn't find any examples in the documentation showing the correct way to do this.
Interested in using this project but when I ran the tests I got failures, please advise:
thread 'test::shared::check_test_value' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("test/.build/libexamplelib.dylib"), State { next_error: Some(Error(OsError("dlopen(test/.build/libexamplelib.dylibassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
---- test::shared::create_struct_unsafe stdout ----
thread 'test::shared::create_struct_unsafe' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("test/.build/libexamplelib.dylib"), State { next_error: Some(Error(OsError("dlopen(test/.build/libexamplelib.dylibassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
---- test::shared::add_2_numbers stdout ----
thread 'test::shared::add_2_numbers' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("test/.build/libexamplelib.dylib"), State { next_error: Some(Error(OsError("dlopen(test/.build/libexamplelib.dylibassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
---- test::shared::create_struct_arc stdout ----
thread 'test::shared::create_struct_arc' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("test/.build/libexamplelib.dylib"), State { next_error: Some(Error(OsError("dlopen(test/.build/libexamplelib.dylibassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
---- test::shared::create_struct_safe stdout ----
thread 'test::shared::create_struct_safe' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("test/.build/libexamplelib.dylib"), State { next_error: Some(Error(OsError("dlopen(test/.build/libexamplelib.dylibassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
---- test::shared::load_examplelib stdout ----
thread 'test::shared::load_examplelib' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("test/.build/libexamplelib.dylib"), State { next_error: Some(Error(OsError("dlopen(test/.build/libexamplelib.dylibassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
---- test::unix::shared::libm_ceil stdout ----
thread 'test::unix::shared::libm_ceil' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("libm.dylib"), State { next_error: Some(Error(OsError("dlopen(libm.dylibmassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
---- test::unix::shared::new_libm stdout ----
thread 'test::unix::shared::new_libm' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("libm.dylib"), State { next_error: Some(Error(OsError("dlopen(libm.dylibmassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
---- test::unix::shared::libm_ceil0 stdout ----
thread 'test::unix::shared::libm_ceil0' panicked at 'called `Result::unwrap()` on an `Err` value: Error(LibraryOpen("libm.dylib"), State { next_error: Some(Error(OsError("dlopen(libm.dylibmassertion failed: `(left == right)`\n left: ``,\n right: ``, 1): image not found", "dlopen"), State { next_error: None })) })', libcore/result.rs:945:5
E.g.:
let path_to_lib_str =
path_to_lib
.as_ref()
.to_string_lossy();
let path_to_lib_c_str = path_to_lib_str.as_ptr() as *const c_char;
here path_to_lib_c_str
is not really a c_str, but a pointer to a regular Rust utf8 string slice. The issue can be reproduced with something like this:
let name = "mylib.so123";
LibUnsafe::new(&name[0..8]).unwrap();
where mylib.so
is a valid shared lib that can be located by dlopen.
The documentation could use some updating. Here is what I'm thinking:
LibArc
and LibRc
in the Choosing your guarantees section.Data
, Func
s, and Lib
s, especially information about unsafety and information about writing optimally performant code.SharedlibError
. Include an example of error handling code.For some reason we are importing the Unix os with #[macro_use]
. This is probably not necessary.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.