我使用以下方案:
所有代码(主程序,动态库)都是用Rust编写的,它都是用-Cprefer-dynamic
编译的。
动态库包含一个Plugin
结构,它使用plugin::Plugin
函数实现new
特征,该函数返回一个盒装特征对象(plugin::Plugin
)。
动态库示例:
#[derive(Debug)]
pub struct Plugin;
impl Plugin {
#[no_mangle]
pub fn new() -> Box<plugin::Plugin> {
println!("IN NEW!");
Box::new(Plugin)
}
}
impl plugin::Plugin for Plugin {
fn test(&mut self) -> plugin::Result<()> {
println!("IN TEST!");
Ok(())
}
}
plugin::Plugin
是一个特质:
pub trait Plugin: Debug {
fn test(&mut self) -> Result<()>;
}
主程序:
fn main() {
env_logger::init().unwrap();
info!("[MAIN]<-");
if let Ok(mut plugins) = load(Path::new("plugins/")) {
for (path, plugin) in plugins.iter_mut() {
debug!("path: {:?}, plugin: {:?}", path, plugin);
plugin.plugin.test();
}
thread::sleep(Duration::from_secs(30));
// <- as soon as the plugins is beyond his lifetime, segmentation fault.
}
info!("[MAIN]->");
}
fn load(path: & Path) -> Result<HashMap<String, Plugin>> {
let mut plugins = HashMap::new();
let valid_extensions: [& OsStr; 3] = ["dylib".as_ref(), "so".as_ref(), "dll".as_ref()];
for dir_entry in try!(path.read_dir()) {
let path = try!(dir_entry).path();
if path.extension().is_none() || !valid_extensions.contains(& path.extension().unwrap()) {
warn!("invalid dynamic library extension; extension: {:?}", path.extension());
continue
}
let key = path.clone().into_os_string().into_string().unwrap();
let lib = DynamicLibrary::open(Some(& path)).unwrap();
let new: extern fn() -> Box<plugin::Plugin> = unsafe {
std::mem::transmute(lib.symbol::<u8>("new").unwrap())
};
let plugin = Plugin {
_lib: lib,
plugin: new(),
};
plugins.insert(key.clone(), plugin);
}
Ok(plugins)
}
struct Plugin {
_lib: DynamicLibrary,
pub plugin: Box<plugin::Plugin>,
}
将FFI用于此类Rust-Rust交互是否正确?