为什么在链接存档时会出现“多重定义”错误?

时间:2012-02-03 13:04:12

标签: c unit-testing linker cpputest

我使用CppUTest来测试fornol.c源文件中定义的C代码。该文件定义了主要生产main()函数。

我还有一个AllTests.cpp文件也有main()函数,但main()只能在运行单元测试时使用。

AllTests.cpp被编译为.o文件,而fornol.c被编译为libfornol.a档案。

然后CppUTest尝试将所有内容链接在一起,但这是我得到的内容:

Linking fornol_tests
cc    -o fornol_tests objs/tests/AllTests.o objs/tests/FornolTests.o lib/libfornol.a ../../CppUTest/lib/libCppUTest.a ../../CppUTest/lib/libCppUTestExt.a -lstdc++ -lgcov
lib/libfornol.a(fornol.o): In function `main':
/home/dlindelof/Work/endor/nol/fornol/fornol.c:453: multiple definition of `main'
objs/tests/AllTests.o:/home/dlindelof/Work/endor/nol/fornol/tests/AllTests.cpp:4: first defined here
collect2: ld returned 1 exit status

好像main()中定义并存档fornol.c中的libfornol.a功能与main()中定义的AllTests.cpp冲突。但我的理解是,只有当/或某个给定符号尚未被引用时,才会搜索存档/库文件。因此,如果所有定义都在归档/库文件中,则多次定义相同的符号应该不是问题。

我在这里做错了什么?

2 个答案:

答案 0 :(得分:4)

您需要从main()中移除AllTests.cpp并将其放入自己的源文件中。

当链接器在库中链接时,它不能拆分库中的目标文件; 它必须链接或省略库中的每个目标文件作为一个单元。 (我知道LLVM是不同的,但这是另一个话题。)这就是为什么,如果你看一下像glibc这样的库的源代码,每个函数都会获得自己的源文件。

所以发生的事情是链接器需要从库(fornol.o)中提取目标文件(libfornol.a)以满足依赖性,但该目标文件带有用它复制符号(main)。

将测试代码放在库中是完全可以的(我们常常在我工作的地方这样做),但是将它保存在自己的源文件中(我们传统上使用main.cc)。 (无论如何,这是一个更好的测试,因为测试代码不应该访问static - 声明的符号。)

答案 1 :(得分:0)

库应该没有main()函数,因为它是

你应该从fornol.c中删除那个main()并再次编译它。

main()是可执行文件源代码的入口点,因为库(特别是静态“.a”库)只是预编译的源代码,你不能在那里使用main。

如果你想要你的库的主要生产入口点你可以将fornol.c中的main()重命名为更明确和更少保留的东西,例如“fornolMain()”。

静态库在二进制可执行文件中编译,因此只有在加载符号时才会搜索。它与编译fornol.c并链接fornol.o和您的其他.o

完全相同