我有一个 C++ 库,我试图用 Clang 在 Mac OS X 上运行它。该库由一个 DLL 和一个单元测试可执行文件组成。它使用 GCC 和 MSVC 编译得很好,使用 GCC,我使用以下设置:
- 库是用
-fvisibility=hidden
编译的 - 所有公开的类都明确标记为
__attribute__(visibility("default"))
- 该库有一些异常类,派生自
std::runtime_error
。所有此类类都标记为默认可见性。有一个根类LibraryException
,从中派生出更具体的异常。 - 在 GCC 上,我使用
-std=c++0x
,使用 clang,库和单元测试可执行文件都是使用-stdlib=libc++ -std=c++ 构建的11
在 Mac OS X 上,单元测试框架现在失败了,因为异常类型错误。 IE。这样的测试失败了:
// 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 | 验证了我的自定义异常类的 typeinfo 和 vtable 是导出的 | c++filt -p -i
。这似乎是所有异常(exception)情况的情况……这到底是怎么回事?我尝试调试错误,我看到了如何在库中抛出正确的类型,但无法在单元测试可执行文件中捕获相同的类型。 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
异常时,它也会失败。
最佳答案
正确的解决方法是:
在应用可见性属性时,必须在编译库时以及在使用库时应用它。否则,客户端将看不到这些类。对于 boost::lexical_cast,这意味着您必须使用
#pragma GCC visibility push(default)
#include <boost/lexical_cast.hpp>
#pragma GCC visibility pop
直到他们通过向异常添加 __attribute((visibility("default")))
将其固定在库中(从 Boost 1.50 开始,该属性存在,但似乎目前还没有对 Clang 的支持)。在库中的 header 中使用它时,可以在客户端代码中正确捕获它。此 #pragma
也适用于 Clang。
指定 throw () 析构函数这一事实是有点运气,但这绝对不是正确的解决方法。
关于c++ - 在 Clang/MacOS X 上捕获派生异常类型失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11913151/