c++ - Boost 单元测试框架 dll 导出的 std::basic_ostringstream 导致 "already defined symbol"-error

标签 c++ visual-c++ boost dll

我使用 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 链接正常。但是当链接动态链接到 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.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.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 的源代码中使用 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 (截至 17.08.2017 邮件列表中仍然没有给出解决方案)

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

最佳答案

我敢打赌您会引入两种不同的 C 运行时。 一个通过 Boost,另一个通过您的项目。 请检查您的项目 some_test.exe->Configuration Properties-> C/C++ -> Code Generation -> Runtime Library 并尝试多线程 DLL。

关于c++ - Boost 单元测试框架 dll 导出的 std::basic_ostringstream 导致 "already defined symbol"-error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37922117/

相关文章:

c++ - 在有向图中只访问一次所有节点

c++ - 尝试将指向 int 的指针传递给需要指向 long 的指针的函数,如何执行此操作

visual-c++ - cvBlobsLib 外部链接错误..请帮帮我

c++ - 为什么 C++ Boost 发行版有 `.dll` 和 `.lib` 文件?

c++ - 位图边界矩形算法 C++

c# - 如何在 Directwrite 中获取给定字体的可用 OpenType 功能?

c - 为什么 MSVC 预处理器连接 token 的方式与 GCC 和 Clang 不同?

c++ - 为什么要使用 io_service::work?

c++ - 将 boost::asio::ip::address_v4 隐藏为字符串

c++ - 如何在 Visual Studio 中调试命令行实用程序