The code works great and I see 42 printed out every second. However, when I edit render.rs and change that number to 43, then run cargo build inside that project (not the main project), the number does not change.
Are dylibs cached in some way that I am not understanding? Is it possible to do a "hot reload" while the main application is running?
First off, thank you for spending your time looking into this.
If I change 43 to something else, go into ./src/plugin/ and cargo build --release , then go cargo run in the project dir, it works.
Yes, I get the same thing. The issue is when I tuck that code inside of the loop{} and then repeat the above steps while the application is running, I see no change.
Oh, I believe you've misunderstood what Libloading is supposed to do; it's only supposed to load it once, not every time it changes on disk. If you want something like that, then try to use some kind of filesystem notification like notify to drop the preexisting library (It keeps a hold on the file) and then to load the new one.
The above looks like a good place to start getting ideas from. It looks like that crate simply copies the file with a unique name using an epoch prefix to a different directory and renames/shadows it everytime.
Does that mean if I reloaded the library 20x that there will be 20 copies in memory? Or how do I drop it?
When you replace the Library in memory, it will be dropped, and looking at the code for dropping it(On unix):
impl Drop for Library {
fn drop(&mut self) {
with_dlerror(|| if unsafe { dlclose(self.handle) } == 0 {
Some(())
} else {
None
}).unwrap();
}
}
We can see it uses dlclose which has an entry in the man page:
dlclose()
The function dlclose () decrements the reference count on the dynamic library handle handle . If the reference count drops to zero and no other loaded libraries use symbols in it, then the dynamic library is unloaded.
Therefore it will not be loaded 20x on unix systems (and probably not either on windows, glancing at its code it doesn't keep any kind of global state unless the winapi function name is misleading [Which isn't uncommon in my experience]).
Looking at the code for dynamic_reload it appears that it does the job for you.
TL;DR - unloading a library loaded via dlopen in macOS seems to not be possible.
EDIT: well, no, I have that backwards. You may be running into similar restrictions in some way, but it seems as though the objective-c runtime is what's unable to unload modules... so perhaps something else is going on!
Ah, so it sounds like you could try building your dylib as a no_std lib, if possible. At least you could confirm that TLS usage is what's causing your library to not be unloaded.
Yeah, no_std is not going to be an option for what I was hoping to do.
I even tried the solution used in papyrus, and it still did not work! I'll try the dynamic_reload library next I guess, but I don't think its going to change the outcome.
I am a Rust beginner, so the concept of attempting a cdylib also scares me as I barely know enough about Rust types to get by, much less C ones.
Just to followup, I attempted to use the dynamic_library but I had the same issue. It appears that macOS it out to kill my project before I can even start
Thanks for your help, both of you. I was really hoping to avoid compile times on my raspberry pi, but it seems if I want to do any dylib stuff, I have no choice.
If your targeting Linux, have you considered using Docker or some other virtualized environment for development? It’ll probably be a lot less time consuming than waiting for raspberry pi builds...