我收到多个定义错误但不明白为什么。
我正在使用Cygwin上的g ++编译C代码。我正在使用单元测试框架(谷歌测试,这是C ++,这就是为什么我不使用gcc)。单元测试源文件#include包含我想要单元测试的函数的.c文件(fileA.c),基本上使它成为所述文件的扩展,并编译单元测试源文件。测试中的函数调用在fileB.h中声明并在fileB.c中定义的函数。这有点像Override a function call in C。我没有显示包含警卫,但基本上剥离的代码看起来像这样:
fileB.h
typedef void * pClass; // to hide the "class" in the .c file
extern pClass pObject1;
void do_something_with_object( void * );
fileB.c
#include "FileB.h"
typedef struct myclass {
int stuff;
} myclass;
myclass Obj1 = { initial_value };
void *pObj1 = &Obj1;
void do_something_with_object( void *arg) {
// do stuff, casting to myclass and verifying it's the right kind
}
fileA.h
#include "fileB.h"
void myfunc( void );
fileA.c
#include "fileA.h"
void myfunc( void ) {
do_something_with_object( pObj1 );
}
utest_fileA.cpp
#include "../fileA.c"
// google test infrastructure stuff not shown
TEST(testname, testcase) {
myfunc();
}
fileB的sybols链接到一个包含所有生产代码的静态库。静态库是用g ++编译的,所以没有extern "C"
个问题。 utest_fileA.cpp的makefile在此库中静态链接。到现在为止还挺好。现在,我想提供我自己的假的do_something_with_object版本,这样我就可以监视传入的内容,以确保myfunc使用正确的参数调用do_something_with_object。我不想修改生产代码只是为了支持这个单元测试。所以,我在单元测试源的编译单元中进一步创建了一个虚假版本的do_something_with_object:
static void * myspy;
void do_something_with_object( void * arg) {
myspy = arg;
}
这个想法是单元测试将使用假定义,因为它有一个定义,它不会在静态库中寻找它,并且不会有冲突。通常这是有效的。但是在我现在面对的情况下,我得到do_something_with_object()的多个定义错误,首先找到假的,然后找到真的。我没有看到与这种情况有什么不同的东西,但显然我错过了一些东西。可能是什么导致了这个?我应该寻找什么?尝试将utest_fileA.o与libMyLib.a链接时,它失败了。它使用-static标志。我尝试了一些我在其他地方看到的关于stackoverflow的建议,比如-z muldefs,但是Cygwin不喜欢这样,我真的很想知道发生了什么。
答案 0 :(得分:0)
多个定义的原因是fileB.h中的“extern pClass Object1”。作为一个未解析的外部,当一个目标文件包含它时,链接器会拉入定义它的对象,即fileB.o。链接器会引入整个fileB.o而不仅仅是单个符号,因此函数定义也会被拉入。因此,当单元测试代码编译并具有间谍定义时,它编译得很好。但是当链接器尝试在静态库中链接时,它会找到另一个定义并且链接失败。
我没有尝试通过链接器首先找到间谍版本来覆盖静态库中的函数调用,而是最终给了间谍一个稍微不同的名称,并使用预处理器将其交换为单元测试。这允许生产代码保持不变。它与Override a function call in C中选择的答案类似,但不完全相同,因为间谍及其预处理程序指令是在单独的文件中定义的,可以包含在任何单元测试中,因此无需注册特定头文件中的替换。