Fix 5: Allow backward-compatibility and add plugin-template-v2

This commit is contained in:
Sebastian 2026-06-24 17:17:36 +02:00 committed by Hakan Seven
commit d0003534a0
12 changed files with 568 additions and 60 deletions

View file

@ -41,7 +41,9 @@ pub mod shm;
#[cfg(feature = "host")]
pub mod runner;
pub use manifest::{ApiVersion, PluginManifest, API_VERSION, API_VERSION_MIN_SUPPORTED};
pub use manifest::{
host_accepts_plugin_version, ApiVersion, PluginManifest, API_VERSION, API_VERSION_MIN_SUPPORTED,
};
pub use ribbon::{CadModule, IconKind, ModuleEvent, RibbonGroup, RibbonItem, StyleKey, ToolDef};
#[cfg(feature = "host")]

View file

@ -28,6 +28,13 @@ impl ApiVersion {
}
}
/// True when a plugin built against `plugin_major` can be loaded by this host.
/// The host supports majors from `API_VERSION_MIN_SUPPORTED` up to
/// `API_VERSION`.
pub fn host_accepts_plugin_version(plugin_major: u32) -> bool {
plugin_major >= API_VERSION_MIN_SUPPORTED && plugin_major <= API_VERSION
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -152,7 +152,7 @@ unsafe fn load_plugin(path: &Path) -> Result<Box<dyn BuiltinPlugin>, Box<dyn std
.get(b"ocs_plugin_api_version")
.map_err(|_| "missing ocs_plugin_api_version symbol")?;
let v = version();
if v < crate::API_VERSION_MIN_SUPPORTED || v > crate::API_VERSION {
if !crate::host_accepts_plugin_version(v) {
return Err(format!(
"API version {v} is incompatible (host supports {}-{})",
crate::API_VERSION_MIN_SUPPORTED,

View file

@ -0,0 +1,13 @@
[package]
name = "plugin-template-api2"
version = "0.1.0"
edition = "2021"
description = "API v2 compatibility fixture for the out-of-process plugin path."
license = "GPL-3.0-only"
[lib]
crate-type = ["cdylib"]
[dependencies]
ocs_plugin_api = { path = "../ocs_plugin_api", features = ["host"] }
acadrust = "0.3.4"

View file

@ -0,0 +1,76 @@
//! API v2 compatibility fixture.
//!
//! Mimics an old plugin compiled against `ocs_plugin_api` v2: it reports API
//! major 2 from `ocs_plugin_api_version()` and implements only the v2 surface
//! (`HostApi` methods up to `start_interactive`). The current host must still
//! be able to load and dispatch it.
use ocs_plugin_api::host::{BuiltinPlugin, HostApi};
use ocs_plugin_api::manifest::{ApiVersion, PluginManifest};
use ocs_plugin_api::ribbon::{CadModule, IconKind, ModuleEvent, RibbonGroup, RibbonItem, ToolDef};
static MANIFEST: PluginManifest = PluginManifest {
id: "opencad.my_plugin",
name: "My Plugin",
version: env!("CARGO_PKG_VERSION"),
description: "API v2 fixture plugin.",
api_version: ApiVersion { major: 2 },
ribbon_order: 60,
xdata_apps: &[],
command_prefixes: &["MP_"],
};
struct MyModule;
impl CadModule for MyModule {
fn id(&self) -> &'static str {
"my_plugin"
}
fn title(&self) -> &'static str {
"My Plugin"
}
fn ribbon_groups(&self) -> Vec<RibbonGroup> {
vec![RibbonGroup {
title: "Tools",
tools: vec![RibbonItem::LargeTool(ToolDef {
id: "MP_HELLO",
label: "Hello",
icon: IconKind::Glyph("*"),
event: ModuleEvent::Command("MP_HELLO".to_string()),
})],
}]
}
}
struct MyPlugin;
impl BuiltinPlugin for MyPlugin {
fn manifest(&self) -> &'static PluginManifest {
&MANIFEST
}
fn ribbon(&self) -> Box<dyn CadModule> {
Box::new(MyModule)
}
fn dispatch(&self, host: &mut dyn HostApi, cmd: &str) -> bool {
match cmd {
"MP_HELLO" => {
host.push_info("Hello from API v2 plugin");
true
}
_ => false,
}
}
}
// Custom C-ABI export that reports API v2, emulating an older build of
// `ocs_plugin_api::export_plugin!`.
#[no_mangle]
pub extern "C" fn ocs_plugin_api_version() -> u32 {
2
}
#[no_mangle]
pub extern "C" fn ocs_plugin_register() -> *mut Box<dyn BuiltinPlugin> {
let plugin: Box<dyn BuiltinPlugin> = Box::new(MyPlugin);
Box::into_raw(Box::new(plugin))
}