2009-05-07 42 views
24

Tôi đang làm việc trên một thư viện C++ nhất định (hoặc nhiều khung công tác hơn). Tôi muốn làm cho nó trở về tương thích tương thích với các phiên bản trước, không chỉ duy trì khả năng tương thích API mà còn ABI (giống như công việc tuyệt vời của Qt).Tạo Thư viện với ABI tương thích ngược có sử dụng Boost

Tôi sử dụng rất nhiều chức năng của Boost và có vẻ như điều này làm cho khả năng tương thích ngược chỉ là không thể, trừ khi tôi buộc người dùng phải có phiên bản Boost (đôi khi cũ).

Có cách nào (không cần viết lại 1/2 của Boost) để tạo một số "tiền tố" xung quanh không gian tên/đổi tên nó để ngăn không cho nó can thiệp vào phiên bản Boost của người dùng không?

Ví dụ: libXYZ của tôi sử dụng Boost 1.33 và nó có lớp boost::foo. Trong phiên bản 1.35 boost::foo đã được nâng cấp và thành viên mới đã được thêm vào, do đó, boost::foo từ 1.33 và 1.35 là không tương thích với ABI. Vì vậy, người dùng libXYZ phải sử dụng Boost 1.33 hoặc biên dịch lại libXYZ với Boost 1.35 (có thể đã bị hỏng một số API theo cách mà XYZ sẽ không biên dịch).

Lưu ý: Tôi đang nói về UNIX/Linux OS với ELF, nơi liên kết động tương tự như liên kết tĩnh, vì vậy bạn không thể liên kết với hai phiên bản thư viện khác nhau vì biểu tượng sẽ can thiệp.

Một giải pháp phù hợp mà tôi có thể nghĩ đến là đưa Boost vào một không gian tên riêng khác. Vì vậy, libXYZ sẽ sử dụng ::XYZ::boost::foo thay vì ::boost::foo. Điều này sẽ ngăn ngừa va chạm với phiên bản Boost khác mà người dùng có thể sử dụng.

Vì vậy, libXYZ sẽ tiếp tục làm việc với Boost 1.33 tĩnh hoặc động liên kết với nó withing namespace khác, giả định, rằng nó:

  • Sẽ không vạch trần Boost API bên ngoài.
  • Sẽ giữ phiên bản riêng tư ổn định của API được tiếp xúc.

Có cách nào để làm những việc như vậy với Boost không?

Chỉnh sửa: Cuối cùng, tôi quyết định tạo tập lệnh sẽ đổi tên tất cả biểu tượng tăng cường trong nguồn thành một số biểu tượng tùy chỉnh.

Lý do: đơn giản hóa quá trình xây dựng, độc lập với hỗ trợ khả năng hiển thị của trình biên dịch, tính năng hiển thị chỉ hoạt động trên thư viện động, vì điều này không hoạt động, vì vậy tôi cần xây dựng riêng biệt và phụ thuộc cho từng loại thư viện.

Các kịch bản có sẵn ở đó: http://art-blog.no-ip.info/files/rename.py

Chỉnh sửa 2: Phiên bản mới nhất của Boost BCP hỗ trợ namespace đổi tên.

+0

Ý của bạn là gì bởi "liên kết động tương tự như liên kết tĩnh?" ELF SOs rất giống với các DLL trên Windows. Trong thực tế, các tệp DLL có lẽ giống như các định dạng tĩnh hơn so với các ELF SO (các tệp DLL không phải là vị trí độc lập như các ELF thường là). – Zifre

Trả lời

28

Về cơ bản, chỉ cần đảm bảo giao diện công khai vào thư viện của bạn không hiển thị Boost. Bạn luôn có thể sử dụng nó tuy nhiên nhiều bạn muốn nội bộ. Nói chung, có giao diện của một thư viện phụ thuộc vào một thư viện khác là xấu (trừ khi nó phụ thuộc vào một thư viện chuẩn như STL). Boost gần như phù hợp với danh mục thư viện "chuẩn", nhưng ABI của nó thay đổi rất nhiều đến nỗi giao diện của bạn không nên sử dụng nó.

Để chắc chắn rằng bạn không tiếp xúc với những biểu tượng Boost, có một vài điều bạn có thể làm:

A. biên dịch với -fvisibility=hidden và đánh dấu tất cả những biểu tượng nào với __attribute__((visibility("default"))). bạn có thể sử dụng một macro để làm điều này dễ dàng hơn:

#define ABI __attribute__((visibility("default"))) 

B. làm điều gì đó như thế này:

#pragma GCC visibility push(hidden) 
#include <boost/whatever.hpp> 
#pragma GCC visibility pop 

Bạn cũng nên quấn này xung quanh tất cả những biểu tượng nội bộ khác mà bạn không muốn xuất khẩu, hoặc tuyên bố điều này với __attribute__((visibility("hidden"))). Một lần nữa, bạn có thể sử dụng một macro để làm điều này dễ dàng hơn:

#define INTERNAL __attribute__((visibility("hidden"))) 

Trong số các tùy chọn này, tôi thích một tốt hơn, bởi vì nó làm cho bạn một cách rõ ràng suy nghĩ về những biểu tượng đó được xuất khẩu, vì vậy bạn không vô tình xuất khẩu điều bạn don không muốn.

Nhân tiện, bạn có thể tìm thấy nhiều thông tin hơn về cách tạo DSO trong số How to Write Shared Libraries của Ulrich Drepper.

+4

Điều này là không đủ, ngay cả khi tôi không tiếp xúc với Boost API, bởi vì người dùng có thể sử dụng phiên bản Boost khác nhau có thể can thiệp vào các ký hiệu bên trong được sử dụng trong thư viện này. – Artyom

+1

Bạn có thể sửa lỗi đó bằng trình liên kết. – Zifre

+1

Tôi có thể làm như thế nào? Làm thế nào để lọc các biểu tượng tôi muốn phơi bày và thèm tôi không? Nhắc nhở, không có __dllexport như các tùy chọn. – Artyom

0

Bạn sẽ có thể làm điều gì đó như thế này:

namespace XYZ 
{ 
#include <boost/my_library.hpp> 
} 

Và nó nên đổ các tiêu đề thúc đẩy vào không gian tên XYZ. Tuy nhiên, lưu ý rằng điều này sẽ chỉ hoạt động với các thư viện chỉ tiêu đề.

+3

Điều này sẽ không hoạt động bởi vì, nếu my_library sử dụng, ví dụ std :: string và bao gồm nó sẽ là putten bên trong không gian tên XYZ là không chính xác. Không gian tên – Artyom

+0

chỉ bao quanh việc bao gồm tăng –

5

Nói chung, bạn không thể dựa vào bất kỳ loại ABI nào trong C++ ngoài các ràng buộc C chuẩn. Nhưng Tùy thuộc vào có bao nhiêu giả định bạn thực hiện, bạn có thể sử dụng nhiều hơn và nhiều hơn nữa của C + + trong giao diện của bạn.

Tôi đã tìm thấy this bài viết tuyệt vời về các bước để biến API của bạn thành ABI ổn định. Ví dụ, không bao giờ vượt qua các kiểu dữ liệu Standard C++ Library (hoặc Boost) trên giao diện của bạn; nó có thể phá vỡ ngay cả với một sửa lỗi nhỏ cho thư viện.

Một số ví dụ về các vấn đề cần xem ra cho khi xuất bản một API tương thích ABI là:

  • Windows Debug heap. Bạn phải chắc chắn rằng tất cả các phân bổ và deallocations là trên cùng một mặt của một "module" (có nghĩa là, thực thi hoặc DLL).
  • Fragile Binary Interface sự cố. Ngay cả khi cả hai bên của hệ thống của bạn nhất quán sử dụng cùng một trình biên dịch và thư viện, bạn phải cẩn thận trong C++ về những gì bạn xuất bản trong các tệp .h và vị trí phân bổ xảy ra.

Nếu bạn theo dõi bài viết được liên kết, bạn sẽ tìm thấy giải pháp cho những vấn đề này và các vấn đề khác.

Sửa:

Tôi cũng thấy một thú vị article published by Microsoft trong đó mô tả cách giao diện COM làm việc, bằng cách tham gia một dự án ++ C và biến nó thành COM. Đó là niềm tin của tôi rằng một trong những lý do chính mà Microsoft phát triển COM là giải quyết vấn đề Giao diện nhị phân mong manh mà C++ có, để họ có thể gửi các tệp DLL với các API hướng đối tượng xuất bản.

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