2016-06-20 11 views
7

io uso Visual Studio 2012. La mia configurazione è simile a questo:std :: basic_ostringstream esportato da Boost quadro unit test risultati dll in un "simbolo già definito" -Errore

  • link some.lib contro some.exe
  • link some.lib contro some_test.exe

io uso BOOST_TEST_DYN_LINK quando si costruisce some_test.exe. I risultati sono gli stessi utilizzando BOOST_ALL_DYN_LINK per some.lib e test.exe.

Ho creato some_test.exe, some.exe e some.lib con/MD (Multi-Threaded DLL). Ho creato le librerie boost con runtime-link = shared. Tutti sono costruiti e collegati da VC11 (Visual Studio 2012).

Il problema è, in some.lib, vorrei utilizzare la variabile locale

std::ostringstream someStream; 

Il some.exe collegamenti sottili. Ma quando collega la some_test.exe, che collega in modo dinamico al quadro unit test spinta (1.59) che mi dà 3 errori (LNK2005):

errori

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)" ([email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@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 " ([email protected]?$basic_ostrin[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]) 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)" ([email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@QEAAXXZ) already defined in some.lib(some.obj) 
some_test.exe : fatal error LNK1169: one or more multiply defined symbols found 

Lo stesso accade quando si utilizza 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)" ([email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@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 " ([email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]) 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)" ([email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@QEAAXXZ) already defined in some.lib(some.obj) 
some_test.exe : fatal error LNK1169: one or more multiply defined symbols found 

Strane dipendenze

ho corse Dependency Walker sul file boost_unit_test_framework-vc110-mt-1_59.dll

012.
[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected]@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) 

o decorati:

[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected]@Z 
[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z 
[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z 

Per confronto, ho scaricato boost_unit_test_framework-vc110-mt-1_61.dll da

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

e che dll esporta anche quelle contrastanti simboli ostringstream

[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected]@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) 

Quindi questo sembra un comportamento normale per il framework di test. Anche se, per me non sembra una buona idea esportare quei simboli in una DLL.

Ho anche fatto un dumpbin /symbols some.lib

Non ci trovo i simboli contrastanti:

2AFC 00000000 SECT1183 notype() External | [email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected] (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  | [email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected] 
43D4 00000000 SECT16FB notype  Static  | [email protected][email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected] 

2AFA 00000000 SECT6AF notype() External | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@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  | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z 
43B9 00000000 SECT16F2 notype  Static  | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z 
43BC 00000000 SECT16F3 notype  Static  | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z 
43BF 00000000 SECT16F4 notype  Static  | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z 
43C2 00000000 SECT16F5 notype  Static  | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@[email protected]@Z 

2B0E 00000000 SECTA3C notype() External | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@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  | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@QEAAXXZ 
4449 00000000 SECT1722 notype  Static  | [email protected][email protected]@[email protected]@[email protected]@[email protected]@[email protected]@QEAAXXZ 

Per quanto ho capito, i simboli (corrispondenti esatto) sono contrassegnati "esterno" in some.lib. Quindi non sono collegati staticamente dal runtime in some.lib, ma in modo dinamico.

Conosciuto Soluzioni alternative

posso aggirare il problema sia utilizzando bei std::stringstream invece di std::ostringstream nella fonte di some.lib.Penso che potrei vivere con quello, ma sarebbe difficile capire per qualsiasi manutentore, perché non si sarebbe permesso di usare ostringstream.

In alternativa, potrei usare la Linker-Flag /FORCE:MULTIPLE per some_test.exe e effettuare il downgrade dell'errore LNK2005 a un LNK4006 di avviso. Ma non mi piacciono i perma-warnings, specialmente se sono solo errori mascherati.

le domande

Qual è il modo giusto di usare il boost_unit_test_framework e non ottenere quei errori del linker?

Esporta intenzionalmente l'esportazione std::basic_ostringstream o devo inviare una segnalazione di errore?

Sto facendo le domande sbagliate?

Varie

Il comportamento di MSVC sembra essere cambiato nella versione 2010. Prima, non ci sono errori. https://social.msdn.microsoft.com/Forums/vstudio/en-US/191de00a-53c9-4bd9-9cb6-e844eb224ca2/lnk2005-when-using-stdostringstream?forum=vclanguage

Dopo 8 giorni senza risposta o commento su SO, ho aperto una discussione sulla mailing-list boost-user. Se viene trovata una risposta, la condividerò tra SO e la mailing list, ovviamente. http://lists.boost.org/boost-users/2016/06/86332.php (come del 2017/08/17 c'è ancora nessuna soluzione data nella mailing list o)

Ora, 1 anno dopo, ho aggiornato a Visual Studio 2015 e ottenere lo stesso comportamento.

+0

Giusto per essere sicuri, ha definito simbolo "BOOST_ALL_DYN_LINK"? – zahir

+0

Avevo BOOST_TEST_DYN_LINK definito per some_test.exe, ma anche ricostruito e linke con BOOST_ALL_DYN_LINK impostato sia per alcuni.lib che some_test.exe. I 3 messaggi di errore rimangono gli stessi. – Sascha

+0

Hai provato con VS 2015? Se il problema si presentava in una versione del compilatore, potrebbe essere scomparso in un'altra. – eh9

risposta

0

Scommetto che stai tirando in due diversi tempi C. Uno attraverso Boost e un altro attraverso il tuo progetto. Controlla il tuo progetto some_test.exe-> Proprietà di configurazione-> C/C++ -> Generazione codice -> Libreria di runtime e prova DLL multithread.

+0

Ho controllato l'impostazione (per la centesima volta :-)).È già impostato su/MD in tutti i progetti. – Sascha

0

googling il tuo problema, ho trovato seguenti suggerimenti, se possono aiutare a


Aggiungi a dipendere progetti macro con BOOST_ALL_NO_LIB e nel progetto principale Aggiungi a linker ingresso librerie necessarie. add/FORCE: MULTIPLE alle opzioni della riga di comando del linker.

Da MSDN: "Use/FORCE: MULTIPLE per creare un file di output indipendentemente dal fatto che LINK trovi più di una definizione per un simbolo."

Prova questo:

L'opzione --build-type=complete cause Boost Genera per costruire tutti varianti supportate delle librerie. Utilizzare /MTd per il debug.

È possibile inoltre consultare this page

+0

Ho provato il tuo suggerimento con BOOST_ALL_NO_LIB, ma non cambia gli errori. Come ho menzionato nella domanda,/FORCE: MULTIPLE cambia l'errore permanente in un avvertimento permanente. Voglio che il mio codice venga compilato senza avvisi. – Sascha