2012-08-11 24 views
6

Tôi có thư viện C++ mà tôi đang cố gắng chạy trên Mac OS X với Clang. Thư viện bao gồm một DLL và một bài kiểm tra Unit-Test. Nó biên dịch tốt với GCC và MSVC, với GCC, tôi sử dụng các cài đặt sau:Bắt các loại ngoại lệ có nguồn gốc không thành công trên Clang/MacOS X

  • Thư viện này được biên soạn với -fvisibility=hidden
  • Tất cả các lớp tiếp xúc được đánh dấu một cách rõ ràng như __attribute__(visibility("default"))
  • Thư viện có một số lớp ngoại lệ, có nguồn gốc từ std::runtime_error. Tất cả các lớp như vậy được đánh dấu để hiển thị mặc định. Có một lớp gốc LibraryException từ đó có nhiều ngoại lệ cụ thể hơn.
  • On GCC, tôi sử dụng -std=c++0x, với kêu vang, cả hai thư viện và các đơn vị kiểm tra thực thi được xây dựng với -stdlib=libc++ -std=c++11

Trên Mac OS X, khuôn khổ kiểm tra đơn vị tại thất bại, bởi vì trường hợp ngoại lệ là loại sai . I E. một thử nghiệm như thế này không thành công:

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

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

Tôi xác minh rằng loại thông tin và vtable của các lớp ngoại lệ tùy chỉnh của tôi được xuất bằng cách sử dụng nm -g library.dylib | c++filt -p -i. Điều này có vẻ là trường hợp cho tất cả các trường hợp ngoại lệ ... cái quái gì đang diễn ra ở đây? Tôi đã cố gắng để gỡ lỗi trên các lỗi, và tôi thấy như thế nào loại chính xác đang được ném trong thư viện và chưa cùng loại không thể bị bắt trong thực thi thử nghiệm đơn vị. Có điều gì đặc biệt cần thiết với Clang để làm việc này không? Tôi đang sử dụng khung googletest mới nhất từ ​​SVN để kiểm tra.

Một chương trình thử nghiệm nhỏ thể hiện cùng một vấn đề:

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

Nó cũng không ví dụ như khi một ngoại lệ boost::lexical_cast được ném từ Thư viện.

Trả lời

3

Đây là giải pháp đúng:

Khi áp dụng thuộc tính hiển thị, phải áp dụng cả khi thư viện được biên dịch tốt khi được tiêu thụ. Nếu không, khách hàng sẽ không nhìn thấy các lớp học. Đối với boost :: lexical_cast, điều này có nghĩa là bạn phải sử dụng

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

cho đến khi họ nhận được nó cố định trong thư viện bằng cách thêm một __attribute((visibility("default"))) đến ngoại lệ (như của Boost 1.50, thuộc tính là hiện tại, nhưng có vẻ như rằng hỗ trợ cho Clang vẫn chưa có). Khi sử dụng nó trong một tiêu đề trong thư viện, vì vậy nó có thể được đánh bắt đúng trong mã máy khách. Điều này #pragma cũng làm việc với Clang.

Thực tế là chỉ định một throw() destructor đã giúp được một số may mắn, nhưng nó chắc chắn không phải là sửa chữa đúng.

+0

Chắc chắn trông giống như một lỗi ... bạn đã tự làm lại bản thân trình phá hủy hay nó là cấu trúc mặc định được xây dựng? Với gcc 4.3.2, tôi nhận được một cảnh báo nếu tôi khai báo một destructor không có 'throw()' specifier khi kế thừa từ 'exception'. –

+0

Tôi redeclared nó trong LibraryException như ~ LibraryException() throw(); nếu không, GCC 4.6 phàn nàn rằng mặc định có một đặc tả ném không chính xác hoặc một cái gì đó tương tự. – Anteru

Các vấn đề liên quan