Có nhiều vấn đề về tính di động với C ++, điều này chỉ do thiếu tiêu chuẩn hóa ở cấp độ nhị phân.
Tôi không nghĩ nó khá đơn giản. Các câu trả lời được cung cấp đã cung cấp lý do tuyệt vời về việc thiếu tập trung vào tiêu chuẩn hóa, nhưng C ++ có thể quá giàu ngôn ngữ để phù hợp để cạnh tranh thực sự với C như một tiêu chuẩn ABI.
Chúng ta có thể đi vào xáo trộn tên do quá tải chức năng, không tương thích vtable, không tương thích với các ngoại lệ ném qua ranh giới mô-đun, v.v ... Tất cả những điều này là một nỗi đau thực sự, và tôi ước họ ít nhất có thể tiêu chuẩn hóa bố cục vtable.
Nhưng một tiêu chuẩn ABI không chỉ là tạo ra các dylib C ++ được sản xuất trong một trình biên dịch có khả năng được sử dụng bởi một nhị phân khác được xây dựng bởi một trình biên dịch khác. ABI được sử dụng nhiều ngôn ngữ . Sẽ thật tuyệt nếu họ ít nhất có thể bao quát phần đầu tiên, nhưng không có cách nào tôi thấy C ++ thực sự cạnh tranh với C ở cấp độ ABI phổ quát rất quan trọng để tạo ra các dylib tương thích rộng rãi nhất.
Hãy tưởng tượng một cặp hàm đơn giản được xuất như thế này:
void f(Foo foo);
void f(Bar bar, int val);
... và tưởng tượng Foo
và Bar
là các lớp với các hàm tạo được tham số hóa, các hàm tạo sao chép, các hàm tạo di chuyển và các hàm hủy không tầm thường.
Sau đó lấy kịch bản của Python / Lua / C # / Java / Haskell / etc. nhà phát triển đang cố gắng nhập mô-đun này và sử dụng nó trong ngôn ngữ của họ.
Trước tiên, chúng ta cần một tiêu chuẩn xáo trộn tên cho cách xuất các biểu tượng sử dụng quá tải hàm. Đây là một phần dễ dàng hơn. Tuy nhiên, nó không thực sự là tên "mangling". Vì người dùng của dylib phải tìm kiếm các biểu tượng theo tên, sự quá tải ở đây sẽ dẫn đến các tên không giống như một mớ hỗn độn. Có lẽ tên biểu tượng có thể giống "f_Foo"
"f_Bar_int"
hoặc một cái gì đó thuộc loại đó. Chúng tôi phải chắc chắn rằng họ không thể đụng độ với một tên thực sự được xác định bởi nhà phát triển, có thể bảo lưu một số ký hiệu / ký tự / quy ước cho việc sử dụng ABI.
Nhưng bây giờ một kịch bản khó khăn hơn. Làm thế nào để nhà phát triển Python, ví dụ, gọi các hàm tạo di chuyển, sao chép các hàm tạo và các hàm hủy? Có lẽ chúng ta có thể xuất khẩu chúng như một phần của dylib. Nhưng nếu Foo
và Bar
được xuất khẩu trong các mô-đun khác nhau thì sao? Chúng ta có nên nhân đôi các biểu tượng và triển khai liên quan đến dylib này hay không? Tôi đề nghị chúng ta nên làm, vì nó có thể trở nên thực sự khó chịu rất nhanh nếu không bắt đầu phải vướng vào nhiều giao diện dylib chỉ để tạo một đối tượng ở đây, chuyển nó ở đây, sao chép nó ở đây, phá hủy nó ở đây. Mặc dù mối quan tâm cơ bản tương tự có thể phần nào áp dụng trong C (chỉ bằng tay / rõ ràng hơn), C có xu hướng tránh điều này chỉ theo bản chất của cách mọi người lập trình với nó.
Đây chỉ là một mẫu nhỏ của sự vụng về. Điều gì xảy ra khi một trong các f
hàm trên ném một BazException
(cũng là một lớp C ++ với các hàm tạo và hàm hủy và dẫn xuất std :: ngoại lệ) vào JavaScript?
Tốt nhất tôi nghĩ rằng chúng ta chỉ có thể hy vọng tiêu chuẩn hóa một ABI hoạt động từ một nhị phân được tạo bởi một trình biên dịch C ++ sang một nhị phân khác được tạo bởi một nhị phân khác. Điều đó sẽ là tuyệt vời, tất nhiên, nhưng tôi chỉ muốn chỉ ra điều này. Thông thường đi kèm với những mối quan tâm như vậy để phân phối một thư viện tổng quát hoạt động các trình biên dịch chéo cũng thường là mong muốn làm cho nó thực sự khái quát và tương thích các ngôn ngữ chéo.
Đề xuất giải pháp
Giải pháp được đề xuất của tôi sau khi vật lộn để tìm cách sử dụng giao diện C ++ cho API / ABI trong nhiều năm với giao diện kiểu COM là trở thành nhà phát triển "C / C ++" (chơi chữ).
Sử dụng C để tạo các ABI phổ quát đó, với C ++ để thực hiện. Chúng ta vẫn có thể thực hiện những việc như xuất các hàm trả về các con trỏ tới các lớp C ++ mờ với các hàm rõ ràng để tạo và hủy các đối tượng như vậy trên heap. Cố gắng yêu thích thẩm mỹ C đó từ góc độ ABI ngay cả khi chúng tôi hoàn toàn sử dụng C ++ để thực hiện. Các giao diện trừu tượng có thể được mô hình hóa bằng cách sử dụng các bảng con trỏ hàm. Thật tẻ nhạt khi bọc thứ này vào API C, nhưng lợi ích và khả năng tương thích của bản phân phối đi kèm sẽ có xu hướng làm cho nó rất đáng giá.
Sau đó, nếu chúng tôi không thích sử dụng giao diện này trực tiếp nhiều như vậy (có lẽ ít nhất chúng tôi không nên vì lý do RAII), chúng tôi có thể gói tất cả những gì chúng tôi muốn trong thư viện C ++ được liên kết tĩnh mà chúng tôi gửi kèm với SDK. Khách hàng C ++ có thể sử dụng điều đó.
Các máy khách Python sẽ không muốn sử dụng trực tiếp giao diện C hoặc C ++ vì không có cách nào để tạo các pythonique đó. Họ sẽ muốn gói nó vào các giao diện pythonique của riêng họ, vì vậy thực sự là chúng tôi chỉ xuất một API C / ABI tối thiểu để làm điều đó dễ dàng nhất có thể.
Tôi nghĩ rằng rất nhiều ngành công nghiệp C ++ sẽ được hưởng lợi từ việc này hơn là cố gắng vận chuyển các giao diện kiểu COM một cách bướng bỉnh. Nó cũng sẽ làm cho tất cả cuộc sống của chúng ta dễ dàng hơn khi những người sử dụng các dylib này không phải lo lắng về ABI vụng về. C làm cho nó đơn giản và sự đơn giản của nó từ phối cảnh ABI cho phép chúng ta tạo ra các API / ABI hoạt động tự nhiên và tối giản cho tất cả các loại FFI.