use std::io; use anyhow::{Context, Result, bail}; use libloading::Library; use plugin_api::Plugin; use tempfile::NamedTempFile; use crate::LocatedPlugin; pub struct LoadedPlugin { pub located: LocatedPlugin, pub plugin: Box, // DO NOT MOVE THIS UP! // This is due to rust's dropping order! // If the library gets dropped (unloaded) before the plugin, a segfault will occur. pub lib: Library, } pub fn load(mut plugin: LocatedPlugin) -> Result { #[cfg(target_os = "linux")] let cdylib = plugin.so; #[cfg(target_os = "windows")] let cdylib = plugin.dll; #[cfg(target_os = "macos")] let cdylib = plugin.dylib; if !cdylib { bail!("unsupported platform"); } #[cfg(target_os = "linux")] let cdylib = "plugin.so"; #[cfg(target_os = "windows")] let cdylib = "plugin.dll"; #[cfg(target_os = "macos")] let cdylib = "plugin.dylib"; let mut tmp = NamedTempFile::new().context("failed creating temp file")?; { let mut entry = plugin.zip.by_name(cdylib).unwrap(); io::copy(&mut entry, &mut tmp).context("failed copying cdylib to temp file")?; } unsafe { let lib = Library::new(tmp.path().display().to_string()).context("failed loading library")?; let ctor = lib .get:: Box>(b"provide_plugin") .context("plugin does not have a provide_plugin function")?; let instance = ctor(); Ok(LoadedPlugin { located: plugin, lib, plugin: instance, }) } }