由Boost单元测试框架dll导出的std :: basic_ostringstream导致"已定义的符号" - 错误

Sas*_*cha 8 c++ dll boost visual-c++

我使用Visual Studio 2012.我的设置是这样的:

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

我在构建some_test.exe时使用BOOST_TEST_DYN_LINK.对于some.lib和test.exe,使用BOOST_ALL_DYN_LINK的结果是相同的.

我用/ MD(多线程DLL)构建了some_test.exe,some.exe和some.lib.我用runtime-link = shared构建了boost库.所有这些都是由VC11(Visual Studio 2012)构建和链接的.

问题是,在some.lib中,我想使用局部变量

std::ostringstream someStream;
Run Code Online (Sandbox Code Playgroud)

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

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

奇怪的依赖

我在文件boost_unit_test_framework-vc110-mt-1_59.dll上运行了Dependency Walker

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

或装饰:

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

为了比较,我从中下载了boost_unit_test_framework-vc110-mt-1_61.dll

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

并且该DLL还会导出那些冲突的ostringstream符号

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

所以这似乎是测试框架的正常行为.虽然,对我来说,将这些符号导出到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
Run Code Online (Sandbox Code Playgroud)

据我所知,(完全匹配)符号在some.lib中标记为"外部".因此,它们不会从运行时静态链接到some.lib,而是动态地链接.

已知的解决方法

我可以使用std::stringstream而不是std::ostringstream在some.lib的源代码中解决问题.我想我可以忍受这个,但对于任何维护者来说都很难理解,为什么不允许使用ostringstream.

或者,我可以使用链接器标记/FORCE:MULTIPLEsome_test.exe并将错误LNK2005降级为警告LNK4006.但我不喜欢perma-warnings,特别是如果它们只是掩盖了错误.

问题

什么是使用boost_unit_test_framework而不是获取链接器错误的正确方法?

是否有意提升出口std::basic_ostringstream或我应该提交错误报告?

我问的是错误的问题吗?

杂项

在2010版本中,MSVC的行为似乎已经发生了变化.之前,没有错误. https://social.msdn.microsoft.com/Forums/vstudio/en-US/191de00a-53c9-4bd9-9cb6-e844eb224ca2/lnk2005-when-using-stdostringstream?forum=vclanguage

在没有回答或评论SO的8天后,我在boost-user邮件列表上打开了一个帖子.如果找到答案,我当然会在SO和邮件列表之间分享.http://lists.boost.org/boost-users/2016/06/86332.php (截至17.08.2017,邮件列表中仍然没有给出解决方案)

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

Mar*_*ann 0

我敢打赌你会拉入两个不同的 C 运行时。一项通过 Boost,另一项通过您的项目。请检查您的项目 some_test.exe-> 配置属性-> C/C++ -> 代码生成 -> 运行时库并尝试多线程 DLL。