【问题标题】:std::basic_ostringstream exported by Boost unit test framework dll results in an "already defined symbol"-errorBoost 单元测试框架 dll 导出的 std::basic_ostringstream 导致“已定义符号”-错误
【发布时间】: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.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 (截至 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


【解决方案1】:

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

【讨论】:

  • 我检查了设置(第一百次:-))。它已在所有项目中设置为 /MD。
【解决方案2】:

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


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

来自MSDN:“使用 /FORCE:MULTIPLE 创建输出文件,无论 LINK 是否找到多个符号定义。”

试试这个:

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

也可以咨询this page

【讨论】:

  • 我用 BOOST_ALL_NO_LIB 尝试了你的建议,但它并没有改变错误。正如我在问题中提到的, /FORCE:MULTIPLE 将永久错误更改为永久警告。我希望我的代码编译时没有警告。
【解决方案3】:

由于尝试了多种方法在我的项目中包含 boost 单元测试,我遇到了类似的问题,并且包含重复的包含文件以及我的 unit_test_main 的重复定义。

【讨论】:

    猜你喜欢
    • 2017-12-11
    • 1970-01-01
    • 2012-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多