提问人:Sascha 提问时间:6/20/2016 最后编辑:Sascha 更新时间:2/25/2021 访问量:700
Boost 单元测试框架 dll 导出的 std::basic_ostringstream 导致“已定义符号”错误
std::basic_ostringstream exported by Boost unit test framework dll results in an "already defined symbol"-error
问:
我使用 Visual Studio 2012。我的设置是这样的:
- 针对某些.exe的some.lib链接
- 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 构建了提升库。所有这些都由 VC11 (Visual Studio 2012) 构建和链接。
问题是,在 some.lib 中,我想使用局部变量
std::ostringstream someStream;
some.exe 链接正常。但是当链接动态链接到 boost 单元测试框架 (1.59) 的 some_test.exe 时,它给了我 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
奇怪的依赖关系
我在文件 boost_unit_test_framework-vc110-mt-1_59 上运行了 Dependency Walker.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 还会导出那些冲突的 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)
因此,对于测试框架来说,这似乎是正常行为。 不过,对我来说,将这些符号导出到 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
据我了解,(完全匹配)符号在 some.lib 中标记为“外部”。因此,它们不是从运行时静态链接到 some.lib,而是动态链接。
已知的解决方法
我可以解决该问题,要么使用而不是在 some.lib 的源代码中。我想我可以忍受这一点,但对于任何维护者来说,为什么不允许使用 ostringstream 都很难理解。std::stringstream
std::ostringstream
或者,我可以使用 Linker-Flag 进行some_test.exe并将错误LNK2005降级为警告LNK4006。但我不喜欢永久警告,特别是如果它们只是被屏蔽的错误。/FORCE:MULTIPLE
问题
使用boost_unit_test_framework而不出现这些链接器错误的正确方法是什么?
boost 是故意导出还是我应该提交错误报告?std::basic_ostringstream
我是不是问错了问题?
杂项
MSVC 的行为似乎在版本 2010 中已更改。在此之前,没有错误。https://social.msdn.microsoft.com/Forums/vstudio/en-US/191de00a-53c9-4bd9-9cb6-e844eb224ca2/lnk2005-when-using-stdostringstream?forum=vclanguage
在 8 天没有对 SO 做出答复或评论后,我在 boost-user 邮件列表上打开了一个线程。当然,如果找到答案,我会在 SO 和邮件列表之间分享。http://lists.boost.org/boost-users/2016/06/86332.php(截至2017年8月17日,邮件列表中仍然没有给出解决方案)
现在,1 年后,我升级到 Visual Studio 2015 并得到相同的行为。
答:
我敢打赌,你会拉入两个不同的 C 运行时。 一个通过 Boost,另一个通过您的项目。 请检查您的项目some_test.exe->配置属性-> C/C++ -> 代码生成 -> 运行时库,并尝试多线程 DLL。
评论
通过谷歌搜索您的问题,我发现了以下建议,如果它们可以帮助您的话
添加到 depend-projects 宏,并在主项目中添加到链接器输入必要的库。
将 /FORCE:MULTIPLE 添加到链接器命令行选项中。BOOST_ALL_NO_LIB
来自 MSDN:“使用 /FORCE:MULTIPLE 创建输出文件,无论 LINK 是否为符号找到多个定义。
试试这个:
该选项会导致 Boost Build 构建所有 支持的库变体。用于调试。
--build-type=complete
/MTd
您也可以查阅此页面
评论
由于尝试了许多方法在我的项目中包含提升单元测试,我遇到了类似的问题,并且包含重复的包含文件以及我的unit_test_main的重复定义。
评论