-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot load library if new fields are added in sabi_trait trait #118
Comments
It seems to me like extensibility is there to support loading newer libraries than expected, essentially working in the wrong direction to what's needed for a plugin system. Try compiling the plugin with interface 0.1.1, then loading it with interface 0.1.0. This works in my experience, but is really the opposite of what I wanted. EDIT: let lib = PluginLibRef::load_from_file(&PathBuf::from("tests/data/libexample_provider.so"))
.expect("plugin must be loadable"); You check the version and type layout yourself, reversing the expected and actual layouts: let header = lib_header_from_path(&PathBuf::from("tests/data/libexample_provider.so"))
.expect("plugin library header must be loadable");
// TODO check version strings manually
if let IsLayoutChecked::Yes(layout) = header.root_mod_consts().layout() {
// Note the full path here, the abi_checking module is hidden from documentation
// Also note the arguments have been reversed, passing the plugin's layout first
abi_stable::abi_stability::abi_checking::check_layout_compatibility(layout, PluginLibRef::LAYOUT)
.expect("interface must be compatible");
};
let lib = unsafe {
header
.unchecked_layout::<PluginLibRef>()
.expect("plugin broke while loading")
}; Then everything seems to work like you would want for a plugin system. I can add new methods/nonexhaustive variants to the interface and still load older libraries, but not the other way around. No clue whether this is still safe to use, but it seems to behave correctly for now. |
@thorio, that's a good idea for validating the layout, in my testing I did managed to use the unsafe functions to load the library which ignored layout validation, and everything seems to work as expected. My version of ensuring compatibility was a bit different, I used the same check_layout_compatibility function without reversing the arguments but instead permissively passes the validation if the error detected is just AbiInstability::FieldCountMismatch where expected count is more than actual count fn ensure_compatibility(
interface: &'static TypeLayout,
implementation: &'static TypeLayout,
) -> Result<(), AbiInstabilityErrors> {
let compatibility = abi_stable::abi_stability::abi_checking::check_layout_compatibility(
interface,
implementation,
);
if let Err(err) = compatibility {
let incompatibilities = err.errors.iter().filter(|e| !e.errs.is_empty());
let fatal_incompatibilities = incompatibilities.filter(|err| {
err.errs.iter().any(|err| {
!matches!(
err,
AbiInstability::FieldCountMismatch(assert) if assert.expected > assert.found
)
})
});
if fatal_incompatibilities.count() > 0 {
return Err(err);
}
}
Ok(())
} Checking the generated code for the Trait_TO, this part of the docs does work as expected (ie: default implementation does get invoked if there's no corresponding VTable entry in the library layout).
It's just the layout checking logic that seems to be contradicting what the docs say.
|
For people who have stumbled upon this same plugin use case, I have since changed my approach to implementing a plugin system. Check out remoc's rtc feature which can create the same sort of RPC capability like sabi_trait as long as there is a binary pipe between 2 ends (even across networks). In fact, you can even combine sabi with remoc, with sabi providing the abi stable pipe to a dylib using the |
Hello, I'm currently trying out this crate to implement a plugin system.
Although the docs seem to suggest that I can load a library that's compiled against a previous minor version of the shared interface, I'm getting a AbiInstability error when trying to load.
I'm not sure whether I'm doing anything wrong which made it not work.
With the above interface crate, I'm able to compile and run
hello()
without issues. However if I update thePlugin
trait as such and try to rebuild & run the main executable without recompiling the library, I'm getting a AbiInstability error "Too many fields" while loading the library.Logging the AbiInstability error
The text was updated successfully, but these errors were encountered: