7

我有一个 C++ 库,我正在尝试使用 Clang 在 Mac OS X 上运行。该库由一个 DLL 和一个单元测试可执行文件组成。它使用 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)

我验证了我的自定义异常类的 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";
}

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

4

1 回答 1

3

这是正确的解决方案:

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

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

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

指定 throw () 析构函数有帮助的事实是一些运气,但这绝对不是正确的解决方法。

于 2012-08-11T09:08:00.800 回答