在Clang/MacOS X上捕获派生的异常类型失败

Ant*_*eru 7 c++ macos porting clang

我有一个C++库,我试图在使用Clang的Mac OS X上运行.该库由DLL和Unit-Test可执行文件组成.它与GCC和MSVC编译良好,使用GCC,我使用以下设置:

  • 该库是用.编译的 -fvisibility=hidden
  • 所有公开的类都明确标记为 __attribute__(visibility("default"))
  • 该库有一些异常类,派生自std::runtime_error.所有这些类都标记为默认可见性.有一个根类LibraryException,从中可以派生出更具体的异常.
  • 在GCC上,我使用-std=c++0xclang,库和单元测试可执行文件都是用-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)
Run Code Online (Sandbox Code Playgroud)

我验证了我的自定义异常类的typeinfo和vtable是使用导出的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";
}
Run Code Online (Sandbox Code Playgroud)

例如,当boost::lexical_cast从库中抛出异常时,它也会失败.

Ant*_*eru 3

这是正确的解决方案:

应用可见性属性时,必须在编译库时以及使用库时应用它。否则,客户端将看不到这些类。对于 boost::lexical_cast ,这意味着你必须使用

 #pragma GCC visibility push(default)
 #include <boost/lexical_cast.hpp>
 #pragma GCC visibility pop
Run Code Online (Sandbox Code Playgroud)

直到他们通过在异常中添加 a 来修复它__attribute((visibility("default")))(从 Boost 1.50 开始,该属性已经存在,但似乎还不存在对 Clang 的支持)。当在库的标头中使用它时,可以在客户端代码中正确捕获它。这#pragma也适用于 Clang。

指定 throw () 析构函数确实有帮助,但它绝对不是正确的修复方法。