c++ - 解決法 - undefined reference リンク エラー




ライブラリがリンクされている順序がGCCでエラーを起こすことがあるのはなぜですか? (7)

-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 

慎重に!

  1. グループ内の順序は重要です! 次に例を示します。デバッグライブラリにはデバッグルーチンがありますが、非デバッグライブラリには弱いバージョンがあります。 デバッグライブラリFIRSTをグループに入れる必要があります。そうしないと、非デバッグバージョンに解決されます。
  2. グループリストの各ライブラリの前に-Xlinkerを付ける必要があります

ライブラリがリンクされている順序がGCCでエラーを起こすことがあるのはなぜですか?


GNU ldリンカーは、いわゆるスマートリンカーです。 先行する静的ライブラリが使用する関数を追跡し、ルックアップテーブルから使用されていない関数を恒久的に投げ捨てます。 その結果、静的ライブラリをあまりにも早くリンクすると、そのライブラリ内の関数は、後でリンク線上の静的ライブラリで使用できなくなります。

典型的なUNIXリンカは左から右に動作するので、すべての依存ライブラリを左側に、リンク線の右側にそれらの依存関係を満たすものを置きます。 あるライブラリは他のライブラリに依存していると同時に、他のライブラリはそれらに依存していることがあります。 これが複雑になるところです。 循環参照に関しては、コードを修正してください!


静的ライブラリが関わっているときにGCCでどのように動作するかを明確にするための例です。 だから我々は次のシナリオを持っていると仮定しよう:

  • myprog.o - myprog.oに依存するmain()関数を含む
  • 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

(より精巧なテキストを得るためにこの答えの歴史を見てくださいが、私は今、読者が実際のコマンドラインを見るのがより簡単だと思います)。

以下のすべてのコマンドで共有される共通ファイル

$ 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を複数回検索して、サイクリングの依存関係を解決します。 別の方法として、ライブラリを複数回指定することもできます。それぞれが前になるようにします。 -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だけでなく、 libdにも依存することに注意してください。 libb後で別のライブラリに依存する場合、バイナリは再リンクする必要があります。 また、他の人が実行時にdlopenを使ってlibbをロードすると(プラグインを動的に読み込むことを考えると)、呼び出しも失敗します。 したがって、 "right"本当にwrongているはずです。


もう1つの選択肢は、ライブラリのリストを2回指定することです。

gcc prog.o libA.a libB.a libA.a libB.a -o prog.x

これを行うと、リファレンスが2番目のブロックで解決されるため、正しいシーケンスを気にする必要はありません。


少なくともいくつかのプラットフォームでは、リンクの順序は重要です。 私は間違った順序でライブラリーにリンクされたアプリケーションのクラッシュを見ました(間違っているのはAの前にリンクされていますが、BはAに依存しています)。


速いヒントが私を引きつけました:あなたが "gcc"または "g ++"としてリンカを起動している場合、 "--start-group"と "--end-group"を使用すると、それらのオプションはリンカー - エラーにもフラグを立てません。 ライブラリの順序が間違っていると、未定義のシンボルとのリンクに失敗します。

GCCに引数をリンカに渡すように指示するには、それらを "-Wl、 - start-group"などと書く必要があります。





linker