2017-10-02 9 views
5

私はRustでOctave関数をビルドしようとしています。 OctaveのAPIはC++なので、rust-bindgenを使ってバインディングを生成しました。私は現在、bindings that include std::stringを生成しようとしているときに発生する問題を解決しています。 C++ std::stringへの不透明で有効なポインタを残すことができればいいと思います。 C++で渡す必要があるときはいつでも、C++側でユーティリティ関数を構築することは可能でしょうかstd::stringRust interop with C++ std :: string

私が最初にこれを試みたとき、私は素朴でした。明らかに間違っています。錆std::ffi:CStringはC文字列であり、C++文字列ではありません。私はthis recent blog 2つを比較するときに役立つことが分かった。私の最初の試みは、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があることを願っています。どのように進むべきかについての提案はありますか?

+0

Cを知らない++コンパイラ/ stdlibのベンダーはこれを理解していません。私はRustには期待しないだろう。 ; - ](明らかに 'std :: string'は必須の実装であり必須の実装ではありません。値で_anything_を渡したい場合は少なくともサイズ/レイアウトを知る必要があります) – ildjarn

+0

私は試していますUbuntu LinuxでGNU Octaveと相互運用するコンパイラは 'gcc -dumpversion'のgcc 6.3.0で、stdlibは' ldconfigのlibstdC++ .so.6(libc6、x86-64)=> /usr/lib/x86_64-linux-gnu/libstdc++.so.6です。 -p | grep stdC++ 'を実行します。 https://stackoverflow.com/a/10355215/23059 –

+1

「_GLIBCXX_USE_CXX11_ABI」の有無にかかわらず定義されていますか? ; - ]ポイントは、C++で構築ツールを適切に抽象化していない場合は、他の場所で行うことは非常にスリムです。例えば。私のシステムには、libC++、libstdC++、およびDinkumwareのstdlibがあります。 – ildjarn

答えて

3

これは古典的FFIの問題であり、解決策は、「砂時計」のデザインを使用することです:言語A < =>共通ABI < =>言語B.

をそれはもちろん、に、可能かもしれませんbindgenを発展させてC++ ABIを忠実に再現できるようにしますが、実際にはC++コンパイラが必要になります。

「砂時計」デザインを使用すると、難しいABIを持つ各言語は、独自の特殊なツールチェーンを使用して、特定のよく知られたABIに変換します。この場合、C++ < => C < =>錆になります。

考えられる解決策は、C++ APIの周りにCラッパーライブラリを作成し、それにbindgenを使用することです。これがLLVMとClangプロジェクトのやり方です。

これは最も簡単な解決策です。Octavoプロジェクトでは、このようなオクタブロスのファサードをツリー内に統合することができます(これは常に最新のものであることを保証するのが最善です)。


別の解決策は、(std::stringなど)の一般的なC++のタイプのC-ABIを提供するの面倒をbindgenためのC++のコンパニオンライブラリを作成することです。

  • Cは何もジェネリックを持っていない、ので、C++テンプレートは外の範囲のいずれかでなければならない、または事前にインスタンス化されたテンプレートは一度に一つをラップしなければならないであろう。これは、特に以来、より困難な試みだろうC++の型はすでにPODをしている場合を除き、彼らは不透明なポインタを介して操作する必要があるので、
  • Cは、移動またはコピーコンストラクタを呼び出す方法を知らない、
  • Cは...
関連する問題