2012-08-11 64 views
6

我有一个C++库,我试图用Clang在Mac OS X上运行。该库由一个DLL和一个单元测试可执行文件组成。它编译罚款与GCC和MSVC,与海湾合作委员会,我使用以下设置:捕获派生的异常类型在Clang/MacOS上失败X

  • 图书馆与-fvisibility=hidden
  • 编译所有外露类被明确标记为__attribute__(visibility("default"))
  • 图书馆有一些异常类,来自std::runtime_error。所有这些类都标记为默认可见性。有一个根类LibraryException,从中派生出更多特定的异常。
  • 在GCC,我用-std=c++0x,铿锵,无论是库和单元测试可执行文件是建立与-stdlib=libc++ -std=c++11

在Mac OS X,单元测试框架,现在失败了,因为异常是错误的类型。即像这样的测试失败:

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

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

我核实,我的自定义异常类的所属类别和虚函数表使用nm -g library.dylib | c++filt -p -i出口。这似乎是所有例外的情况......这里发生了什么?我试图对这些错误进行调试,然后我看到正确的类型是如何在库中引发的,然而在单元测试可执行文件中不能捕获相同的类型。 Clang有什么特别的要求来实现这个目标吗?我正在使用SVN的最新googletest框架进行测试。

一个小的测试程序显示出了同样的问题:

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"; 
} 

boost::lexical_cast异常是从图书馆抛出它也没有为实例。

回答

3

这里是正确的解决方案:

当应用可见性属性,它必须同时适用时,当它被消耗的库被编译为好。否则,客户端将看不到这些类。对于升压:: lexical_cast的,这意味着你必须使用

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

,直到他们得到它通过增加__attribute((visibility("default")))的异常(如boost 1.50的固定在库中,属性是存在的,但它似乎对Clang的支持还没有)。在库中的头文件中使用它时,可以在客户端代码中正确捕获它。 #pragma也适用于Clang。

指定一个throw()析构函数帮助的事实是一些运气,但它绝对不是正确的修复。

+0

绝对看起来像一个bug ...你自己重新声明了析构函数还是默认构造的?使用gcc 4.3.2如果我从'exception'继承时声明一个没有'throw()'说明符的析构函数,我会得到一个警告。 – 2012-08-11 10:20:06

+0

我在LibraryException中重新声明它为〜LibraryException()throw();否则,GCC 4.6会抱怨默认的抛出规格或类似的错误。 – Anteru 2012-08-11 10:47:24