Expand description
Build-time support for copying plugin libraries into the Cargo output directory.
This module provides utilities for integrating plugin libraries into Rust applications
at build time. It is designed to be used from build.rs scripts to automatically copy
plugin dynamic libraries from their build locations into the application’s output directory,
making them available for runtime loading.
§Overview
The plugin system requires dynamic libraries to be available at runtime in a known location. This module solves that problem by:
- Reading plugin declarations from
[package.metadata.plugins]inCargo.toml - Resolving plugin library paths (supporting both absolute and relative paths)
- Copying plugin libraries to
target/{PROFILE}/plugins/ - Emitting
cargo:rerun-if-changeddirectives for proper incremental builds
§Plugin Declaration Format
Plugins are declared in the consuming application’s Cargo.toml under
[package.metadata.plugins]. The format supports both individual plugins and
grouped plugins:
[package.metadata.plugins]
# Individual plugin
ssh_plugin = "target/{PROFILE}/libssh_plugin.so"
# Grouped plugins
[package.metadata.plugins.connection]
ssh = "../plugins/ssh/target/{PROFILE}/libssh.so"
telnet = "../plugins/telnet/target/{PROFILE}/libtelnet.so"
# Absolute paths are also supported
[package.metadata.plugins.system]
audit = "/opt/genja/plugins/libaudit.so"§Path Resolution
Plugin paths can be specified in three ways:
- Relative paths: Resolved relative to the manifest directory (where
Cargo.tomllives) - Absolute paths: Used as-is without modification
- Profile placeholders: The
{PROFILE}placeholder is replaced with the current build profile (“debug” or “release”)
§Build Integration
To use this module in your application, add a build.rs file to your project root:
// build.rs
fn main() {
genja_plugin_manager::build_support::copy_plugins_from_manifest()
.expect("Failed to copy plugins");
}Then declare your plugins in Cargo.toml:
[package.metadata.plugins]
my_plugin = "target/{PROFILE}/libmy_plugin.so"§Runtime Loading
After build-time copying, plugins can be loaded at runtime using the plugin manager:
use genja_plugin_manager::PluginManager;
let mut manager = PluginManager::new();
manager.load_plugins_from_directory("target/debug/plugins")?;§Cross-Platform Considerations
The helper reads only [package.metadata.plugins], so the plugin path you
declare there must use the correct filename for the OS building the
application:
Linux:
[package.metadata.plugins]
my_plugin = "target/{PROFILE}/libmy_plugin.so"macOS:
[package.metadata.plugins]
my_plugin = "target/{PROFILE}/libmy_plugin.dylib"Windows:
[package.metadata.plugins]
my_plugin = "target/{PROFILE}/my_plugin.dll"§Error Handling
All functions in this module return io::Result<()>. Common error scenarios include:
- Missing environment variables (
CARGO_MANIFEST_DIR,OUT_DIR,PROFILE) - Invalid
Cargo.tomlsyntax or structure - Missing plugin source files
- Permission errors when creating directories or copying files
- Invalid plugin path configurations (e.g., paths with no filename)
§Examples
§Basic Usage
// build.rs
fn main() {
genja_plugin_manager::build_support::copy_plugins_from_manifest()
.expect("Failed to copy plugins");
}§With Error Handling
// build.rs
fn main() {
if let Err(e) = genja_plugin_manager::build_support::copy_plugins_from_manifest() {
eprintln!("Warning: Failed to copy plugins: {}", e);
eprintln!("Plugins may not be available at runtime");
}
}§Multiple Plugin Groups
[package.metadata.plugins.connection]
ssh = "target/{PROFILE}/libssh.so"
telnet = "target/{PROFILE}/libtelnet.so"
[package.metadata.plugins.inventory]
file = "target/{PROFILE}/libfile_inventory.so"
database = "target/{PROFILE}/libdb_inventory.so"
[package.metadata.plugins.runner]
threaded = "target/{PROFILE}/libthreaded_runner.so"
serial = "target/{PROFILE}/libserial_runner.so"§Implementation Notes
- The module uses
cargo:rerun-if-changeddirectives to ensure plugins are recopied when source files change - Plugin directory structure is created automatically if it doesn’t exist
- Existing plugin files in the destination are overwritten without warning
- The module processes nested plugin groups recursively
- Profile resolution happens before path resolution, allowing profile-specific paths
Functions§
- copy_
plugins_ from_ manifest - Copy plugin libraries declared in
[package.metadata.plugins]from the calling application’sCargo.tomlintotarget/{PROFILE}/plugins.