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

时间:2018-12-01 18:00:27

标签: c rust ffi

我试图在不多运气的情况下将Rust绑定到nbdkit。我需要制作一个.so文件,这很容易。 .so文件必须具有一个称为plugin_init的公共函数,这也很容易。但是,此函数必须返回一个指向C兼容的struct的指针,该指针包含字符串和函数指针的混合(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)>,
}

和一个plugin_init函数:

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 OK可以看到整数和字符串。但是,函数指针根本不起作用。它们完全是伪造的,似乎比原始指针占用更多的空间,因此我想我要公开一个“胖” Rust指针。

关于该主题的文档很少,我可以找到。帮助。

1 个答案:

答案 0 :(得分:1)

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

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

要修复您的结构定义,不得使用Option来定义longnameversiondescription