【问题标题】:Rust interop with C++ std::stringRust 与 C++ std::string 互操作
【发布时间】:2018-03-13 11:33:11
【问题描述】:

我正在尝试在 Rust 中构建 Octave 函数。 Octave 的 API 在 C++ 中,所以我使用 rust-bindgen 生成了绑定。我目前正在解决尝试生成bindings that include std::string 时出现的问题。如果我能让它保持不透明且指向C++ std::string 的有效指针,那就太好了。是否可以在我需要传入 C++ std::string 的任何时候在 C++ 端构建实用程序函数?

当我第一次尝试这个时,我很天真。这显然是错误的。 Rust std::ffi:CString 用于 C 字符串,而不是 C++ 字符串。我发现this recent blog 在比较两者时很有帮助。我的第一次尝试看起来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)
}

我需要将函数名称和文档作为字符串传递给octave_dld_function_create。我希望有一个CppString 可以代替我使用。关于如何进行的任何建议?

【问题讨论】:

  • C++ 编译器/stdlib 供应商没有解决这个问题;我不希望 Rust 会。 ;-](需要明确的是,std::string 是一个强制接口,而不是强制实现,如果你想通过值传递任何东西,你至少需要知道它的大小/布局。)
  • 我正在尝试与 Ubuntu Linux 上的 GNU Octave 互操作。编译器是来自gcc -dumpversion 的gcc 6.3.0,标准库是来自ldconfig -p | grep stdc++ 的libstdc++.so.6 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libstdc++.so.6。 stackoverflow.com/a/10355215/23059
  • 那是定义了_GLIBCXX_USE_CXX11_ABI 还是没有定义? ;-] 重点是,如果它没有在 C++ 构建工具中正确抽象,那么在其他地方这样做的机会非常渺茫。例如。我的系统有可用的 libc++、libstdc++ 和 Dinkumware 标准库。
  • 我不知道。我看到在一些 Octave 构建文件中引用了 -lstdc++。我不确定我需要一些抽象的东西。我可以在构建时向 Octave 库添加一个函数。
  • -lstdc++ 是一个链接器命令,它只暗示一些(共享)目标文件要链接到;因为即使是 C++ 编译器也不知道“std::string 是什么?”这个问题的答案,除了你提供给它的源代码。

标签: c++ string rust interop


【解决方案1】:

这是一个经典的 FFI 问题,解决方案是使用“沙漏”设计:语言 A 通用 ABI 语言 B。

当然,有可能改进 bindgen 以便它可以忠实地重现 C++ ABI,但实际上它需要一个完整的 C++ 编译器,这可能需要付出太多努力。

使用“沙漏”设计,每种具有困难 ABI 的语言都使用自己的专用工具链来转换为特定的知名 ABI。在这种情况下,它将是 C++ C Rust。

一个可能的解决方案是围绕 C++ API 创建一个 C 包装库,然后在其上使用 bindgen。这就是 LLVM 和 Clang 项目所做的。

这是最简单的解决方案,Octavo 项目很可能愿意将这样的 octavo-c 外观集成到树中(这总是最好的保证它是最新的)。


另一个解决方案是为 bindgen 创建一个 C++ 配套库,它负责为常见的 C++ 类型(例如 std::string)提供 C-ABI。这将是一项更加困难的工作,尤其是因为:

  • C 没有泛型,因此 C++ 模板必须超出范围,或者必须一次包装一个预先实例化的模板,
  • C 不知道如何调用移动或复制构造函数,因此除非 C++ 类型已经是 POD,否则它们必须通过不透明指针进行操作,
  • C 不知道...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-23
    • 2021-05-19
    • 1970-01-01
    • 2019-06-04
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 2017-10-26
    相关资源
    最近更新 更多