最終更新:2026-10-12
C++ string ABI 互換性¶
プロジェクト実戦の問題:C++ String ABI 互換性問題を避ける¶
多くの人がC++ stringを好まず、自分で車輪を再発明するのはなぜでしょうか?その問題のひとつがC++ stringのabi問題です。あなたは遭遇したことがありますか?
以前、conanとクロスプラットフォームライブラリを使っていたときにC++ stringのabi互換問題が発生しました。本節ではABIの背景とコンパイラに関連する内容を取り上げ、この穴の避け方について話します。経験があれば、ぜひコメントを~
1. ABI 変更の背景¶
**GCC 5.1**以降はC++11サポートが強化され、いくつかの新機能が導入されました。このバージョンで、libstdc++は新しいライブラリABIを導入し、std::stringとstd::listの実装を更新しました。これらの変更はC++11標準に準拠するものです。C++11標準はCopy-On-Write文字列を禁止し、リンクリストが自身のサイズを追跡することを要求しています。
実際のプロジェクトでConanを使う場合、開発者は compiler.libcxx を調整することで使用するABIを選択できます:
- libstdc++:旧ABIを使用。
- libstdc++11:新ABIを使用。
適切なABIを選択することで、特に異なるバージョンのコンパイラやライブラリを使う場合に、他の依存ライブラリとの互換性を確保できます。
2. コンパイラのデフォルト設定¶
GCCを使ってコンパイルする際、--with-default-libstdcxx-abi=gcc4-compatible を明示的に指定しなければ、GCCはデフォルトで新しいC++11 ABIを使用します。これは次を意味します:
- あなたのコードや依存ライブラリが旧ABIでコンパイルされている場合、リンクしようとしたときに未定義シンボルのエラーに遭遇する可能性があります。
例えば、以下のコードをコンパイルするとき:
次のコマンドを使うと:
シンボル __Z3fooRKSs が生成されます。これは旧ABIの形式です。
しかし、新ABIを使う別のファイルをコンパイルしてリンクすると、次のようなエラーが出る可能性があります:
Undefined symbols for architecture x86_64:
"foo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)", referenced from:
_main in ccbWGoYh.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
3. 解決策¶
コンパイルを確実に通すために、2つの解決策があります:
方法 1: ABIを手動で指定
すべてのソースファイルをコンパイルするとき、手動で -D_GLIBCXX_USE_CXX11_ABI=0 を追加して古いライブラリと互換性を保ちます。例えば:
方法 2: すべてのファイルを新しいABIでコンパイル
新しいC++11 ABIを使ってよいなら、ライブラリファイルをコンパイルするときに -D_GLIBCXX_USE_CXX11_ABI=1 を使えば、両者のシンボルが一致します:
このとき、リンク時にシンボルが一致し、未定義シンボルのエラーはもう発生しません。
4. シンボルの比較¶
nm コマンドで異なるABI下のシンボルを確認すると、両者の違いが直観的にわかります:
g++-14 -D_GLIBCXX_USE_CXX11_ABI=0 -c lib.cc
nm lib.o | grep foo
# 输出: 0000000000000000 T __Z3fooRKSs
g++-14 -D_GLIBCXX_USE_CXX11_ABI=1 -c lib.cc
nm lib.o | grep foo
# 输出: 0000000000000000 T __Z3fooRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
5. まとめ¶
ABIはC++のアップグレードおよびコンパイルの過程で遭遇する非常に大きな穴です。この記事でこれらの内容を明確に説明できていれば幸いです。
関連トピック¶
- C++ 純粋仮想関数と抽象クラス | C++那些事
- C++ assert アサーション | C++那些事
- C++ ビットフィールド | C++那些事
- C 言語による C++ 多態の実現 | C++那些事
- C++ const 定数と修飾 | C++那些事
- C++ const ファミリー | C++那些事
- C++ 間接参照演算子 * | C++那些事
- C++ 初期化と代入 | C++那些事
- C++ 複数戻り値の書き方 | C++那些事
- C++ mutable キーワード | C++那些事