[解決済み] C++17、C++14、C++11のオブジェクトをリンクしても安全か?
質問
3つのコンパイルされたオブジェクトがあるとします。 同じコンパイラ/バージョン :
- A は C++11 標準でコンパイルされています。
- B は C++14 標準でコンパイルされています。
- C は C++17 標準でコンパイルされています。
簡単のために、すべてのヘッダーが C++11 で書かれていたと仮定しましょう。 3 つの標準バージョン間でセマンティクスが変更されていない構造体のみを使用する場合
そのため、相互依存性はヘッダー インクルードで正しく表現され、コンパイラーは異議を唱えませんでした。これらのオブジェクトのどの組み合わせが、単一のバイナリにリンクしても安全なのでしょうか、また安全ではないのでしょうか。なぜでしょうか。
EDIT: 主要なコンパイラ (例: gcc, clang, vs++) をカバーする回答が歓迎されます。
どのように解決するのですか?
これらのオブジェクトのどの組み合わせが、単一のバイナリにリンクしても安全なのでしょうか?なぜですか?
GCCのため
は、オブジェクトA, B, Cのどんな組み合わせでもリンクすることが安全です。もし、それらがすべて同じバージョンでビルドされているなら、それらはABI互換で、標準バージョン(すなわち
-std
オプション) は何の違いもありません。
なぜでしょうか?なぜなら、これは私たちの実装の重要な特性であり、私たちはそれを確実にするために懸命に働いているからです。
問題があるのは、異なるバージョンのGCCでコンパイルされたオブジェクトを一緒にリンクする場合です。
と
でコンパイルされたオブジェクトをリンクした場合、新しいC++標準の不安定な機能を、その標準に対するGCCのサポートが完全でないうちに使ってしまった場合です。たとえば、GCC 4.9を使ってオブジェクトをコンパイルし
-std=c++11
を使ってコンパイルし、別のオブジェクトをGCC 5と
-std=c++11
を使用すると問題が発生します。C++11のサポートはGCC 4.xでは実験的でしたから、C++11の機能のGCC 4.9と5のバージョンの間で互換性のない変更があったのです。同様に、もし、あるオブジェクトをGCC 7でコンパイルし
-std=c++17
でコンパイルし、別のオブジェクトをGCC 8と
-std=c++17
というのは、GCC 7 と 8 の C++17 サポートはまだ実験的で発展途上のものだからです。
一方、以下のオブジェクトのどのような組み合わせでも動作します。
libstdc++.so
のバージョンについては後述します)。
-
オブジェクト D は GCC 4.9 でコンパイルされ
-std=c++03
-
オブジェクト E は GCC 5 でコンパイルされ
-std=c++11
-
オブジェクト F は GCC 7 でコンパイルされ
-std=c++17
これは、使用した 3 つのコンパイラー バージョンのすべてで C++03 サポートが安定しているため、すべてのオブジェクト間で C++03 コンポーネントに互換性があるためです。C++11 のサポートは GCC 5 以降安定していますが、オブジェクト D は C++11 の機能を使用しておらず、オブジェクト E と F はどちらも C++11 のサポートが安定しているバージョンを使用しています。C++17のサポートはどのコンパイラのバージョンでも安定していませんが、オブジェクトFだけがC++17の機能を使っているので、他の2つのオブジェクトとの互換性に問題はありません(唯一共有している機能はC++03またはC++11から来ており、使われているバージョンでそれらの部分は問題ありません)。後で4番目のオブジェクトGをGCC 8を使ってコンパイルし
-std=c++17
を使用して 4 番目のオブジェクトである G をコンパイルしたい場合、F と G の C++17 シンボルは互換性がないため、同じバージョンで F を再コンパイルする必要があります (または F へのリンクを行わない)。
上記の D、E、F 間の互換性についての唯一の注意点は、プログラムでは
libstdc++.so
の共有ライブラリを使用しなければならないということです。オブジェクトFはGCC 7でコンパイルされたので、そのリリースの共有ライブラリを使う必要があります。なぜなら、プログラムのどの部分もGCC 7でコンパイルすると
libstdc++.so
には存在しないシンボルに依存する可能性があるからです。同様に、もし、GCC 8でビルドされたオブジェクトGにリンクした場合、GCC 8の
libstdc++.so
を使い、Gが必要とするすべてのシンボルが見つかることを確実にする必要があります。単純なルールは、プログラムが実行時に使用する共有ライブラリが、少なくともオブジェクトのいずれかをコンパイルするために使用されるバージョンと同じくらい新しいことを保証することです。
GCC を使用する際のもうひとつの注意点は、あなたの質問に対するコメントですでに言及されていますが、GCC 5 以降は
の2つの実装があります。
std::string
の二つの実装が libstdc++ で利用可能です。この 2 つの実装はリンク互換ではありませんが(マングル名が異なるので一緒にリンクできません)、同じバイナリに共存できます(マングル名が異なるので、あるオブジェクトで
std::string
を使い、もう一方が
std::__cxx11::string
). もしあなたのオブジェクトが
std::string
を使用している場合、通常、それらはすべて同じ文字列の実装でコンパイルされるべきです。コンパイル時に
-D_GLIBCXX_USE_CXX11_ABI=0
を選択すると、オリジナルの
gcc4-compatible
の実装、あるいは
-D_GLIBCXX_USE_CXX11_ABI=1
を選択すると、新しい
cxx11
の実装(名前に惑わされないでください、C++03 でも使用できます。
cxx11
と呼ばれるのは、それがC++11の要件に適合しているからです)。どの実装がデフォルトかは GCC がどのように設定されたかによりますが、デフォルトは常にマクロでコンパイル時に上書きすることが可能です。
関連
-
[解決済み】致命的なエラー LNK1169: ゲームプログラミングで1つ以上の多重定義されたシンボルが発見された
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー
-
[解決済み] 1ビットのセット、クリア、トグルはどのように行うのですか?
-
[解決済み] static_cast, dynamic_cast, const_cast, reinterpret_cast はいつ使うべきですか?
-
[解決済み] C++11では、標準化されたメモリモデルが導入されました。その意味するところは?そして、C++プログラミングにどのような影響を与えるのでしょうか?
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] C++の規格では、初期化されていないboolがプログラムをクラッシュさせることは可能ですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] テスト
-
[解決済み】Visual Studio 2015で「非標準の構文。'&'を使用してメンバーへのポインターを作成します」エラー
-
[解決済み】クラステンプレートの引数リストがない
-
[解決済み】Cygwin Make bash コマンドが見つかりません。
-
[解決済み】関数名の前に期待されるイニシャライザー
-
[解決済み】'cout'は型名ではない
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】クラスのコンストラクタへの未定義参照、.cppファイルの修正も含む
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】Enterキーを押して続行する