C ++には多くの移植性の問題がありますが、これはバイナリレベルでの標準化の欠如によるものです。
こんなに簡単だとは思いません。提供された回答は、標準化に焦点が当てられていないことに関してすでに優れた理論的根拠を提供していますが、C ++は言語が豊富すぎて、ABI標準としてのCと真に競合するには適していないかもしれません。
関数のオーバーロード、vtableの非互換性、モジュールの境界を越えてスローされる例外との非互換性などに起因する名前のマングリングに進むことができます。これらはすべて非常に苦痛です。
しかし、ABI規格は、あるコンパイラで作成されたC ++ dylibを、別のコンパイラで作成された別のバイナリで使用できるようにすることだけではありません。ABIは言語間で使用されます。彼らが少なくとも最初の部分をカバーできればいいのですが、C ++が最も広く互換性のあるdylibを作るために非常に重要な普遍的なABIレベルでCと真に競合することを見る方法はありません。
次のようにエクスポートされた単純な関数のペアを想像してください。
void f(Foo foo);
void f(Bar bar, int val);
...そして、パラメータ化されたコンストラクタ、コピーコンストラクタ、移動コンストラクタ、および非自明なデストラクタを持つクラスを想像Foo
しBar
ました。
次に、Python / Lua / C#/ Java / Haskell / etcのシナリオを取り上げます。開発者がこのモジュールをインポートして、言語で使用しようとしています。
最初に、関数のオーバーロードを利用してシンボルをエクスポートする方法の名前マングリング標準が必要です。これは簡単な部分です。しかし、実際には「マングリング」という名前であってはなりません。dylibのユーザーは名前でシンボルを検索する必要があるため、ここでのオーバーロードは完全な混乱のように見えない名前につながるはずです。たぶん、シンボル名はそのような"f_Foo"
"f_Bar_int"
ものかもしれませんし、その種のものかもしれません。開発者が実際に定義した名前と衝突しないようにする必要があります。おそらく、ABIの使用のためにいくつかのシンボル/文字/慣習を予約します。
しかし、今はより厳しいシナリオです。たとえば、Python開発者は、移動コンストラクター、コピーコンストラクター、およびデストラクターをどのように呼び出しますか?たぶん、それらをdylibの一部としてエクスポートできます。しかし、異なるモジュールでエクスポートされた場合はどうFoo
なりBar
ますか?このdylibに関連付けられているシンボルと実装を複製する必要がありますか?ここでオブジェクトを作成し、ここに渡し、そこにコピーして、ここでそれを破棄するために複数のdylibインターフェイスに絡まり始めなければならないのは、本当に速く非常に迷惑になるかもしれないので、そうすることをお勧めします。同じ基本的な懸念がCでも多少適用される可能性がありますが(より手動/明示的に)、Cは、人々がそれをプログラムする方法の性質上、これを避ける傾向があります。
これは、ぎこちなさのほんの小さなサンプルです。f
上記の関数の1つがBazException
(コンストラクターとデストラクターを持ち、std :: exceptionを派生するC ++クラスでもある)JavaScriptをスローするとどうなりますか?
せいぜい、あるC ++コンパイラーによって生成された1つのバイナリーから別のC ++コンパイラーによって生成された別のバイナリーまで動作するABIを標準化することしか期待できないと思います。それはもちろん素晴らしいことですが、私はこれを指摘したかっただけです。通常、クロスコンパイラで動作する汎用ライブラリを配布するためにこのような懸念を伴うことは、多くの場合、実際に汎用で互換性のあるクロス言語にすることです。
推奨される解決策
COMスタイルのインターフェースで長年API / ABIのC ++インターフェースを使用する方法を見つけるのに苦労した後、私が提案した解決策は、「C / C ++」(しゃれ)開発者になることです。
Cを使用してこれらのユニバーサルABIを作成し、実装にC ++を使用します。ヒープ上のそのようなオブジェクトを作成および破棄するための明示的な関数を使用して、不透明なC ++クラスへのポインターを返すエクスポート関数などを引き続き実行できます。実装に完全にC ++を使用している場合でも、ABIの観点からそのCの美学に恋をしてみてください。抽象インターフェイスは、関数ポインターのテーブルを使用してモデル化できます。このようなものをC APIにまとめるのは退屈ですが、それに付属するディストリビューションの利点と互換性は非常に価値がある傾向があります。
次に、このインターフェイスを直接使用するのがあまり好きではない場合(少なくともRAIIの理由でおそらくそうすべきではありません)、SDKに同梱されている静的にリンクされたC ++ライブラリで必要なすべてをラップできます。C ++クライアントはそれを使用できます。
Pythonクライアントは、これらのpythoniqueを作成する方法がないため、CまたはC ++インターフェイスを直接使用することを望みません。彼らはそれを独自のpythoniqueインターフェースにラップしたいので、実際にはそれをできるだけ簡単にするために最低限のC API / ABIをエクスポートするだけで良いのです。
多くのC ++業界は、COMスタイルのインターフェイスなどを頑固に出荷しようとするよりも、これを行う方が有益だと思います。また、これらのdylibのユーザーが厄介なABIに煩わされる必要がないため、すべての生活が楽になります。Cはそれを単純にし、ABIの観点から見ると単純であるため、あらゆる種類のFFIで自然に機能し、ミニマリズムで機能するAPI / ABIを作成できます。