3つのプロジェクトがあります:Server、Client、およびCommons。 Commonsでヘッダーとソースのペアを作成しても問題は発生せず、ServerとClient。
ただし、何らかの理由でServerまたはClientプロジェクト内で追加のソース/ヘッダーファイルを作成すると、常にmultiple definition of (...)
とfirst defined here
エラー。
例:
commands.h(Clientプロジェクトのルートディレクトリ)
#ifndef COMMANDS_H_
#define COMMANDS_H_
#include "commands.c"
void f123();
#endif /* COMMANDS_H_ */
commands.c(Clientプロジェクトのルートディレクトリ)
void f123(){
}
main.c(Clientプロジェクトのルートディレクトリ)
#include "commands.h"
int main(int argc, char** argv){
}
エラー:
make: *** [Client] Error 1 Client
first defined here Client
multiple definition of `f123' commands.c
クリーニング、インデックスの再構築、プロジェクトの再構築は役に立ちません。どちらもコンピューターを再起動しません。
ここでの問題は、関数プロトタイプの前にcommands.c
にcommands.h
を含めることです。したがって、Cプリプロセッサは、commands.c
の内容を関数プロトタイプの前のcommands.h
に挿入します。 commands.c
には関数定義が含まれます。その結果、エラーを引き起こす関数宣言より前に関数定義が終了します。
プリプロセッサフェーズ後のcommands.h
の内容は次のようになります。
#ifndef COMMANDS_H_
#define COMMANDS_H_
// function definition
void f123(){
}
// function declaration
void f123();
#endif /* COMMANDS_H_ */
Cでの定義後に関数を宣言できないため、これはエラーです。#include "commands.c"
と関数宣言を入れ替えた場合、関数プロトタイプが関数宣言の前に来るため、エラーは発生しません。
ただし、.c
ファイルを含めることは悪い習慣であり、避けるべきです。この問題のより良い解決策は、commands.h
にcommands.c
を含めて、コマンドのコンパイルされたバージョンをメインファイルにリンクすることです。例えば:
commands.h
#ifndef COMMANDS_H_
#define COMMANDS_H_
void f123(); // function declaration
#endif
commands.c
#include "commands.h"
void f123(){} // function definition
ヘッダーファイルには、commands.cを含めないでください。一般に、.cファイルを含めるべきではありません。むしろ、commands.cにはcommands.hを含める必要があります。ここで定義されているように、Cプリプロセッサは、commands.cの内容を、includesがあるcommands.hに挿入しています。最終的に、commands.hにf123の2つの定義が作成されます。
commands.h
#ifndef COMMANDS_H_
#define COMMANDS_H_
void f123();
#endif
commands.c
#include "commands.h"
void f123()
{
/* code */
}
たぶん.c
ファイルを複数回メイクファイルに入れます。
私はこれの奇妙なバージョンに巻き込まれたので、このAを追加しています。この形式の複数の繰り返しのためにロードが失敗しました
<path>/linit.o:(.rodata1.libs+0x50): multiple definition of `lua_lib_BASE'
<path>/linit.o:(.rodata1.libs+0x50): first defined here
Makefileマジックのバグであることが判明しました。Cファイルのリストがあり、vpathなどを使用しているため、コンパイルは階層内の正しいディレクトリからそれらを取得します。ただし、1つのCファイルがリストの1行の終わりと次の行の先頭で繰り返されたため、makeによって生成されたgccロードには.o
ファイルをコマンドラインで2回。ダラー。複数の定義は、同じファイルの複数のオカレンスからのものでした。リンカは、静的初期化子以外の重複を無視しました!