x86_64 linux only, don't care about other platforms
there is a crate "plugin_trait" , which defines some traits
there is a crate "app", which imports the "plugin_trait" crate" and runs an app
Now, while the "app" is running, we can build a new plugin by using the "plugin_trait" crate, building a *.so, which the currently running app can then dynamically load (and hopefully also unload un-used plugins).
I would suggest referring to this article from Mario Ortiz Manero:
My old Plugins in Rust article is kinda unsound because it passes trait objects across the FFI boundary and not using #[repr(C)] appropriately.
Originally it was assumed that this would be fine as long as you pin the compiler version, but in the 3 years since that article was written a lot of work has been done by the unsafe code workgroup. The biggest difference is that you can no longer rely on different runs of the compiler (even if it's the exact same version) to generate compatible code unless you are explicitly opting into ABI compatibility with #[repr(C)] and explicit calling conventions.
I mean, it works in practice so that's something, but the nice thing about undefined behaviour is that "working exactly like you expect" is just as likely an outcome.
I believe your claim of: it is possible to compile 'app-server' and 'plugin' with same compiler version on some machine, and get incompatibility -- i.e. the app-server segfaulting on trying to load the so.
I find [1] a bit surprising, but believable.
I am not sure if the github repo above suffers from [1].
I am asking, in your opinion, whether the github repo above suffers from [1].
You probably don't want to go down this path, going by the mess amos got himself into:
(Scroll down to "What can prevent dlclose from unloading" of that link doesn't take you there and you don't have half an hour)
Essentially, it is impossible to unload .so's under glibc if there's any global objects in it, which there will be in Rust. They use a terrible terrible crime to force it to happen, but it's not something that should get anywhere near production.
I'd recommend using child processes and IPC of some sort. You can use shared memory if performance is absolutely critical.