【发布时间】:2016-10-21 16:26:45
【问题描述】:
我使用 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;
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
奇怪的依赖
我对文件 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)
或装饰:
??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.dllhttps://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 的源代码中使用 std::stringstream 而不是 std::ostringstream 来解决问题。我想我可以接受,但任何维护者都很难理解,为什么不允许使用 ostringstream。
或者,我可以对 some_test.exe 使用 Linker-Flag /FORCE:MULTIPLE 并将错误 LNK2005 降级为警告 LNK4006。但我不喜欢永久警告,尤其是当它们只是被掩盖的错误时。
问题
使用 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 并获得相同的行为。
【问题讨论】:
-
确定一下,你定义了“BOOST_ALL_DYN_LINK”符号吗?
-
我为 some_test.exe 定义了 BOOST_TEST_DYN_LINK,但也为 some.lib 和 some_test.exe 设置了 BOOST_ALL_DYN_LINK 并重建和链接。 3 条错误消息保持不变。
-
你试过VS 2015吗?如果问题出现在一个编译器版本中,它可能已经在另一个版本中消失了。
-
@eh9 我刚刚尝试了 VS 2015,得到了相同的结果。我在问题中添加了链接器错误。
标签: c++ visual-c++ boost dll