2013-07-03 55 views
14

Mac上でlibC++とstdlibC++のABI矛盾を処理するにはどうすればよいでしょうか?libC++と古いlibstdC++のABIの違いを処理する良い方法は何ですか?

問題:多くのC++ 11機能には、C++標準ライブラリの新しいlibC++実装が必要です。しかし、libC++は古いlibstdC++とABI互換ではありませんが、現在のところ、ほとんどのソフトウェアは通常、後者とリンクしています。例えば、システムコンパイラはまだstdlibC++を使用しています。つまり、macportでインストールされたすべてのライブラリは、文字列のようなstdクラス用に異なるABIを持ち、C++ 11を大量に使用するプロジェクトとはリンクできません。

私の現在のハック・オブ・a解決策:2つのバージョンのライブラリを用意しておくと、一般に問題(boost、opencvなど)が発生し、適切なものにリンクされます。

もし私が本当にlibC++を使いたいのであれば、私はstdlibC++を使って自分のシステムをパージし、macports(または他の場所であれば)からlibC++とのリンクしかないことを確かめてください。あなたはこの仕事がいかに難しいかを見ることができます。

誰も私たちが住んでいるこの "stdlib-limbo"に関連する素晴らしい方法を試しましたか? :)

編集:Appleは、システムにlibC++とlibstdC++の両方を同梱しています。前提となる問題を攻撃し、libC++への切り替えを試みると仮定します。あなたのシステムに現在インストールされているライブラリ(システムに同梱されているもの、ほとんどはmacport経由で、一部は手作業でコンパイルされたもの)の100%がlibstdC++にリンクされているので、libstdC++からlibC++への切り替えの推奨方法は何ですか)?誰もこれをして生き残ったのですか?

+1

一緒にリンクされているすべてのコードが同じ標準ライブラリの実装とバージョンを使用する必要があります。他のすべては互換性がなく、決して働くつもりはありませんでした。 – PlasmaHH

+0

はい、もちろんあります。これはすべての問題です。同時に、2つの互換性のない標準的なライブラリ実装が同時に流通しています。私の質問は、この問題に対処するために人々が採用した戦略についてです。 – kamjagin

+1

それは戦略です。もっと多くの標準的なライブラリの実装があり、それらは相互に互換性がなく、永遠にそのままになります。 – PlasmaHH

答えて

12

標準ライブラリタイプを「隠して」使用することを禁止すると、いくつかのTU(またはライブラリやモジュール)がlibC++を使用し、いくつかはlibstdC++を使用する単一のプログラムでlibC++とlibstdC++を混在させることが完全に安全です。 TU間のインタフェースが互換性のない型を使用しない限り、問題はないはずです。

libC++は、ABIの互換性のない型同士を間違えないようにするために、インラインネームスペースを使用します。インタフェースがlibC++ std::stringを直接使用する場合、libstdC++を期待するライブラリstd::stringは、実際のシンボルが異なるため、インタフェースにリンクされません:std::stringstd::__1::string

libC++は、例外やダイナミックメモリ割り当てなどの低レベル機能がABI互換であることを保証します(同じabiライブラリを使用してlibstdC++とlibC++を構築することを前提としています)ので、libC++を使用するTUでメモリを解放することは安全ですメモリはlibstdC++を使用してTUに割り当てられました。また、libC++のコードビルドから例外をスローし、libstdC++を使用してコード内にキャッチしました。

インターフェイスの型が標準ライブラリ型を隠しているときに問題がある可能性があります。 struct S { std::string s; };を使用しているインタフェースでは、タイプSの定義は、TUがstd::stringと考えるものによって異なり、1つの定義ルールに違反します。あなたの本当の問題は、インタフェースで使用標準ライブラリの種類を行うライブラリであるかのように聞こえるしかし


私は1つが、私は本当に++私はstdlibC++を使用して何の私のシステムをパージし、MacPortsのから何か(またはどこか他の)のみのlibC++とリンクしていることを確認する必要がありますのlibcを利用したい場合はことを示唆しているかもしれないと思います。あなたはこの仕事がいかに難しいかを見ることができます。

インターフェイスで標準ライブラリを使用するTUにlibC++を使用する必要があります。 libstdC++を完全に削除する必要はありません。インタフェースで標準ライブラリを使用しないライブラリは、引き続きlibstdC++とリンクすることができます。

編集:Appleは、システムにlibC++とlibstdC++の両方を同梱しています。前提となる問題を攻撃し、libC++への切り替えを試みると仮定します。あなたのシステムに現在インストールされているライブラリ(システムに同梱されているもの、ほとんどはmacport経由で、一部は手作業でコンパイルされたもの)の100%がlibstdC++にリンクされているので、libstdC++からlibC++への切り替えの推奨方法は何ですか)?誰もこれをして生き残ったのですか?

インターフェイスで標準ライブラリを使用している場合にのみ重要です。これらのライブラリは、OS X用にビルドするときに、すでにlibC++に切り替えていることを期待しています。もしそうでなければ、おそらくパッチを受け入れるでしょう。

適切なライブラリを使用して独自のバイナリをビルドすることは、「ハック」ではありません。それはあなたのためにそれをやって上流のプロジェクトを欠席することは正しいことです。独自のコードでlibC++を一貫して使用する場合は、ライブラリの複数のバージョンをビルドする必要はありません。 libC++バージョンのみ。


のlibC++のABI互換性のための参照:http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-September/024594.html

+0

ありがとう - 私はlibstdC++からlibC++への切り替えに関する問題を過大評価しています。尊敬されるブースト(ファイルシステム)が犯人の一つであったことを考えると、私は、多くの確立されたライブラリもそのインタフェースで標準ライブラリを使用していると考えていました。 – kamjagin

+0

"うまくいけば、そのようなライブラリはOS XのためにビルドするときにすでにlibC++に切り替わっているはずです。もしそうでなければ、そうするためにパッチを受け入れるでしょう。 AppleがXcodeのC++標準ライブラリオプションのコンパイラのデフォルトをlibstdC++からlibC++に切り替える前にAppleがデフォルト以外のものに対して修正したデフォルトのstdlibと全く同じ問題を引き起こすのではないかと疑いがあります。 – Kaiserludi

+0

私はサードパーティのライブラリプロバイダのために2つのオプションしか表示していません: - libstdC++に対してビルドされたものと、libC++に対するものです。 - API内のすべてのstdlibの使用を取り除きます変更) – Kaiserludi

1

あなたはこれを気に入らないでしょう。

異なるシステムで定義が変更されるタイプを使用するABIを持つことはできません。これは、ABIがstd::string(たとえば)を使用し、異なるコンパイラまたは異なるプラットフォームを使用してコンパイルするときに実行している処理です。

これを修正するには、可能であれば、コンパイラ固有のすべてのものをABIから削除し、ネイティブタイプまたはライブラリで定義されているタイプに置き換えることが望ましいです。これらのライブラリ定義の型は、ABIのコンパイラ以外のものだけを公開する必要があります。

場合によっては、簡単な交換で手に入れることができます。あなたはより徹底的な措置を取る必要がある他の回。 1つのアプローチは、std::stringのようなものの周りに一種のブリッジやラッパークラスを用意することです。たぶん、このような何か:

class MyString 
{ 
public: 
    virtual const char* c_str() const = 0; 
    static MyString* Make(); 
    virtual MyString* Clone() const = 0; 
protected: 
    MyString(); 
}; 

、ライブラリ自体に:

class MyStringImpl 
: 
    public MyString 
{ 
public: 
    const char* c_str() const 
    { 
    return mStr.c_str(); 
    } 

    MyString* Clone() const 
    { 
    return new MyStringImpl (*this); 
    } 

    MyStringImpl() 
    { 
    } 

    MyStringImple (const MyString& rhs) 
    : 
    mStr (rhs.c_str()) 
    { 
    } 
private: 
    std::string mStr; 
}; 

MyString* MyString::Make() 
{ 
    return new MyStringImpl; 
} 

グロス。おそらく非効率的です。書き込むコードがたくさんあります。しかし、これは自分で描いたコーナーです。

+0

"コンパイラ固有のものをすべてABIから排除し、どちらかのネイティブタイプに置き換えることになります" intやlongのようなものでさえ、PODの実際のレイアウトだけでなくコンパイラによっても異なることに注意してください。 – PlasmaHH

+0

@PlasmaHH:フェアポイント。実際には、私は 'uint32_t'などの固定サイズの型を使います。 –

+0

* nix側から来ています。私は同じコンパイラABIを2004年(gccのそれ)と他のコンパイラintelとoracleは通常gnu-abiモードを提供します)、MSVCは毎年ABIを解散させ、開発者がCOM-heavenを探索するよう強制します。それでも、私はPODがメモリ内で線形にレイアウトされ、初期パディングがゼロであると考えました。 PODのABIと非互換性は、メンバー間のパディングの間に未定義であるのか、それとも緩やかに定義されている(または取り除かれている)いくつかの追加ポイントがありますか? – kamjagin

関連する問題