Remove deprecated bevy_dynamic_plugin (#14534)

# Objective

- Dynamic plugins were deprecated in #13080 due to being unsound. The
plan was to deprecate them in 0.14 and remove them in 0.15.

## Solution

- Remove all dynamic plugin functionality.
- Update documentation to reflect this change.

---

## Migration Guide

Dynamic plugins were deprecated in 0.14 for being unsound, and they have
now been fully removed. Please consider using the alternatives listed in
the `bevy_dynamic_plugin` crate documentation, or worst-case scenario
you may copy the code from 0.14.
This commit is contained in:
BD103 2024-07-30 11:31:08 -04:00 committed by GitHub
parent 9575b20d31
commit d722fef23d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 2 additions and 219 deletions

View file

@ -110,9 +110,6 @@ bevy_core_pipeline = [
"bevy_render", "bevy_render",
] ]
# Plugin for dynamic loading (using [libloading](https://crates.io/crates/libloading))
bevy_dynamic_plugin = ["bevy_internal/bevy_dynamic_plugin"]
# Adds gamepad support # Adds gamepad support
bevy_gilrs = ["bevy_internal/bevy_gilrs"] bevy_gilrs = ["bevy_internal/bevy_gilrs"]

View file

@ -18,7 +18,6 @@ mod sub_app;
mod terminal_ctrl_c_handler; mod terminal_ctrl_c_handler;
pub use app::*; pub use app::*;
pub use bevy_derive::DynamicPlugin;
pub use main_schedule::*; pub use main_schedule::*;
pub use panic_handler::*; pub use panic_handler::*;
pub use plugin::*; pub use plugin::*;
@ -38,6 +37,6 @@ pub mod prelude {
PostStartup, PostUpdate, PreStartup, PreUpdate, SpawnScene, Startup, Update, PostStartup, PostUpdate, PreStartup, PreUpdate, SpawnScene, Startup, Update,
}, },
sub_app::SubApp, sub_app::SubApp,
DynamicPlugin, Plugin, PluginGroup, Plugin, PluginGroup,
}; };
} }

View file

@ -120,16 +120,6 @@ impl Plugin for PlaceholderPlugin {
fn build(&self, _app: &mut App) {} fn build(&self, _app: &mut App) {}
} }
/// A type representing an unsafe function that returns a mutable pointer to a [`Plugin`].
/// It is used for dynamically loading plugins.
///
/// See `bevy_dynamic_plugin/src/loader.rs#dynamically_load_plugin`.
#[deprecated(
since = "0.14.0",
note = "The current dynamic plugin system is unsound and will be removed in 0.15."
)]
pub type CreatePlugin = unsafe fn() -> *mut dyn Plugin;
/// Types that represent a set of [`Plugin`]s. /// Types that represent a set of [`Plugin`]s.
/// ///
/// This is implemented for all types which implement [`Plugin`], /// This is implemented for all types which implement [`Plugin`],

View file

@ -1,22 +0,0 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[deprecated(
since = "0.14.0",
note = "The current dynamic plugin system is unsound and will be removed in 0.15."
)]
pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let struct_name = &ast.ident;
TokenStream::from(quote! {
#[no_mangle]
pub extern "C" fn _bevy_create_plugin() -> *mut dyn bevy::app::Plugin {
// make sure the constructor is the correct type.
let object = #struct_name {};
let boxed = Box::new(object);
Box::into_raw(boxed)
}
})
}

View file

@ -9,7 +9,6 @@
extern crate proc_macro; extern crate proc_macro;
mod app_plugin;
mod bevy_main; mod bevy_main;
mod derefs; mod derefs;
mod enum_variant_meta; mod enum_variant_meta;
@ -18,19 +17,6 @@ use bevy_macro_utils::{derive_label, BevyManifest};
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::format_ident; use quote::format_ident;
/// Generates a dynamic plugin entry point function for the given `Plugin` type.
///
/// This is deprecated since 0.14. The current dynamic plugin system is unsound and will be removed in 0.15.
#[proc_macro_derive(DynamicPlugin)]
#[deprecated(
since = "0.14.0",
note = "The current dynamic plugin system is unsound and will be removed in 0.15."
)]
pub fn derive_dynamic_plugin(input: TokenStream) -> TokenStream {
#[allow(deprecated)]
app_plugin::derive_dynamic_plugin(input)
}
/// Implements [`Deref`] for structs. This is especially useful when utilizing the [newtype] pattern. /// Implements [`Deref`] for structs. This is especially useful when utilizing the [newtype] pattern.
/// ///
/// For single-field structs, the implementation automatically uses that field. /// For single-field structs, the implementation automatically uses that field.

View file

@ -31,7 +31,7 @@ sysinfo = { version = "0.30.0", optional = true, default-features = false, featu
"apple-app-store", "apple-app-store",
] } ] }
# Only include when not bevy_dynamic_plugin and on linux/windows/android # Only include when on linux/windows/android
[target.'cfg(any(target_os = "linux", target_os = "windows", target_os = "android"))'.dependencies] [target.'cfg(any(target_os = "linux", target_os = "windows", target_os = "android"))'.dependencies]
sysinfo = { version = "0.30.0", optional = true, default-features = false } sysinfo = { version = "0.30.0", optional = true, default-features = false }

View file

@ -1,24 +0,0 @@
[package]
name = "bevy_dynamic_plugin"
version = "0.15.0-dev"
edition = "2021"
description = "Provides dynamic plugin loading capabilities for non-wasm platforms"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT OR Apache-2.0"
keywords = ["bevy"]
[dependencies]
# bevy
bevy_app = { path = "../bevy_app", version = "0.15.0-dev" }
# other
libloading = { version = "0.8" }
thiserror = "1.0"
[lints]
workspace = true
[package.metadata.docs.rs]
rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"]
all-features = true

View file

@ -1,7 +0,0 @@
# Bevy Dynamic Plugin
[![License](https://img.shields.io/badge/license-MIT%2FApache-blue.svg)](https://github.com/bevyengine/bevy#license)
[![Crates.io](https://img.shields.io/crates/v/bevy_dynamic_plugin.svg)](https://crates.io/crates/bevy_dynamic_plugin)
[![Downloads](https://img.shields.io/crates/d/bevy_dynamic_plugin.svg)](https://crates.io/crates/bevy_dynamic_plugin)
[![Docs](https://docs.rs/bevy_dynamic_plugin/badge.svg)](https://docs.rs/bevy_dynamic_plugin/latest/bevy_dynamic_plugin/)
[![Discord](https://img.shields.io/discord/691052431525675048.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/bevy)

View file

@ -1,41 +0,0 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc(
html_logo_url = "https://bevyengine.org/assets/icon.png",
html_favicon_url = "https://bevyengine.org/assets/icon.png"
)]
//! Bevy's dynamic plugin loading functionality.
//!
//! This crate allows loading dynamic libraries (`.dylib`, `.so`) that export a single
//! [`Plugin`](bevy_app::Plugin). For usage, see [`dynamically_load_plugin`].
//!
//! # Deprecation
//!
//! The current dynamic plugin system is unsound and will be removed in 0.15. You may be interested
//! in the [Alternatives](#alternatives) listed below. If your use-case is not supported, please
//! consider commenting on [#13080](https://github.com/bevyengine/bevy/pull/13080) describing how
//! you use dynamic plugins in your project.
//!
//! # Warning
//!
//! Note that dynamic linking and loading is inherently unsafe because it allows executing foreign
//! code. Additionally, Rust does not have a stable ABI and may produce
//! incompatible libraries across Rust versions, or even subsequent compilations. This will not work
//! well in scenarios such as modding, but can work if the dynamic plugins and the main app are
//! built at the same time, such as with Downloadable Content (DLC) packs.
//!
//! # Alternatives
//!
//! You may be interested in these safer alternatives:
//!
//! - [Bevy Assets - Scripting]: Scripting and modding libraries for Bevy
//! - [Bevy Assets - Development tools]: Hot reloading and other development functionality
//! - [`stabby`]: Stable Rust ABI
//!
//! [Bevy Assets - Scripting]: https://bevyengine.org/assets/#scripting
//! [Bevy Assets - Development tools]: https://bevyengine.org/assets/#development-tools
//! [`stabby`]: https://github.com/ZettaScaleLabs/stabby
mod loader;
pub use loader::*;

View file

@ -1,86 +0,0 @@
#![allow(unsafe_code)]
#![allow(deprecated)]
use libloading::{Library, Symbol};
use std::ffi::OsStr;
use thiserror::Error;
use bevy_app::{App, CreatePlugin, Plugin};
/// Errors that can occur when loading a dynamic plugin
#[derive(Debug, Error)]
#[deprecated(
since = "0.14.0",
note = "The current dynamic plugin system is unsound and will be removed in 0.15."
)]
pub enum DynamicPluginLoadError {
/// An error occurred when loading a dynamic library.
#[error("cannot load library for dynamic plugin: {0}")]
Library(#[source] libloading::Error),
/// An error occurred when loading a library without a valid Bevy plugin.
#[error("dynamic library does not contain a valid Bevy dynamic plugin")]
Plugin(#[source] libloading::Error),
}
/// Dynamically links a plugin at the given path. The plugin must export a function with the
/// [`CreatePlugin`] signature named `_bevy_create_plugin`.
///
/// # Safety
///
/// 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`].
///
/// Dynamically loading plugins is orchestrated through dynamic linking. When linking against
/// foreign code, initialization routines may be run (as well as termination routines when the
/// program exits). The caller of this function is responsible for ensuring these routines are
/// sound. For more information, please see the safety section of [`libloading::Library::new`].
#[deprecated(
since = "0.14.0",
note = "The current dynamic plugin system is unsound and will be removed in 0.15."
)]
pub unsafe fn dynamically_load_plugin<P: AsRef<OsStr>>(
path: P,
) -> Result<(Library, Box<dyn Plugin>), DynamicPluginLoadError> {
// SAFETY: Caller must follow the safety requirements of Library::new.
let lib = unsafe { Library::new(path).map_err(DynamicPluginLoadError::Library)? };
// SAFETY: Loaded plugins are not allowed to specify `_bevy_create_plugin` symbol manually, but
// must instead automatically generate it through `DynamicPlugin`.
let func: Symbol<CreatePlugin> = unsafe {
lib.get(b"_bevy_create_plugin")
.map_err(DynamicPluginLoadError::Plugin)?
};
// SAFETY: `func` is automatically generated and is guaranteed to return a pointer created using
// `Box::into_raw`.
let plugin = unsafe { Box::from_raw(func()) };
Ok((lib, plugin))
}
/// An extension trait for [`App`] that allows loading dynamic plugins.
#[deprecated(
since = "0.14.0",
note = "The current dynamic plugin system is unsound and will be removed in 0.15."
)]
pub trait DynamicPluginExt {
/// Dynamically links a plugin at the given path, registering the plugin.
///
/// For more details, see [`dynamically_load_plugin`].
///
/// # Safety
///
/// See [`dynamically_load_plugin`]'s safety section.
unsafe fn load_plugin<P: AsRef<OsStr>>(&mut self, path: P) -> &mut Self;
}
impl DynamicPluginExt for App {
unsafe fn load_plugin<P: AsRef<OsStr>>(&mut self, path: P) -> &mut Self {
// SAFETY: Follows the same safety requirements as `dynamically_load_plugin`.
let (lib, plugin) = unsafe { dynamically_load_plugin(path).unwrap() };
std::mem::forget(lib); // Ensure that the library is not automatically unloaded
plugin.build(self);
self
}
}

View file

@ -230,7 +230,6 @@ bevy_audio = { path = "../bevy_audio", optional = true, version = "0.15.0-dev" }
bevy_color = { path = "../bevy_color", optional = true, version = "0.15.0-dev" } bevy_color = { path = "../bevy_color", optional = true, version = "0.15.0-dev" }
bevy_core_pipeline = { path = "../bevy_core_pipeline", optional = true, version = "0.15.0-dev" } bevy_core_pipeline = { path = "../bevy_core_pipeline", optional = true, version = "0.15.0-dev" }
bevy_dev_tools = { path = "../bevy_dev_tools", optional = true, version = "0.15.0-dev" } bevy_dev_tools = { path = "../bevy_dev_tools", optional = true, version = "0.15.0-dev" }
bevy_dynamic_plugin = { path = "../bevy_dynamic_plugin", optional = true, version = "0.15.0-dev" }
bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.15.0-dev" } bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.15.0-dev" }
bevy_gizmos = { path = "../bevy_gizmos", optional = true, version = "0.15.0-dev", default-features = false } bevy_gizmos = { path = "../bevy_gizmos", optional = true, version = "0.15.0-dev", default-features = false }
bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.15.0-dev" } bevy_gltf = { path = "../bevy_gltf", optional = true, version = "0.15.0-dev" }

View file

@ -29,8 +29,6 @@ pub use bevy_core_pipeline as core_pipeline;
#[cfg(feature = "bevy_dev_tools")] #[cfg(feature = "bevy_dev_tools")]
pub use bevy_dev_tools as dev_tools; pub use bevy_dev_tools as dev_tools;
pub use bevy_diagnostic as diagnostic; pub use bevy_diagnostic as diagnostic;
#[cfg(feature = "bevy_dynamic_plugin")]
pub use bevy_dynamic_plugin as dynamic_plugin;
pub use bevy_ecs as ecs; pub use bevy_ecs as ecs;
#[cfg(feature = "bevy_gilrs")] #[cfg(feature = "bevy_gilrs")]
pub use bevy_gilrs as gilrs; pub use bevy_gilrs as gilrs;

View file

@ -51,10 +51,6 @@ pub use crate::text::prelude::*;
#[cfg(feature = "bevy_ui")] #[cfg(feature = "bevy_ui")]
pub use crate::ui::prelude::*; pub use crate::ui::prelude::*;
#[doc(hidden)]
#[cfg(feature = "bevy_dynamic_plugin")]
pub use crate::dynamic_plugin::*;
#[doc(hidden)] #[doc(hidden)]
#[cfg(feature = "bevy_gizmos")] #[cfg(feature = "bevy_gizmos")]
pub use crate::gizmos::prelude::*; pub use crate::gizmos::prelude::*;

View file

@ -54,7 +54,6 @@ The default feature set enables most of the expected features of a game engine,
|bevy_ci_testing|Enable systems that allow for automated testing on CI| |bevy_ci_testing|Enable systems that allow for automated testing on CI|
|bevy_debug_stepping|Enable stepping-based debugging of Bevy systems| |bevy_debug_stepping|Enable stepping-based debugging of Bevy systems|
|bevy_dev_tools|Provides a collection of developer tools| |bevy_dev_tools|Provides a collection of developer tools|
|bevy_dynamic_plugin|Plugin for dynamic loading (using [libloading](https://crates.io/crates/libloading))|
|bmp|BMP image format support| |bmp|BMP image format support|
|dds|DDS compressed texture support| |dds|DDS compressed texture support|
|debug_glam_assert|Enable assertions in debug builds to check the validity of parameters passed to glam| |debug_glam_assert|Enable assertions in debug builds to check the validity of parameters passed to glam|

View file

@ -16,7 +16,6 @@ crates=(
bevy_app bevy_app
bevy_time bevy_time
bevy_log bevy_log
bevy_dynamic_plugin
bevy_asset/macros bevy_asset/macros
bevy_asset bevy_asset
bevy_audio bevy_audio