2012-08-11 9 views
6

Ho una libreria C++ che sto cercando di eseguire su Mac OS X con Clang. La libreria è costituita da una DLL e un eseguibile di Test unità. Si compila bene con GCC e MSVC, con GCC, io uso le seguenti impostazioni:Tipi di eccezioni derivate dalla cattura non riesce su Clang/MacOS X

  • La libreria viene compilata con -fvisibility=hidden
  • Tutte le classi esposte sono esplicitamente contrassegnati come __attribute__(visibility("default"))
  • La biblioteca dispone di alcune classi di eccezioni, derivato da std::runtime_error. Tutte queste classi sono contrassegnate per visibilità predefinita. Esiste una classe radice LibraryException da cui derivano eccezioni più specifiche.
  • Su GCC, io uso -std=c++0x, con clangore, sia la biblioteca e l'eseguibile test di unità è costruita con -stdlib=libc++ -std=c++11

In Mac OS X, il framework di unit test ora viene a mancare, perché le eccezioni sono di tipo sbagliato . Cioè un test come questo non riesce:

// bla.foo() throws CustomException, which is derived from LibraryException 
TEST_THROWS (bla.foo(), CustomException) 

// This works however 
TEST_THROWS (bla.foo(), LibraryException) 

ho verificato che il typeinfo e vtable delle mie classi di eccezioni personalizzate viene esportato utilizzando nm -g library.dylib | c++filt -p -i. Questo sembra essere il caso per tutte le eccezioni ... cosa diavolo sta succedendo qui? Ho provato a eseguire il debug degli errori, e vedo come viene lanciato il tipo corretto nella libreria e tuttavia lo stesso tipo non può essere catturato nell'eseguibile del test dell'unità. C'è qualcosa di speciale richiesto con Clang per farlo funzionare? Sto usando l'ultimo framework googletest di SVN per i test.

Un piccolo programma di test presenta lo stesso problema:

try { 
    funcThatThrowsCustomExceptionFromLibraryDylib(); 
} catch (CustomException& e) { 
    // doesn't get here 
} catch (LibraryException& e) { 
    // does get here 
    // after demangle, this prints CustomException 
    // Can cast down to CustomException and access the fields as well 
    std::cout << typeid (e).name() << "\n"; 
} 

Non riesce anche ad esempio quando un'eccezione boost::lexical_cast viene lanciata dalla Libreria.

risposta

3

ecco la soluzione giusta:

Quando si applica l'attributo visibilità, deve essere applicato sia quando la libreria viene compilata anche quando si è consumato. Altrimenti, il client non vedrà le classi. Per boost :: lexical_cast, questo significa che dovete usare

#pragma GCC visibility push(default) 
#include <boost/lexical_cast.hpp> 
#pragma GCC visibility pop 

fino a quando non farlo fisso nella biblioteca con l'aggiunta di un __attribute((visibility("default"))) all'eccezione (a partire da 1,50 Boost, l'attributo è presente, ma sembra che la il supporto per Clang non esiste ancora). Quando lo si utilizza in un'intestazione nella libreria, in modo che possa essere catturato correttamente nel codice client. Questo #pragma funziona anche con Clang.

Il fatto che specificare un distruttore throw() abbia aiutato è stato un po 'di fortuna, ma non è sicuramente la soluzione giusta.

+0

Sicuramente sembra un bug ... hai dichiarato di nuovo il distruttore o è il predefinito costruito? Con gcc 4.3.2 viene visualizzato un avviso se dichiaro un distruttore senza l'identificatore 'throw()' quando si eredita da 'exception'. –

+0

L'ho ridichiarato in LibraryException come ~ LibraryException() throw(); in caso contrario, GCC 4.6 si è lamentato del fatto che quello predefinito ha una specifica di lancio errata o qualcosa di simile. – Anteru