创建一个rust共享库,该库返回一个指向C主程序的函数指针结构



我正在尝试将Rust绑定到nbdkit,但运气不佳。我需要制作一个.so文件,这很容易。.so文件必须有一个名为plugin_init的公共函数,这也很简单。但是,此函数必须返回一个指向C兼容的struct的指针,该CCD_4包含字符串和函数指针的混合(C主程序稍后将调用该指针(。

API是:https://github.com/libguestfs/nbdkit/blob/409ce4c9238a84ede6688423b20d5f706067834b/include/nbdkit-plugin.h#L53

我想出了:

#[repr(C)]
pub struct NBDKitPlugin {
_struct_size: uint64_t,
_api_version: c_int,
_thread_model: c_int,
name: *const c_char,
longname: Option<*const c_char>,
version: Option<*const c_char>,
description: Option<*const c_char>,
load: Option<extern fn ()>,
unload: Option<extern fn ()>,
config: Option<extern fn ()>, // XXX
config_complete: Option<extern fn () -> c_int>,
config_help: Option<*const c_char>,
open: extern fn (c_int) -> *mut c_void,
close: Option<extern fn (*mut c_void)>,
}

和CCD_ 5函数:

extern fn hello_load () {
println! ("hello this is the load method");
}
struct MyHandle {
}
extern fn hello_open (readonly: c_int) -> *mut c_void {
println! ("hello, this is the open method");
let mut h = MyHandle {};
let vp: *mut c_void = &mut h as *mut _ as *mut c_void;
return vp;
}
#[no_mangle]
pub extern fn plugin_init () -> *const NBDKitPlugin {
println! ("hello from the plugin");
let plugin = Box::new (NBDKitPlugin {
_struct_size: mem::size_of::<NBDKitPlugin>() as uint64_t,
_api_version: 2,
_thread_model: 3,
name: CString::new("hello").unwrap().into_raw(),
longname: None,
version: None,
description: None,
load: Some (hello_load),
unload: None,
config: None,
config_complete: None,
config_help: Some (CString::new("my config_help here").unwrap().into_raw()),
open: hello_open,
close: None,
});
return Box::into_raw(plugin);
}

除了内存泄漏之外,这在一定程度上起作用。整数和字符串可以从C中看到。但是函数指针根本不起作用。它们完全是伪造的,似乎比原始指针占据了更多的空间,所以我想我暴露了一个"胖"的Rust指针。

我能找到的关于这个主题的文档似乎很少。帮助

您可能已经了解到,封装在Option(Option<&T>(中的引用(&T(经过优化,使得None被编码为全零,这对引用无效,并且Option<&T>的大小与&T相同。

但是,对于原始指针(*const T*mut T(,所有零都是有效的位模式:它表示空指针。因此,将它们包装在Option中与将i32包装在CCD16中没有什么不同:Option类型更大,因此可以存储判别式。

若要修复结构定义,不得使用Option定义longnameversiondescription

最新更新