2012-08-11 13 views
6

Tengo una biblioteca C++ que estoy intentando ejecutar en Mac OS X con Clang. La biblioteca consta de un DLL y un ejecutable Unit-Test. Se compila bien con GCC y MSVC, con GCC, utilizo los siguientes ajustes:La captura de tipos de excepciones derivadas falla en Clang/MacOS X

  • La biblioteca se compila con -fvisibility=hidden
  • Todas las clases expuestas están marcados explícitamente como __attribute__(visibility("default"))
  • La biblioteca tiene algunas clases de excepción, derivado de std::runtime_error. Todas esas clases están marcadas para visibilidad predeterminada. Existe una clase raíz LibraryException de la cual se derivan excepciones más específicas.
  • En GCC, utilizo -std=c++0x, con sonido metálico, la biblioteca y el archivo ejecutable de prueba de unidad se construye con -stdlib=libc++ -std=c++11

En Mac OS X, el marco de pruebas unitarias ahora no funciona, porque las excepciones son del tipo incorrecto . Es decir. una prueba como esta falla:

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

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

I verificado que la typeinfo y vtable de mis clases de excepciones personalizadas se exporta con nm -g library.dylib | c++filt -p -i. Este parece ser el caso para todas las excepciones ... ¿Qué diablos está pasando aquí? He intentado depurar los errores y veo cómo se está lanzando el tipo correcto en la biblioteca y, sin embargo, el mismo tipo no se puede capturar en el ejecutable de la prueba unitaria. ¿Hay algo especial requerido con Clang para que funcione? Estoy usando el último framework de googletest de SVN para probar.

Un pequeño programa de prueba presenta el mismo 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"; 
} 

También falla, por ejemplo, cuando una excepción boost::lexical_cast se lanza desde la Biblioteca.

Respuesta

3

Aquí está la solución correcta:

Al aplicar el atributo de visibilidad, se debe aplicar tanto cuando la biblioteca se compila como bien cuando se consume. De lo contrario, el cliente no verá las clases. Por impulso :: lexical_cast, esto significa que usted tiene que utilizar

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

hasta que consiguen lo arreglen en la biblioteca mediante la adición de un __attribute((visibility("default"))) a la excepción (a partir de Boost 1.50, el atributo está presente, pero parece que la soporte para Clang aún no está allí). Al usarlo en un encabezado en la biblioteca, para que pueda capturarse adecuadamente en el código del cliente. Este #pragma también funciona con Clang.

El hecho de que la especificación de un destructor throw() ayudó fue un poco afortunado, pero definitivamente no es la solución correcta.

+0

Definitivamente parece un error ... ¿ha redeclarado el destructor usted mismo o es el construido por defecto? Con gcc 4.3.2 recibo una advertencia si declaro un destructor sin el especificador 'throw()' al heredar de 'exception'. –

+0

Lo he vuelto a declarar en LibraryException como ~ LibraryException() throw(); de lo contrario, GCC 4.6 se quejó de que el predeterminado tiene una especificación de tiro incorrecta o algo similar. – Anteru

Cuestiones relacionadas