web-dev-qa-db-ja.com

リンカー重複シンボルエラーの原因を理解する

以前にコンパイルしたc ++プログラムがありますが、Jamfilesをいじった後、プログラムはコンパイルされなくなり、ldduplicate symbol errorを発行しました。これは、元のJamfileに連続して戻り、bjam cleanを実行し、オブジェクトを手動で削除し、MacO10.6.7でgccフロントエンドのclangからgcc4.2.1に切り替えた後も持続しました。

プログラムの簡単な説明は、main.cppと4つのファイルa.h,cppb.h,cppがあり、これらはmain.oにリンクされている静的ライブラリにコンパイルされていることです。 main.cppb.cppはどちらも、2つの異なる中間ファイルを介して、問題のシンボルoff.hを含むファイルに依存しますが、a.ha.cppもいずれにも依存しません。 off.hへの道。

質問する前に、すべてのファイルが複数の定義ガード(#ifndef#define#endif)でラップされていることを確認しました。それらが欠落しているファイルを見つけましたが、 off.hを参照しないでください。さらに重要なことに、b.hにはoff.hを参照するものは含まれず、実装b.cppのみがoff.hを参照します。これだけで私は戸惑いました。

混乱を助長するために、off.hからb.cppへの参照を削除することができ、予想どおり、正常に再コンパイルされました。ただし、参照を再度追加すると、コンパイルも正常に行われ、オブジェクトファイルをクリーンアップした後もコンパイルが続行されました。特にシンボルが競合してはならないこと、シンボルの重複を防いだこと、以前の/不完全なビルドを取り除いたことを考えると、コンパイルに失敗した理由についてはまだ途方に暮れています。

プログラムを正常にコンパイルできたので、提案をテストするためにプログラムを再現できるとは思えません。しかし、これがどのように発生するのか知りたいのですが、将来この動作に遭遇した場合、私が行ったことを超えた場合、それを修正するために何をすることができますか?

23
rcollyer

これは多くの場合、単にオブジェクトを宣言するのではなく、ヘッダーファイルでオブジェクトを定義した結果です。考えてみましょう:

h.h

#ifndef H_H_
#define H_H_
int i;
#endif

a.cpp

#include "h.h"

b.cpp

#include "h.h"
int main() {}

これにより、重複するシンボルiが生成されます。解決策は、ヘッダーファイルでオブジェクトを宣言することです。extern int i;そしてそれをソースコードファイルの1つだけで定義するには:int i;

49
Robᵩ