静的ライブラリに分割されたコードベースがあります。残念ながら、ライブラリには循環依存関係があります。例:libfoo.a
はlibbar.a
に依存し、その逆も同様です。
これを処理する「正しい」方法は、次のように、リンカーの--start-group
および--end-group
オプションを使用することです。
g++ -o myApp -Wl,--start-group -lfoo -lbar -Wl,--end-group
しかし、既存のMakefileでは、問題は通常次のように処理されます。
g++ -o myApp -lfoo -lbar -lfoo
(これが複雑な相互依存関係を持つ最大20のライブラリに拡張されたと想像してください。)
私は2番目のフォームを最初のフォームに変更するMakefileを調べてきましたが、今では同僚から理由が尋ねられています...そして、「よりクリーンであるため」と、他のフォームは危険であるという漠然とした感覚以外は、私はしません。良い答えがあります。
それで、同じライブラリを複数回リンクすることはできますかever問題を引き起こす可能性がありますか?たとえば、同じ.oが2回引き込まれた場合、複数定義されたシンボルでリンクが失敗する可能性がありますか?または、同じ静的オブジェクトの2つのコピーが作成され、微妙なバグが発生するリスクはありますか?
基本的に、同じライブラリを複数回リンクすることによってリンク時または実行時エラーが発生する可能性があるかどうかを知りたいです。もしそうなら、それらをトリガーする方法。ありがとう。
私が提供できるのは反例の欠如だけです。私は実際にはこれまでに最初のフォームを見たことがなく(明らかに優れているにもかかわらず)、これが2番目のフォームで解決されるのを常に見ており、結果として問題を確認していません。
それでも、最初の形式に変更することをお勧めします。これは、特定の方法で動作するリンカーに依存するのではなく、ライブラリ間の関係を明確に示すためです。
そうは言っても、少なくとも、コードをリファクタリングして、共通の部分を追加のライブラリに引き出す可能性があるかどうかを検討することをお勧めします。
の問題
g++ -o myApp -lfoo -lbar -lfoo
libfoo
の2回のパスとlibbar
の1回のパスで十分であるという保証はありません。
Wl,--start-group ... -Wl,--end-group
を使用したアプローチは、より堅牢であるため、より優れています。
次のシナリオを検討してください(すべてのシンボルは異なるオブジェクトファイルにあります)。
myApp
には、fooA
で定義されたシンボルlibfoo
が必要です。fooA
には、barB
で定義されたシンボルlibbar
が必要です。barB
には、fooC
で定義されたシンボルlibfoo
が必要です。これは循環依存関係であり、-lfoo -lbar -lfoo
で処理できます。fooC
には、barD
で定義されたシンボルlibbar
が必要です。上記のケースでビルドできるようにするには、-lfoo -lbar -lfoo -lbar
をリンカーに渡す必要があります。どうして?
libfoo
を初めて認識し、シンボルfooA
ではなくfooC
の定義を使用します。これまでのところ、fooC
バイナリに。ただし、リンカはbarB
が機能するために必要なので、fooA
の定義を探し始めます。-libbar
を認識し、barB
の定義を含み(ただしnotbarD
)、fooC
の定義の検索を開始します。fooC
の定義は、2回目の処理時にlibfoo
にあります。ここで、barD
の定義も必要であることが明らかになりましたが、遅すぎると、コマンドラインにlibbar
がなくなりました。上記の例は、任意の依存関係の深さに拡張できます(ただし、これは実際にはめったに起こりません)。
したがって、
g++ -o myApp -Wl,--start-group -lfoo -lbar -Wl,--end-group
リンカは必要な頻度でライブラリグループを通過するため、より堅牢なアプローチです。パスによってシンボルテーブルが変更されなかった場合にのみ、リンカはコマンドラインの次のライブラリに移動します。
ただし、パフォーマンスにわずかなペナルティがあります。最初の例では、手動コマンドライン-lbar
と比較して-lfoo -lbar -lfoo
がもう一度スキャンされました。言及/検討する価値があるかどうかわからない。
これはレガシーアプリケーションであるため、ライブラリの構造は、もう使用しない別の製品を構築するために使用されるなど、おそらくもう問題にならない配置から継承されているに違いありません。
継承されたライブラリー構造の構造上の理由が残っている場合でも、ほぼ確実に、レガシー構成からもう1つのライブラリーを作成することは許容されます。 20個のライブラリのすべてのモジュールを新しいライブラリliballofthem.a
に入れるだけです。そうすれば、すべてのアプリケーションは単純にg++ -o myApp -lallofthem ...
になります。