The problem is that Symbol comes from an external crate and requires an explicit lifetime. Thus, the lifetime propagates through out the struct and the impl. In my new function inside the implementation I can now not assign the lib to the library field inside the struct because lib's lifetime is shorter. That would still make sense, though it is clearly not what I want. What doesn't make any sense to me is that I am even unable to call lib.get(...) because apparently lib does not live long enough. But why? Lib is defined before and leaves the scope later.
I can also not assign the Library directly to the struct field, because then I end up with the use of an uninitialized field. E.g.
let plg: Plugin;
plg.library = Library::new(path).unwrap();
Does not work.
I tried to Box everything. As I understand that should transfer ownership to the Box'ed field. But that doesn't seam to work either. Should a Box'ed value not also take on the lifetime of the Box as well?
How do I have to write my code, so that I can load a library (dll) and store it in a struct?
I am not sure that I understand the problem fully, but you can try to pass a Library as a parameter to the Plugin::new method, and initialize it elsewhere.
That doesn't really work for me. I get the same issue until I end up initializing the Library in fn main(). I am trying to arrange my code so that I don't have to do that. I don't think that fn main() is the only place in which I can allocate resources. I must have a conceptual problem.
The problem is that
let lib = Library::new(path).unwrap();
let answer: Callback = unsafe {
lib.get(name.as_bytes()).unwrap()
};
only works for me if I do that in fn main(). However, I want to have it elsewhere. But if I do that I get the error that lib.get(...) can't be used because lib does not life long enough. If I were to do it in fn main() I will run into a problem later. Ultimately I want to have a folder with some plugins. The app should load all plugins that are fond in the folder. If I add a new plugin, I don't want to recompile the app. So, I must have a dynamic approach. I won't be able to manually do it in the fn main() anymore.
E.g. This works:
fn main() {
let lib = Library::new("plugins/plg.dll").unwrap();
let answer: Symbol<unsafe extern fn() -> i32> = unsafe {
lib.get(b"answer\0").unwrap()
};
let a = unsafe { answer() };
println!("The answer is: {}", a);
}
At a first glance I don't quite get what is happening here...
I am back at work now and I will need to get back to this later today when I have a chance to devote some time to it. I'll let you know how it works out.
@matklad
First of thank you very much for you help! It is very much appreciated.
Oh man... this was a complicated and heavy birth!
Your link about storing an owner and a reference in the same struct helped me a lot. It explained the issue very well. Your example at github was also very helpful. It contains some nifty techniques I have not even considered (e.g. nested functions).
As I have some plans on how to use this in my app I had some adjustments to make. I will post my solution at the end of the post in case someone else will find it useful. I have a running demo now but it still needs some changes for my specific case later. But it's late now... tomorrow is another day and I will have another issue to solve I consider this specific problem as solved.
@emoon
Thanks for your link. After you posted it I remembered it from another thread. I have looked at it for some inspiration but ended up sticking to finding a solution for my specific problem as I wanted to learn from it so I know how to solve things in the future.
For reference here is what I ended up with:
(Including a hint for further problems, but that was not the issue of this thread. I have also omitted some app specific parts.)
I'm a little surprised there's nothing in the standard library with the shape of fn leak<T>(object: T) -> &'static T. Obviously there are a lot of cases where it'd be completely inappropriate, but if you're loading a bounded number of dynamic libraries "don't unload them" becomes a reasonable option.
fn leak<T>(object: T) -> &'static T {
use std::mem;
let box_ = Box::new(object);
let permaref = unsafe { mem::transmute::<&T, &T>(&box_) };
mem::forget(box_); /* don't ever free the value */
permaref
}
There was a proposal (got closed in favor of getting more experience out of the tree), and the function now exists as an external crate. It has a different signature (fn leak<T>(v: Box<T>) -> &'static T, and also traits for owned containers) though.
That makes me wonder. I have been trying to avoid global variables but would it make sense to have the plugins as global variables? What would be the advantages?