1. ホーム
  2. c++

[解決済み] libstdc++ を静的にリンクする: 何かゴチャゴチャは?

2022-12-25 04:21:26

質問

Ubuntu 12.10 で GCC 4.7 の libstdc++ を使用して構築された C++ アプリケーションを、かなり古いバージョンの libstdc++ が付属する Ubuntu 10.04 を実行しているシステムにデプロイする必要があります。

現在、私は -static-libstdc++ -static-libgcc でコンパイルしていますが、このブログの記事で提案されているように libstdc++ を静的にリンクする . 作者は、libstdc++を静的にコンパイルするときに、動的にロードされたC++のコードを使用しないように警告しています。それでも、今のところ、すべてが順調に進んでいるようです。Ubuntu 10.04 で C++11 の機能を利用することができ、これは私が求めていたものです。

私は、この記事が 2005 年のものであり、おそらくその後に多くの変更があったことに注目しています。そのアドバイスはまだ最新ですか? 私が注意すべき潜んでいる問題はありますか?

どのように解決するのですか?

そのブログ記事はかなり不正確です。

私が知る限り、C++ ABI の変更は GCC のすべてのメジャー リリースで導入されています (すなわち、異なる第 1 または第 2 バージョン番号のコンポーネントを持つもの)。

そうではありません。GCC 3.4 以降に導入された唯一の C++ ABI の変更は後方互換性があり、C++ ABI はほぼ 9 年間安定していたことを意味します。

さらに悪いことに、ほとんどの主要な Linux ディストリビューションは GCC スナップショットおよび/または GCC バージョンにパッチを適用しており、バイナリを配布する際にどの GCC バージョンを扱っているか正確に知ることが事実上不可能になっています。

たとえば、Fedora の 4.6.3 20120306 (Red Hat 4.6.3-2) は、上流の FSF 4.6.x リリースと ABI 互換で、他のどのディストロの 4.6.x でもほぼ確実に互換性があります。

GNU/Linux では、GCC のランタイムライブラリは ELF シンボルバージョニングを使用しているので、オブジェクトやライブラリに必要なシンボルのバージョンを確認するのは簡単で、もし、あなたが libstdc++.so があれば、それがあなたのディストロの別のバージョンからわずかに異なるパッチが適用されたバージョンであっても問題なく動作します。

が、これが動作するためには、C++ コード (または C++ ランタイム サポートを使用するコード) は動的にリンクしてはいけません。

これも真実ではありません。

とはいえ、静的にリンクすることで libstdc++.a への静的なリンクは、あなたにとって1つの選択肢です。

ライブラリを動的にロードする場合、うまくいかないことがあるのは、( dlopen を使用して) 動的にロードした場合に動作しない理由は、依存する libstdc++ シンボルが、(静的に) リンクした時にはアプリケーションで必要とされていなかったかもしれないからです。 これは共有ライブラリを動的にリンクすることで解決できます。 libstdc++.so (ELFシンボルインター フェースとは、実行ファイルに存在するシンボルは共有ライブラリによって使用され、 実行ファイルに存在しないシンボルは、どの libstdc++.so にリンクされます。 もしあなたのアプリケーションが dlopen を使わないアプリケーションでは、気にする必要はありません。

もう一つの選択肢 (そして私が好むもの) は、より新しい libstdc++.so をアプリケーションと一緒に展開し、それがデフォルトのシステムの libstdc++.so の前に見つかるようにします。これは、ダイナミックリンカーが正しい場所を探すように $LD_LIBRARY_PATH 環境変数を使うか、あるいは RPATH を設定する。 私はどちらかというと RPATH を使うことを好みます。これは、アプリケーションが動作するために環境が正しく設定されていることに依存しないためです。 もしアプリケーションをリンクするときに '-Wl,-rpath,$ORIGIN' でリンクすると (シングルクォートで囲むのは、シェルが $ORIGIN を展開しようとするのを防ぐためです)、実行ファイルには RPATH$ORIGIN で、ダイナミックリンカーに実行ファイル自身と同じディレクトリにある共有ライブラリを探すように指示します。もし、より新しい libstdc++.so を実行ファイルと同じディレクトリに置くと、実行時にそれが見つかり、問題は解決します。 (別の方法として、実行ファイルを /some/path/bin/ に、より新しい libstdc++.so を /some/path/lib/ でリンクし '-Wl,-rpath,$ORIGIN/../lib' など、実行ファイルからの相対的な位置を固定し、RPATHを $ORIGIN )