回答:
(この回答の履歴を参照して、より複雑なテキストを入手してください。しかし、読者が実際のコマンドラインを見る方が簡単だと思います)。
以下のすべてのコマンドで共有される共通ファイル
$ cat a.cpp
extern int a;
int main() {
return a;
}
$ cat b.cpp
extern int b;
int a = b;
$ cat d.cpp
int b;
$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o
$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order
リンカは左から右に検索し、未解決のシンボルを見つけます。ライブラリがシンボルを解決する場合、そのライブラリのオブジェクトファイルを使用してシンボルを解決します(この場合はどちらもlibb.aから)。
静的ライブラリの相互依存関係は同じように機能します-シンボルを必要とするライブラリが最初になければならず、次にシンボルを解決するライブラリが必要です。
静的ライブラリが別のライブラリに依存しているが、他のライブラリも以前のライブラリに依存している場合、サイクルがあります。次の方法で周期的に依存ライブラリを囲むことにより、この問題を解決することができます-(
し、-)
のような、-( -la -lb -)
(次のような括弧、エスケープする必要があるかもしれない-\(
とし-\)
)。次に、リンカーはそれらの囲まれたlibを複数回検索して、循環依存関係が解決されるようにします。または、ライブラリを複数回指定して、それぞれを1つずつ優先させることもできます-la -lb -la
。
$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!
$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order
ここでも同じです-ライブラリはプログラムのオブジェクトファイルに従う必要があります。静的ライブラリとの違いは、動的ライブラリは依存関係を自分で整理するため、ライブラリ同士の依存関係を気にする必要がないことです。
最近の一部のディストリビューション--as-needed
では、プログラムのオブジェクトファイルが動的ライブラリの前に来るように強制するリンカーフラグをデフォルトで使用しているようです。そのフラグが渡された場合、リンカーは、実行可能ファイルが実際に必要としないライブラリーにリンクしません(これは左から右に検出されます)。私の最近のarchlinuxディストリビューションはデフォルトでこのフラグを使用しないため、正しい順序に従わないことによるエラーは発生しませんでした。
前者を作成するときにb.so
に対する依存関係を省略することは正しくありませんd.so
。あなたは、リンク時にライブラリを指定する必要がありますa
、その後、しかし、a
実際には整数必要はありませんb
、それは気になされるべきではないので、自分自身をb
自身の依存関係。
以下は、依存関係の指定を怠った場合の影響の例です libb.so
$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)
$ g++ -L. -lb a.cpp # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above
$ g++ a.cpp -L. -lb # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right"
あなたは今のバイナリが持つ依存には何があるかを調べる場合は、バイナリ自体が上にも依存することに注意してくださいlibd
だけでなく、libb
それが必要として。このようにすると、libb
後で別のライブラリに依存する場合、バイナリを再リンクする必要があります。実行時に他の誰かがをlibb
使用dlopen
してロードする場合(プラグインを動的にロードすることを考えると)、呼び出しも失敗します。ですから、"right"
本当のはずwrong
です。
lorder
+ tsort
ください。しかし、循環参照がある場合は、順序がないことがあります。次に、すべてが解決されるまで、ライブラリリストを循環させるだけです。
GNU ldリンカーは、いわゆるスマートリンカーです。前の静的ライブラリで使用されている関数を追跡し、ルックアップテーブルから使用されていない関数を永久に破棄します。その結果、スタティックライブラリをリンクするのが早すぎると、そのライブラリの関数は、リンク行の後でスタティックライブラリで使用できなくなります。
典型的なUNIXリンカーは左から右に機能するため、依存関係にあるすべてのライブラリを左側に配置し、依存関係を満たすライブラリをリンク行の右側に配置します。一部のライブラリは他のライブラリに依存していると同時に、他のライブラリはそれらに依存している場合があります。ここが複雑になります。循環参照に関しては、コードを修正してください!
静的ライブラリが関係する場合にGCCでどのように機能するかを明確にする例を次に示します。それでは、次のシナリオがあるとします。
myprog.o
- main()
依存関数libmysqlclient
libmysqlclient
-静的、例のために(もちろん、それlibmysqlclient
は巨大なので、共有ライブラリを好むでしょう); で/usr/local/lib
; からのものに依存libz
libz
(動的)これをどのようにリンクしますか?(注:gcc 4.3.4を使用してCygwinでコンパイルした例)
gcc -L/usr/local/lib -lmysqlclient myprog.o
# undefined reference to `_mysql_init'
# myprog depends on libmysqlclient
# so myprog has to come earlier on the command line
gcc myprog.o -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# we have to link with libz, too
gcc myprog.o -lz -L/usr/local/lib -lmysqlclient
# undefined reference to `_uncompress'
# libz is needed by libmysqlclient
# so it has to appear *after* it on the command line
gcc myprog.o -L/usr/local/lib -lmysqlclient -lz
# this works
-Xlinkerオプションを使用できます。
g++ -o foobar -Xlinker -start-group -Xlinker libA.a -Xlinker libB.a -Xlinker libC.a -Xlinker -end-group
ALMOSTは等しい
g++ -o foobar -Xlinker -start-group -Xlinker libC.a -Xlinker libB.a -Xlinker libA.a -Xlinker -end-group
気をつけて!
リンクの順序は確かに、少なくとも一部のプラットフォームでは重要です。ライブラリと間違った順序でリンクされたアプリケーションのクラッシュを確認しました(誤った場合、AはBの前にリンクされますが、BはAに依存します)。
私はこれをたくさん見ました、私たちのモジュールのいくつかは私たちのコードの100のライブラリに加えてシステムとサードパーティのライブラリをリンクしています。
さまざまなリンカーHP / Intel / GCC / SUN / SGI / IBM / etcに応じて、未解決の関数/変数などを取得できます。一部のプラットフォームでは、ライブラリを2回リストする必要があります。
ほとんどの場合、ライブラリ、コア、プラットフォーム、抽象化のさまざまな層の構造化された階層を使用しますが、一部のシステムでは、リンクコマンドの順序をいじる必要があります。
ソリューションのドキュメントを見つけたら、次の開発者が再度解決する必要はありません。
私の昔の講師は、「凝集度が高くカップリングが低い」と言っていましたが、今日でもそうです。
gcc
は(比較的)最近、より厳密な動作に変更されました。