Rust interop with C++ std::string

送分小仙女□ 提交于 2020-01-24 03:30:26

问题


I'm trying to build Octave functions in Rust. Octave's API is in C++, so I've generated bindings using rust-bindgen. I'm currently working through the problems that occur when trying to generate bindings that include std::string. It would be nice if I could leave it opaque and valid pointer to a C++ std::string. Would it be possible to build a utility function on the C++ side any time I needed to pass in a C++ std::string?

I was naive when I first attempted this. It is clearly wrong. A Rust std::ffi:CString is for C strings, not C++ strings. I found this recent blog helpful when comparing the two. My first attempt looks like this:

#![allow(non_snake_case)]
#![allow(unused_variables)]

extern crate octh;

// https://thefullsnack.com/en/string-ffi-rust.html
use std::ffi::CString;

#[no_mangle]
pub unsafe extern "C"  fn Ghelloworld (shl: *const octh::root::octave::dynamic_library, relative: bool) -> *mut octh::root::octave_dld_function {
    let name = CString::new("helloworld").unwrap();
    let pname = name.as_ptr() as *const octh::root::std::string;
    std::mem::forget(pname);

    let doc = CString::new("Hello World Help String").unwrap();
    let pdoc = doc.as_ptr() as *const octh::root::std::string;
    std::mem::forget(pdoc);

    octh::root::octave_dld_function_create(Some(Fhelloworld), shl, pname, pdoc)
}    

pub unsafe extern "C" fn Fhelloworld (args: *const octh::root::octave_value_list, nargout: ::std::os::raw::c_int) -> octh::root::octave_value_list {
    let list_ptr = ::std::ptr::null_mut();
    octh::root::octave_value_list_new(list_ptr);
    ::std::ptr::read(list_ptr)
}

I need to pass in the function name and documentation as strings to octave_dld_function_create. I wish there was a CppString that I could use instead. Any suggestions on how to proceed?


回答1:


This is a classic FFI issue and the solution is to use a "hour-glass" design: Language A <=> Common ABI <=> Language B.

It could be possible, of course, to evolve bindgen so that it can faithfully reproduce a C++ ABI, but in practice it would require a full C++ compiler which is probably too much effort.

Using a "hour-glass" design, each of the languages with a difficult ABI use their own specialized toolchain to convert to a specific well-known ABI. In this case, it would be C++ <=> C <=> Rust.

A possible solution is to create a C wrapper library around the C++ API, and then use bindgen on that. This is what the LLVM and Clang projects do.

It is the simplest solution, and the Octavo project may very well be willing to integrate such an octavo-c facade in-tree (which is always best to guarantee it's up-to-date).


Another solution would be to create a C++ companion library for bindgen, which takes care of providing a C-ABI for common C++ types (such as std::string). This would be a more difficult endeavor, especially since:

  • C has no generics, thus C++ templates would have to be either out-of-scope, or pre-instantiated templates would have to be wrapped one at a time,
  • C does not know how to invoke move or copy constructors, so unless the C++ types are already PODs, they have to be manipulated through opaque pointers,
  • C does not know ...


来源:https://stackoverflow.com/questions/46524781/rust-interop-with-c-stdstring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!