C++17、C++14、C++11オブジェクトをリンクしても安全ですか?質問する

C++17、C++14、C++11オブジェクトをリンクしても安全ですか?質問する

3つのコンパイル済みオブジェクトがあるとします。これらはすべて同じコンパイラ/バージョン:

  1. AはC++11標準でコンパイルされました
  2. BはC++14標準でコンパイルされました
  3. C was compiled with the C++17 standard

For simplicity, let's assume all headers were written in C++11, using only constructs whose semantics haven't changed between all three standard versions, and so any interdependencies were correctly expressed with header inclusion and the compiler did not object.

Which combinations of these objects is it and isn't it safe to link into a single binary? Why?


EDIT: answers covering major compilers (e.g. gcc, clang, vs++) are welcome

ベストアンサー1

Which combinations of these objects is it and isn't it safe to link into a single binary? Why?

For GCC it is safe to link together any combination of objects A, B, and C. If they are all built with the same version then they are ABI compatible, the standard version (i.e. the -std option) doesn't make any difference.

Why? Because that's an important property of our implementation which we work hard to ensure.

Where you have problems is if you link together objects compiled with different versions of GCC and you have used unstable features from a new C++ standard before GCC's support for that standard is complete. For example, if you compile an object using GCC 4.9 and -std=c++11 and another object with GCC 5 and -std=c++11 you will have problems. The C++11 support was experimental in GCC 4.x, and so there were incompatible changes between the GCC 4.9 and 5 versions of C++11 features. Similarly, if you compile one object with GCC 7 and -std=c++17 and another object with GCC 8 and -std=c++17 you will have problems, because C++17 support in GCC 7 and 8 is still experimental and evolving.

On the other hand, any combination of the following objects will work (although see note below about libstdc++.so version):

  • object D compiled with GCC 4.9 and -std=c++03
  • object E compiled with GCC 5 and -std=c++11
  • object F compiled with GCC 7 and -std=c++17

This is because C++03 support is stable in all three compiler versions used, and so the C++03 components are compatible between all the objects. C++11 support is stable since GCC 5, but object D doesn't use any C++11 features, and objects E and F both use versions where C++11 support is stable. C++17 support is not stable in any of the used compiler versions, but only object F uses C++17 features and so there is no compatibility issue with the other two objects (the only features they share come from C++03 or C++11, and the versions used make those parts OK). If you later wanted to compile a fourth object, G, using GCC 8 and -std=c++17 then you would need to recompile F with the same version (or not link to F) because the C++17 symbols in F and G are incompatible.

上で説明した D、E、F 間の互換性に関する唯一の注意点は、プログラムがlibstdc++.soGCC 7 (またはそれ以降) の共有ライブラリを使用する必要があることです。オブジェクト F は GCC 7 でコンパイルされているため、そのリリースの共有ライブラリを使用する必要があります。これは、プログラムの一部を GCC 7 でコンパイルすると、libstdc++.soGCC 4.9 または GCC 5 には存在しないシンボルへの依存関係が導入される可能性があるためです。同様に、GCC 8 でビルドされたオブジェクト G にリンクした場合、G に必要なすべてのシンボルが確実に見つかるように、GCC 8 の を使用する必要がありますlibstdc++.so。簡単なルールは、プログラムが実行時に使用する共有ライブラリが、いずれかのオブジェクトのコンパイルに使用されたバージョンと少なくとも同じくらい新しいことを確認することです。

GCCを使用する際のもう1つの注意点は、あなたの質問のコメントですでに述べられているように、GCC 5以降では2つの実装std::stringlibstdc++ で利用できます。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 でも使用できます。C cxx11++11 の要件に準拠しているためにこの名前が付けられています)。どちらの実装がデフォルトになるかは、GCC の構成方法によって異なりますが、マクロを使用してコンパイル時にデフォルトを常に上書きできます。

おすすめ記事