boost test - 'undefined reference'错误

Mih*_*aru 6 c++ boost unit-testing mingw boost-test

我有两个简单的文件:

runner.cpp:

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE Main
#include <boost/test/unit_test.hpp>
Run Code Online (Sandbox Code Playgroud)

和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()
Run Code Online (Sandbox Code Playgroud)

要编译,我正在使用:

$ g++ -I/e/code/boost_1_52_0 -o runner -lboost_unit_test_framework runner.cpp test1.cpp
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

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
Run Code Online (Sandbox Code Playgroud)

我在MinGW上使用g ++ 4.7.2,增强1.52.0.

我只是在尝试编译时遇到了同样的错误test1.cpp- 除了"多主要定义"之外.

我仔细阅读了官方文档很长一段时间,但关于链接选项的细节很少.当我编译升压库,此外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
Run Code Online (Sandbox Code Playgroud)

Mih*_*aru 21

@llonesmiz的帮助下,确定了一些问题.

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

如上所述这里:

链接器的传统行为是在命令行中指定的库中从左到右搜索外部函数.这意味着包含函数定义的库应该出现在使用它的任何源文件或目标文件之后.这包括使用short-cut -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.应明确指定库路径.

如果未指定lib路径,则链接器可能会在一系列默认文件夹中查找lib,从而加载不同的库.这就是我的情况 - 我想链接boost_unit_test_framework,但没有指定路径,因为我假设链接器将在当前文件夹中查找.这就是在运行时发生的事情 - 毕竟 - 如果与dll它在同一个文件夹中exe,它会找到它.

我发现链接器找到lib有点奇怪,因为它被命名了ibboost_unit_test_framework-mgw47-mt-1_52.dll.当我尝试链接到不存在的lib时,链接器却抱怨,所以我认为这不是问题,并且MinGW链接器会忽略这些后缀.

经过一些研究,我发现了这篇关于MinGW库路径的文章.可以在输出中找到MinGW搜索libs的文件夹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 '^ */'
Run Code Online (Sandbox Code Playgroud)

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

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

3.静态与动态链接

我没有指定是否要boost_unit_test_framework静态或动态链接.在这种情况下,gcc更喜欢动态链接:

由于这些优点,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,因此期望动态链接lib.

为了强制执行静态或动态链接,可以使用-Wl,-Bstatic-Wl,-Bdynamic 链接器选项,这里描述.

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

$ g++ -I/e/code/boost_1_52_0 runner.cpp test1.cpp -o runner -Wl,Bdynamic -lboost_unit_test_framework
Run Code Online (Sandbox Code Playgroud)

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

4.Summary

问题是:

  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
Run Code Online (Sandbox Code Playgroud)