【问题标题】:boost test - 'undefined reference' errors升压测试 - “未定义的参考”错误
【发布时间】:2012-11-25 21:41:13
【问题描述】:

我有两个简单的文件:

runner.cpp:

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>

和 test1.cpp:

#define BOOST_TEST_DYN_LINK
#ifdef STAND_ALONE
#   define BOOST_TEST_MODULE Main
#endif
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE( Foo)

BOOST_AUTO_TEST_CASE( TestSomething )
{
    BOOST_CHECK( true );
}

BOOST_AUTO_TEST_SUITE_END()

要编译,我正在使用:

$ g++ -I/e/code/boost_1_52_0 -o runner -lboost_unit_test_framework runner.cpp test1.cpp

我收到以下错误:

C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0x8c): multiple definition of `main'
c:/pdev/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.2/../../../libboost_unit_test_framework.a(unit_test_main.o):unit_test_main.cpp:(.text.startup+0x0): first defined here
c:/pdev/mingw/bin/../lib/gcc/i686-pc-mingw32/4.7.2/../../../libboost_unit_test_framework.a(unit_test_main.o):unit_test_main.cpp:(.text.startup+0x14): undefined reference to `init_unit_test_suite(int, char**)'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0x52): undefined reference to `_imp___ZN5boost9unit_test9framework17master_test_suiteEv'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text+0xb0): undefined reference to `_imp___ZN5boost9unit_test14unit_test_mainEPFbvEiPPc'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test13test_observerD2Ev[__ZN5boost9unit_test13test_observerD2Ev]+0xe): undefined reference to `_imp___ZTVN5boost9unit_test13test_observerE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test13test_observerC2Ev[__ZN5boost9unit_test13test_observerC2Ev]+0xe): undefined reference to `_imp___ZTVN5boost9unit_test13test_observerE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ccU0cDSz.o:runner.cpp:(.text$_ZN5boost9unit_test15unit_test_log_tC1Ev[__ZN5boost9unit_test15unit_test_log_tC1Ev]+0x22): undefined reference to `_imp___ZTVN5boost9unit_test15unit_test_log_tE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x88): undefined reference to `_imp___ZN5boost9unit_test15unit_test_log_t14set_checkpointENS0_13basic_cstringIKcEEjS4_'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x136): undefined reference to `_imp___ZN5boost10test_tools9tt_detail10check_implERKNS0_16predicate_resultERKNS_9unit_test12lazy_ostreamENS5_13basic_cstringIKcEEjNS1_10tool_levelENS1_10check_typeEjz'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x21d): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1ENS0_13basic_cstringIKcEE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x284): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1EPNS0_9test_caseEm'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text+0x2a4): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24auto_test_unit_registrarC1Ei'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text$_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[__ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x1d): undefined reference to `_imp___ZN5boost9unit_test9ut_detail24normalize_test_case_nameENS0_13basic_cstringIKcEE'
C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\cciSdkmB.o:test1.cpp:(.text$_ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE[__ZN5boost9unit_test14make_test_caseERKNS0_9callback0INS0_9ut_detail6unusedEEENS0_13basic_cstringIKcEE]+0x5b): undefined reference to `_imp___ZN5boost9unit_test9test_caseC1ENS0_13basic_cstringIKcEERKNS0_9callback0INS0_9ut_detail6unusedEEE'
collect2.exe: error: ld returned 1 exit status

我在 MinGW 上使用 g++ 4.7.2,boost 1.52.0。

我只尝试编译 test1.cpp 时遇到相同的错误 - 除了“多个主定义”之一。

我仔细阅读官方文档很长一段时间,但关于链接选项的详细信息很少。当我编译boost库时,除了unit_test_framework,我还得到了prg_exec_monitortest_exec_monitor;也许我应该以某种方式链接这些?我尝试了很多组合,但都导致了某种未定义的引用链接器错误。

boost 生成的库的完整列表 - 我将它们全部放在项目根目录中:

libboost_prg_exec_monitor-mgw47-mt-1_52.a
libboost_prg_exec_monitor-mgw47-mt-1_52.dll
libboost_prg_exec_monitor-mgw47-mt-1_52.dll.a
libboost_prg_exec_monitor-mgw47-mt-d-1_52.a
libboost_prg_exec_monitor-mgw47-mt-d-1_52.dll
libboost_prg_exec_monitor-mgw47-mt-d-1_52.dll.a
libboost_test_exec_monitor-mgw47-mt-1_52.a
libboost_test_exec_monitor-mgw47-mt-d-1_52.a
libboost_unit_test_framework-mgw47-mt-1_52.a
libboost_unit_test_framework-mgw47-mt-1_52.dll
libboost_unit_test_framework-mgw47-mt-1_52.dll.a
libboost_unit_test_framework-mgw47-mt-d-1_52.a
libboost_unit_test_framework-mgw47-mt-d-1_52.dll
libboost_unit_test_framework-mgw47-mt-d-1_52.dll.a

【问题讨论】:

  • 使用 g++,您需要将您的库(-lwhatever)放在源文件或目标文件之后(即g++ -I/e/code/boost_1_52_0 -o runner runner.cpp test1.cpp -lboost_unit_test_framework)。链接here。您可能还需要添加类似于您的-I/e/code/boost_1_52_0-L/path/to/libraries
  • This answer 似乎与您正在做的事情非常相似。
  • @llonesmiz 确实,将库放在对象工作之后。 -L. 也是需要的,lib 需要作为-lboost_unit_test_framework-mgw47-mt-1_52 传递。将其作为-lboost_unit_test_framework 传递会导致链接错误。但是,当我怀疑它可能找不到库时,我给出了类似 -lfoo 的内容,它抱怨不存在这样的库。在咨询 this page 关于默认 MinGW 库路径后,我发现我在其中一个文件夹中有另一个 libboost_unit_test_framework.a
  • @llonesmiz 如果你能在答案中总结这些问题,我很乐意接受。
  • 我的建议只完成了一半。自己提出答案,我会投赞成票。

标签: c++ unit-testing boost mingw boost-test


【解决方案1】:

@llonesmiz 的帮助下,发现了一些问题。

1.需要在 对象和使用它们的源之后指定库。

here所述:

链接器的传统行为是从 在命令行上指定的库中从左到右。这意味着一个 包含函数定义的库应该出现在任何源之后 使用它的文件或目标文件。这包括指定的库 快捷方式-l选项,如下命令所示:

$ gcc -Wall calc.c -lm -o calc (correct order)

对于某些链接器,顺序相反(将 -lm 选项放在文件之前 使用它)会导致错误,

$ cc -Wall -lm calc.c -o calc (incorrect order)
main.o: In function 'main':
main.o(.text+0xf): undefined reference to 'sqrt'

因为在 ‘calc.c’ 之后没有包含 sqrt 的库或目标文件。这 选项 -lm 应该出现在文件 ‘calc.c’ 之后

2。应明确指定库路径。

如果没有指定库路径,链接器可能会查找一系列库 默认文件夹,从而加载不同的库然后打算。这是什么 发生在我的案例中 - 我想链接boost_unit_test_framework,但没有 指定路径,因为我假设链接器会在当前文件夹中查找。 毕竟,这就是运行时发生的事情 - 如果dll 在同一个文件夹中 使用exe,它会找到它。

我发现链接器会找到库有点奇怪,因为它是 命名为ibboost_unit_test_framework-mgw47-mt-1_52.dll。当我试图链接到 一个不存在的库,但链接器抱怨说,所以我认为这不是 问题,MinGW 的链接器会忽略这些后缀。

经过一番研究,我找到了this article about MinGW library paths。 MinGW 搜索库的文件夹可以在gcc -print-search-dirs 的输出中找到。 这篇文章还包含一些 bash 魔术来理解该输出:

gcc -print-search-dirs | sed '/^lib/b 1;d;:1;s,/[^/.][^/]*/\.\./,/,;t 1;s,:[^=]*=,:;,;s,;,;  ,g' | tr \; \\012 | grep -v '^ */'

这将打印出这些文件夹的精美列表。 gcc 默认情况下不会 在当前目录中查找库。我查看了它们中的每一个,并找到了 正在加载的库 - libboost_unit_test_framework.a,一个静态库。

这揭示了另一个值得一提的问题:

3.静态链接与动态链接

我没有指定是要静态链接还是动态链接boost_unit_test_framework。 在这种情况下,gcc prefers dynamic linking

由于这些优点 gcc 编译程序以使用共享库 大多数系统上的默认值,如果它们可用的话。每当一个静态库 ‘libNAME.a’ 将用于与编译器选项 -lNAME 链接 首先检查具有相同名称和“.so”的替代共享库 扩展名。

so 是 Unix 上动态库的扩展 - 在 Windows 上,等效为 dll。)

所以,gcc 寻找 libboost_unit_test_framework.dll 在所有它的默认文件夹中,但找不到它。然后它寻找 libboost_unit_test_framework.a,并静态链接。这导致 链接错误,因为来源有#define BOOST_TEST_DYN_LINK,并且 因此希望动态链接库。

要强制执行静态或动态链接,-Wl,-Bstatic-Wl,-Bdynamic 链接器选项开始发挥作用,描述为here

如果我告诉链接器我想要动态链接:

$ g++ -I/e/code/boost_1_52_0 runner.cpp test1.cpp -o runner -Wl,Bdynamic -lboost_unit_test_framework

这将失败,因为链接器将无法找到 dll

4.总结

问题是:

  1. 在使用它们的源之前指定的库
  2. 未指定 lib 路径
  3. 未指定链接类型
  4. 库名不正确

最终的工作命令:

$ g++ -I/e/code/boost_1_52_0 -o runner runner.cpp test1.cpp -L. -Wl,-Bdynamic -lboost_unit_test_framework-mgw47-mt-1_52

【讨论】:

  • 优秀的答案。 main 的多重定义问题也解决了吗?我计划在不久的将来使用类似的东西,我相信这会有很大的帮助。
  • @llonesmiz,是的。我仍然不确定它为什么会发生;无法使用较新的库进行复制。
  • 您的目录显示每个库的两个版本。一个在名称中间带有-d-,一个没有。例如,libboost_unit_test_framework-mgw47-mt-1_52.alibboost_unit_test_framework-mgw47-mt-d-1_52.a。你怎么知道要使用哪一个?
  • @Brick 如果我没记错的话,区别在于-d- 包含调试符号 - 但我不确定是否诚实。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-22
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多