Skip to content
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

[Merged by Bors] - bevy_dynamic_plugin: make it possible to handle loading errors #6437

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions crates/bevy_dynamic_plugin/Cargo.toml
Expand Up @@ -16,3 +16,4 @@ bevy_app = { path = "../bevy_app", version = "0.9.0-dev" }

# other
libloading = { version = "0.7" }
thiserror = "1.0"
24 changes: 19 additions & 5 deletions crates/bevy_dynamic_plugin/src/loader.rs
@@ -1,7 +1,17 @@
use libloading::{Library, Symbol};
use thiserror::Error;

use bevy_app::{App, CreatePlugin, Plugin};

/// Errors that can occur when loading a dynamic plugin
#[derive(Debug, Error)]
pub enum DynamicPluginLoadError {
#[error("cannot load library for dynamic plugin: {0}")]
inodentry marked this conversation as resolved.
Show resolved Hide resolved
Library(libloading::Error),
#[error("dynamic library does not contain a valid Bevy dynamic plugin")]
Plugin(libloading::Error),
}

/// Dynamically links a plugin at the given path. The plugin must export a function with the
/// [`CreatePlugin`] signature named `_bevy_create_plugin`.
///
Expand All @@ -10,11 +20,15 @@ use bevy_app::{App, CreatePlugin, Plugin};
/// The specified plugin must be linked against the exact same libbevy.so as this program.
/// In addition the `_bevy_create_plugin` symbol must not be manually created, but instead created
/// by deriving `DynamicPlugin` on a unit struct implementing [`Plugin`].
pub unsafe fn dynamically_load_plugin(path: &str) -> (Library, Box<dyn Plugin>) {
let lib = Library::new(path).unwrap();
let func: Symbol<CreatePlugin> = lib.get(b"_bevy_create_plugin").unwrap();
pub unsafe fn dynamically_load_plugin(
path: &str,
) -> Result<(Library, Box<dyn Plugin>), DynamicPluginLoadError> {
let lib = Library::new(path).map_err(DynamicPluginLoadError::Library)?;
let func: Symbol<CreatePlugin> = lib
.get(b"_bevy_create_plugin")
.map_err(DynamicPluginLoadError::Plugin)?;
let plugin = Box::from_raw(func());
(lib, plugin)
Ok((lib, plugin))
}

pub trait DynamicPluginExt {
Expand All @@ -26,7 +40,7 @@ pub trait DynamicPluginExt {

impl DynamicPluginExt for App {
unsafe fn load_plugin(&mut self, path: &str) -> &mut Self {
let (lib, plugin) = dynamically_load_plugin(path);
let (lib, plugin) = dynamically_load_plugin(path).unwrap();
std::mem::forget(lib); // Ensure that the library is not automatically unloaded
plugin.build(self);
self
Expand Down