我收到多个定义错误,但不明白原因。
我正在 Cygwin 上使用 g++ 编译 C 代码。我正在使用单元测试框架(google test,它是 C++,这就是我不使用 gcc 的原因)。单元测试源文件 #includes 包含我想要进行单元测试的函数的 .c 文件 (fileA.c),实质上使其成为所述文件的扩展名,然后我编译单元测试源文件。被测试的函数调用在 fileB.h 中声明并在 fileB.c 中定义的函数。有点像Override a function call in C 。我没有显示包含防护,但本质上精简的代码如下所示:
文件B.h
typedef void * pClass; // to hide the "class" in the .c file
extern pClass pObject1;
void do_something_with_object( void * );
文件B.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
}
文件A.h
#include "fileB.h"
void myfunc( void );
文件A.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 的符号链接(symbolic link)到包含所有生产代码的静态库中。静态库是用 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 不喜欢这样,我真的很想了解发生了什么。
最佳答案
出现多个定义的原因是fileB.h中的“extern pClass Object1”。作为未解析的外部,当目标文件包含它时,链接器会拉入定义它的对象,即 fileB.o。链接器拉入整个 fileB.o 而不仅仅是其中的单个符号,因此函数定义也被拉入。因此,当单元测试代码编译并具有 spy 定义时,它可以正常编译。但是当链接器尝试链接静态库时,它找到了另一个定义,因此链接失败。
我没有尝试通过让链接器首先找到 spy 版本来覆盖静态库中的函数调用,而是最终为 spy 提供了一个稍微不同的名称,并使用预处理器将其交换以进行单元测试。这使得生产代码保持不变。它与 Override a function call in C 中选择的答案类似,但不完全相同。 ,因为 spy 及其预处理器指令是在一个单独的文件中定义的,可以包含在任何单元测试中,所以不需要在特定的头文件中注册替换。
关于c++ - 重写静态库中的 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7988043/