「duplicate symbols for architecture x86_64」の原因(複数)

C/C++やObjective-Cのコードを書いていると、このようなコンパイルエラーが頻繁に出てくる。

duplicate symbols for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
42 duplicate symbols for architecture x86_64

原因1「メソッド名や定数名の重複」

実装ファイル内で既に存在する変数名や関数名を多重定義してしまうと今回のようなエラーが発生する。

対処方法1

重複した変数・関数が他のヘッダファイル等でグローバル変数・関数として宣言されていなければ、static指定子を加えることで対処が可能となる。

/* File.c */
static int shop = 99;
static void shopping() {}
念のため重複元となったシンボルに対してもstatic宣言をしてあげると良い(これによって「Undefined symbols」というエラーメッセージが発生するようになった場合は、externを用いた特殊な設計が取られている可能性があるので十分に注意する)。

C++の場合はstaticによる外部宣言の代わりに、無名名前空間を利用できる。

namespace {
  int shop = 99;
  void shopping() {}
}

対処方法2

重複した変数・関数が既にグローバル変数・関数として意図的に宣言されている場合は、別名を付けて対処する。

/* File.c */
static int xx_shop = 99;
static void xx_shopping() {}

原因2「ヘッダーの循環参照問題」

グローバルスコープ、とりわけヘッダファイル内でint shop = 99;のような記述をすると今回のようなエラーなりやすい。

/* File.h */
int shop = 99;

対象コードを含むヘッダファイルが複数のファイルからインクルード/インポートされていたり、ヘッダが循環参照(同じヘッダが再帰的に読み込まれる状態)を起こしていたりするとこのようなエラーが発生する原因となる。

対処方法1

重複対象のグローバル変数または関数がヘッダファイル内に存在している場合は少し面倒。

グローバル変数/関数をextern宣言し、実装ファイル側で実装・初期化する。

/* File.h */
extern int shop;
extern void shopping();

/* File.c */
int shop = 99;
void shopping() {}

対応方法2

グローバル変数がプリミティブ型のconst定数であれば、static宣言で対処することもできる。

/* File.h */
const int shop = 99; // !!!: duplicate symbol _shop in:
static const int shop = 99; // OK
なおプリミティブ型(intやdouble等)const定数は利用時にマクロと同等のインライン展開が行われる。

ちなみにconst無しの変数に対してstatic宣言を行うとバグの原因になるので注意したい。

/* File.h */
static int shop = 99; // NG!
/* foo.c */
void a() { shop = 0; }
/* bar.c */
int b() { a(); return shop; } // !!!: always return 99

この場合、インクルード側(foo.c, bar.c)でそれぞれ個別のshop変数が定義される。要するに、アドレスの異なる複数の変数が使われてしまう。

対応方法3

グローバル関数が汎用的でまた小さなコードなのであれば、インライン関数として宣言することも可能。

/* File.h */
static inline int max(int a, int b) {
  return a > b ? a : b;
}

原因3「ライブラリ同士の重複」

外部ライブラリが公開しているクラス名・関数名・変数名が他のライブラリの物と重複している場合も同様のエラーが発生する。 同名同一のモジュールをリンクしている場合は片方をビルド対象から外したりすると良い。

なお、外部ライブラリと自身のプロジェクト内ソースとの間で重複が発生してしまうケースでは、また違う名前のエラーになる。

メンバー重複

Redefinition of 'shopping'

クラス重複

Duplicate interface definition for class 'MyClass'

名前を変えたり、C++なら名前空間を設定したり、実装ファイル内に移してstatic宣言したりすると良い。

原因4「クラスの実装を複数回行っている」

Objective-Cで@implementation クラス名形式のクラス実装を行う際に、同名のクラス名が既に@implementation実装されていると、今回のようなエラーが発生する。

エラーメッセージ画面をよく見るとduplicate symbol _OBJC_METACLASS_$_MyClass in:という形でエラーの原因になったクラス名(MyClass)が表示されているので、それを手がかりに重複宣言を探すと良い。

広告
広告