Std :: basic_ostringstream exported using Boost unit test framework dll results in an "already defined character" -error

I am using Visual Studio 2012. My setup is this:

  • Links some.lib to some.exe
  • Links some.lib to some_test.exe

I use BOOST_TEST_DYN_LINK when creating some_test.exe. The results are similar using BOOST_ALL_DYN_LINK for some .lib and test.exe.

I created some_test.exe, some.exe and some.lib with / MD (multi-threaded DLL). I created boost files with runtime-link = shared. All of them are built and connected by VC11 (Visual Studio 2012).

The problem is that in some.lib I would like to use a local variable

std::ostringstream someStream; 

The links to some.exe are excellent. But when linking some_test.exe, which is dynamically linked to the boost unit test platform (1.59), it gives me 3 errors (LNK2005):

Mistakes

 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 

The same thing happens when using 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 

Strange dependencies

I ran Dependency Walker in boost_unit_test_framework-vc110-mt-1_59.dll file

 ??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) 

or decorated with:

 ??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 

For comparison, I downloaded boost_unit_test_framework-vc110-mt-1_61.dll from

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

and that dll also exports these conflicting ostringstream characters

 ??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) 

So, this is similar to the normal behavior of the test environment. Although for me it is not a good idea to export these characters to a DLL.

I also did dumpbin /symbols some.lib

There I find conflicting characters:

 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 

As far as I understand, the characters (exact matches) are marked as "External" in some.lib. Therefore, they are not statically linked to runtime in some.lib, but dynamically.

Known workarounds

I can solve the bei problem either by using std::stringstream instead of std::ostringstream in some.lib source. I think I could live with this, but it would be difficult for any attendant to understand why ostringstream could not be used.

Alternatively, I could use Linker-Flag /FORCE:MULTIPLE for some_test.exe and lower the Error LNK2005 value to the warning LNK4006. But I do not like perm warnings, especially if they only masked errors.

Questions

What is the correct way to use boost_unit_test_framework and not get these linker errors?

std::basic_ostringstream export intentionally increase std::basic_ostringstream or should I report an error?

Am I asking the wrong questions?

miscellanea

The behavior of MSVC seems to have changed in the 2010 version. Before that there were no errors. https://social.msdn.microsoft.com/Forums/vstudio/en-US/191de00a-53c9-4bd9-9cb6-e844eb224ca2/lnk2005-when-using-stdostringstream?forum=vclanguage

After 8 days with no response or comments on SO, I opened a thread on the boost-user mailing list. If an answer is found, I will share it between SO and the mailing list, of course. http://lists.boost.org/boost-users/2016/06/86332.php (as of 08/17/2017 there is still no solution indicated on the mailing list)

Now, a year later, I upgraded to Visual Studio 2015 and got the same behavior.

+7
c ++ boost dll visual-c ++
source share
2 answers

I bet you pulled out two different time periods. One through Boost, and the other through your project. Check your project some_test.exe-> Configuration Properties-> C / C ++ → Code Generation → Runtime Library and try a multi-threaded DLL.

0
source share

As a result of looking for your problem, I found the following suggestions if they can help you


Add dependent projects with BOOST_ALL_NO_LIB to the BOOST_ALL_NO_LIB and add the necessary libraries to the linker in the main project. add / FORCE: MULTIPLE for linker command line options.

From MSDN : "Use / FORCE: MULTIPLE to create an output file regardless of whether LINK finds more than one definition for a character."

Try the following:

The --build-type=complete option forces Boost Build to build all supported library options. Use /MTd for debugging.

You can also refer to this page.

0
source share

All Articles