2


私は大きなプロジェクトで働いています。そして今、リンクエラーが発生します。
このエラーは回避策で回避できますが、なぜ機能するのか理解できません。

これが私の問題に関連するファイル構造です:

事業
  | -package_a
    | --a.cpp
    |--..。
  | -package_b
    | --b.cpp
    | --c.cpp
    |--..。
  | -package_others


package_aのすべての*.oはaaにパックされ、package_bの*.oはbaにパックされます。

"g++ -o exec -Bstatic b.a a.a ..."バイナリを生成するために使用されます。

package_b / b.cppに、関数foo()を追加しました。
そしてpackage_a/a.cppで、私はこの関数を使用しました。

しかし、ここでは、aoでのfoo()の未定義の参照を示すリンクエラーが発生します
。foo()がすでにboにあることを(objdumpによって)確認できます。

linkコマンドをに変更すること"g++ -o exec -Bstatic a.a b.a ..."で、バイナリを正常にビルドできます。リンカがリンケージリストの順序を気にすることを理解しました。ただし、これは大きなプロジェクトであり、プロジェクト構成を変更する権限がないため、元のリンク順序を維持する必要があることを理解してください。

次に、package_b / c.cppにダミー関数bar()を追加しました。これは、foo()を呼び出すだけで"g++ -o exec -Bstatic b.a a.a ..."、リンクエラーなしでoriginalが実行されます。

この場合、同じパッケージにダミー関数を追加するだけで機能する理由を誰かに教えてもらえますか?

g++4.4.4とlinux2.6.18-194.el5を使用しています

コメントをいただければ幸いです

4

4 に答える 4

4

これは正常です。リンクするとき、リンカはオブジェクトファイルのリストを調べ、未定義の参照を見つけます。これらの参照は、その後に続く他のオブジェクトファイル/ライブラリによって満たされます

この動作は次のいずれかで変更できます

  • のように、アーカイブの1つを2回含める

    g++ -o exec a.a b.a a.a
    
  • -(コンストラクトを使用する

    g++ -o exec -( a.a b.a -)
    

ただし、これは大きなプロジェクトであり、プロジェクト構成を変更する権限がないため、元のリンク順序を維持する必要があることを理解してください。

頑張ってください...たぶん、マネージャーや、bからの関数を使用したくない人は誰でもa

次に、package_b / c.cppにダミー関数bar()を追加しました。これは、foo()を呼び出すだけで、元の「g ++ -o exec -Bstatic baaa...」はリンクエラーなしで実行されます。

の別の関数package_b/c.cppがすでに参照されていて、リンカがbar()それを使用し(同じファイル内にあるため)、これが参照foo()され、後で出力にも含まれている可能性があります。も入っていたので成功foob.aました。

于 2011-11-07T12:15:43.203 に答える
3

リンカがどのように機能するかを読みたいと思うかもしれません。ところで、オブジェクトファイルアーカイブは静的にのみリンクする-Bstaticため、フラグは不要です.a.(に含まれるオブジェクトファイルのリストがで.aはなくコマンドラインで指定されたかのように.a)。

--start-groupまたは、 /オプションとリンクするアーカイブのリストをいつでもラップ--end-groupして、リンカーにアーカイブのリストを複数回スキャンさせることができます。これにより、アーカイブの順序付けが不要になります(MS VC ++のように)。

g++ -o exec -Wl,--start-group a.a b.a -Wl,--end-group

参照してくださいman ld

   -( archives -)
   --start-group archives --end-group
       The archives should be a list of archive files.  They may be either
       explicit file names, or -l options.

       The specified archives are searched repeatedly until no new
       undefined references are created.  Normally, an archive is searched
       only once in the order that it is specified on the command line.
       If a symbol in that archive is needed to resolve an undefined
       symbol referred to by an object in an archive that appears later on
       the command line, the linker would not be able to resolve that
       reference.  By grouping the archives, they all be searched
       repeatedly until all possible references are resolved.

       Using this option has a significant performance cost.  It is best
       to use it only when there are unavoidable circular references
       between two or more archives.
于 2011-11-07T12:13:59.243 に答える
2

GCCは、Visual-C ++リンカーとは異なり、参照が使用される前に参照が定義されるように、静的ライブラリを順番に指定する必要があります。理由は聞かないでください。ただし、GCCと正しい順序でリンクするファイルをリストしていることを常に確認する必要があります。

ここに詳細な説明があります。

于 2011-11-07T12:12:19.877 に答える
0

静的ライブラリの関数を使用する場合は、コマンドラインで最初に関数の使用元のファイルを配置し、次に関数が定義されているライブラリを配置する必要があります。それ以外の場合、定義を最初に配置すると、gcc(より具体的にはld)は「未使用」関数を破棄します。それがgccの仕組みです。ごめんなさい。

于 2011-11-07T12:17:12.420 に答える