由 Boost 单元测试框架 dll 导出的 std::basic_ostringstream 会导致"already defined symbol"错误

std::basic_ostringstream exported by Boost unit test framework dll results in an "already defined symbol"-error

本文关键字:Boost already defined 错误 symbol ostringstream 单元测试 dll std basic 框架      更新时间:2023-10-16

我使用Visual Studio2012。我的设置就是这样:

  • some.lib链接到某个exe
  • some.lib链接some_test.exe

我在构建some_test.exe时使用boost_test_dyn_link。使用BOOST_ALL_DYN_LINK用于some.lib和test.exe。

,结果是相同的。

我已经构建了some_test.exe,some.exe和some.lib使用/md(多线程dll)。我已经使用Runtime-Link =共享构建了Boost Libs。所有这些都是由VC11构建和链接的(Visual Studio 2012)。

问题是,在某个lib中,我想使用local variable

std::ostringstream someStream;

some.exe链接正常。但是,当链接some_test.exe时,它动态地链接到Boost单元测试框架(1.59),它给了我3个错误(LNK2005):

错误

boost_unit_test_framework-vc110-mt-1_59.lib(boost_unit_test_framework-vc110-mt-1_59.dll) : error LNK2005: "public: __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >(int)" (??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z) already defined in some.lib(some.obj) 
boost_unit_test_framework-vc110-mt-1_59.lib(boost_unit_test_framework-vc110-mt-1_59.dll) : error LNK2005: "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::str(void)const " (?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ) already defined in some.lib(some.obj) 
boost_unit_test_framework-vc110-mt-1_59.lib(boost_unit_test_framework-vc110-mt-1_59.dll) : error LNK2005: "public: void __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::`vbase destructor'(void)" (??_D?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAXXZ) already defined in some.lib(some.obj) 
some_test.exe : fatal error LNK1169: one or more multiply defined symbols found 

使用MSVC14(Visual Studio 2015)

时也会发生同样的情况
boost_unit_test_framework-vc140-mt-1_59.lib(boost_unit_test_framework-vc140-mt-1_59.dll) : error LNK2005: "public: __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char>>::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >(int)" (??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z) already defined in some.lib(some.obj)
boost_unit_test_framework-vc140-mt-1_59.lib(boost_unit_test_framework-vc140-mt-1_59.dll) : error LNK2005: "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::str(void)const " (?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ) already defined in some.lib(some.obj)
boost_unit_test_framework-vc140-mt-1_59.lib(boost_unit_test_framework-vc140-mt-1_59.dll) : error LNK2005: "public: void __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::`vbase destructor'(void)" (??_D?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAXXZ) already defined in some.lib(some.obj)
some_test.exe : fatal error LNK1169: one or more multiply defined symbols found

奇怪的依赖项

i在文件boost_unit_test_framework-vc110-mt-1_59.dll

上运行了依赖关系沃克
??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@$$QEAV01@@Z
std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,int)
std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >(int)

或装饰:

??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@$$QEAV01@@Z
??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@1@H@Z
??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z

为了进行比较,我从

中下载了boost_unit_test_framework-vc110-mt-1_61.dll

https://sourceforge.net/projects/boost/files/boost-binaries/

dll还导出那些冲突的oststream符号

 ??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@$$QEAV01@@Z
 std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,int)
 std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >(int)

因此,对于测试框架来说,这似乎是正常的行为。但是,对我来说,将这些符号导出到DLL似乎不是一个好主意。

我也做了dumpbin /symbols some.lib

在那里我找到了矛盾的符号:

2AFC 00000000 SECT1183 notype ()    External   | ?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ (public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::str(void)const )
43D1 00000000 SECT16FA notype       Static     | $unwind$?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ
43D4 00000000 SECT16FB notype       Static     | $pdata$?str@?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@XZ
2AFA 00000000 SECT6AF notype ()    External    | ??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z (public: __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >(int))
43B6 00000000 SECT16F1 notype       Static     | $unwind$??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z
43B9 00000000 SECT16F2 notype       Static     | $pdata$??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z
43BC 00000000 SECT16F3 notype       Static     | $cppxdata$??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z
43BF 00000000 SECT16F4 notype       Static     | $stateUnwindMap$??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z
43C2 00000000 SECT16F5 notype       Static     | $ip2state$??0?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAA@H@Z
2B0E 00000000 SECTA3C notype ()    External    | ??_D?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAXXZ (public: void __cdecl std::basic_ostringstream<char,struct std::char_traits<char>,class std::allocator<char> >::`vbase destructor'(void))
4446 00000000 SECT1721 notype       Static     | $unwind$??_D?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAXXZ
4449 00000000 SECT1722 notype       Static     | $pdata$??_D?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QEAAXXZ
据我了解,

(确切的匹配)符号在某些lib中标记为"外部"。因此,它们不是从运行时静态链接到某个lib,而是动态的。

已知的解决方法

我可以使用std::stringstream而不是std::ostringstream解决问题。我认为我可以忍受这一点,但是对于任何维护者来说都是很难理解的,为什么不允许使用Oststream。

另外,我可以将Linker-FLAG /FORCE:MULTIPLE用于Some_test.exe,然后将错误lnk2005降级到警告LNK4006。但是我不喜欢Perma-warnings,特别是如果它们只是掩盖错误。

问题

使用BOOST_UNIT_TEST_FRAMEWORK而没有获取这些链接器错误的正确方法是什么?

Boost是否有意导出std::basic_ostringstream,还是我应该提交错误报告?

我问错误的问题吗?

MISC

MSVC的行为似乎在2010年版本中发生了变化。https://social.msdn.microsoft.com/forums/vstudio/en-us/191de00a-53c9-4bd9-4bd9-9cb6-e8444eb224ca2/lnk2005--

8天没有答案或评论后,我在Boost用户邮件列表上打开了一个线程。如果找到答案,我当然会在SO和邮件列表之间分享。http://lists.boost.org/boost-users/2016/06/86332.php(截至2017年8月17日,邮件列表中仍然没有提供解决方案)

现在,一年后,我升级到Visual Studio 2015并获得了相同的行为。

我敢打赌你在两个不同的c runtimes中拉动。一个通过Boost,另一个通过您的项目。请检查您的项目some_test.exe->配置属性 -> c/c ->代码生成 ->运行时库,然后尝试多线程dll。

通过搜索您的问题,我发现了以下建议,如果他们可以帮助您


使用BOOST_ALL_NO_LIB添加到依赖项目的宏,并在主项目中添加到链接器输入必要的库中。添加/强制:链接命令行选项的多个。

来自MSDN:"使用/强制:多个链接为符号找到多个定义的输出文件。

"

尝试以下操作:

选项--build-type=complete导致Boost Build构建全部 库的支持变体。使用/MTd进行调试。

您也可以咨询此页面

我也有类似的问题,因为尝试了许多方法,以在我的项目中包括提升单元测试,并且具有重复的包含在内的文件,并且还重复了我的unit_test_main的定义。