17

Mac で libc++ と stdlibc++ の間の ABI の不一致を処理する良い方法は (もしあれば)?

問題: 多くの c++11 機能には、C++ 標準ライブラリの新しい libc++ 実装が必要です。しかし、libc++ は古い libstdc++ と ABI 互換ではありませんが、現在、ほとんどのソフトウェアは通常、後者に対してリンクしています。たとえば、システム コンパイラはまだ stdlibc++ を使用しています。これは、macports と共にインストールされたすべてのライブラリが、string などの std クラスに対して異なる ABI を持ち、c++11 を多用するプロジェクトとはリンクできないことを意味します。

私の現在の解決策のハック: 2 つのバージョンのライブラリを保持し、これが一般的に問題 (boost、opencv など) を引き起こし、適切なものにリンクします。

本当に libc++ を使用したい場合は、stdlibc++ を使用してシステムからすべてを削除し、macports (または他の場所) からのものはすべて libc++ とのみリンクするようにすることをお勧めします。この作業がいかに困難であるかがわかります。

私たちが住んでいるこの「stdlib-limboの間」に関連する良い方法を考え出した人はいますか? :)

編集:暗黙のフォローアップの質問をより明確にしています: Apple は libc++ と libstdc++ の両方をシステムに同梱しています。根本的な問題を攻撃し、libc++ のみに切り替えようとするとします。システムに現在インストールされているライブラリの 100% (システムに同梱されているライブラリ、ほとんどが macports 経由、いくつかは手動コンパイル経由) が libstdc++ にリンクされている場合 (存在する場合)、libstdc++ から libc++ に切り替える推奨される方法は何ですか? )? これを実行して生き残った人はいますか?

4

2 に答える 2

13

標準ライブラリ型の「隠れた」使用を除けば、libc++ と libstdc++ を 1 つのプログラムに混在させることは完全に安全です。TU (またはライブラリ、またはモジュール) によっては libc++ が使用され、一部は libstdc++ が使用されます。TU 間のインターフェイスが互換性のない型を使用しない限り、問題は発生しません。

libc++ はインライン名前空間を使用して、ABI の非互換型を互いに間違えないようにします。インターフェイスが libc++ を直接使用する場合、実際のシンボルが異なるため、std::stringlibstdc++ を期待するライブラリはインターフェイスにリンクされません。std::stringstd::stringstd::__1::string

また、libc++ は、例外や動的メモリ割り当てなどの低レベル機能が ABI と互換性があることを保証します (同じ abi ライブラリを使用して libstdc++ と libc++ をビルドすると仮定します)。したがって、メモリが割り当てられたときに libc++ を使用する TU でメモリの割り当てを解除しても安全です。 libstdc++ を使用して TU で、または libc++ でビルドされたコードから例外をスローし、libstdc++ を使用してコードでそれをキャッチします。

インターフェイスの型が標準ライブラリの型を隠している場合、問題が発生する可能性があります。struct S { std::string s; };タイプの定義を使用するインターフェイスはS、TU が何を考えているかによって異なるstd::stringため、1 つの定義ルールに違反します。


ただし、実際の問題は、インターフェイスで標準ライブラリ型を使用するライブラリにあるようです。

本当に libc++ を使用したい場合は、stdlibc++ を使用してシステムからすべてを削除し、macports (またはその他の場所) からのものはすべて libc++ とのみリンクするようにすることをお勧めします。この作業がいかに困難であるかがわかります。

インターフェイスで標準ライブラリを使用する TU が libc++ を使用していることを確認するだけで済みます。libstdc++ を完全にパージする必要はありません。インターフェイスで標準ライブラリを使用しないライブラリは、引き続き libstdc++ とリンクできます。

編集:暗黙のフォローアップの質問をより明確にしています: Apple は libc++ と libstdc++ の両方をシステムに同梱しています。根本的な問題を攻撃し、libc++ のみに切り替えようとするとします。システムに現在インストールされているライブラリの 100% (システムに同梱されているライブラリ、ほとんどが macports 経由、いくつかは手動コンパイル経由) が libstdc++ にリンクされている場合 (存在する場合)、libstdc++ から libc++ に切り替える推奨される方法は何ですか? )? これを実行して生き残った人はいますか?

標準ライブラリがインターフェイスで使用されている場合にのみ問題になることを覚えておいてください。そのようなライブラリが、OS X 用にビルドするときに、すでに独自に libc++ に切り替えていることを願っています。そうでない場合は、そうするためのパッチを受け入れる可能性があります。

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


libc++ の abi 互換性に関するリファレンス: http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-September/024594.html

于 2013-07-03T17:34:40.210 に答える
1

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

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

これを修正する際に、私の推奨するアプローチ (可能であれば) は、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;
}

きもい。おそらく非効率的です。書くコードが多い。しかし、これはあなたが描いたコーナーです。

于 2013-07-03T14:45:19.853 に答える