Có phải C ++ 11 đã giải quyết các vấn đề liên quan đến việc chuyển các đối tượng lib giữa các ranh giới thư viện động / chia sẻ? (tức là dlls và như vậy)?


34

Một trong những phàn nàn chính của tôi về C ++ là việc thực hành khó khăn như thế nào khi vượt qua các đối tượng thư viện std bên ngoài ranh giới thư viện động (tức là dll / so).

Thư viện std thường chỉ tiêu đề. Đó là tuyệt vời để làm một số tối ưu hóa tuyệt vời. Tuy nhiên, đối với dll, chúng thường được xây dựng với các cài đặt trình biên dịch khác nhau có thể ảnh hưởng đến cấu trúc / mã bên trong của bộ chứa thư viện std. Ví dụ, trong MSVC, một dll có thể được xây dựng với trình gỡ lỗi lặp trong khi một bản dựng khác bị tắt. Hai dll này có thể gặp vấn đề khi chuyển các thùng chứa std xung quanh. Nếu tôi hiển thị std::stringtrong giao diện của mình, tôi không thể đảm bảo mã mà khách hàng đang sử dụng std::stringlà trùng khớp chính xác với thư viện của tôi std::string.

Điều này dẫn đến khó gỡ lỗi, đau đầu, v.v. Bạn có thể kiểm soát chặt chẽ các cài đặt trình biên dịch trong tổ chức của mình để ngăn chặn các sự cố này hoặc bạn sử dụng giao diện C đơn giản hơn sẽ không gặp phải các vấn đề này. Hoặc chỉ định cho khách hàng của bạn các cài đặt trình biên dịch dự kiến ​​mà họ nên sử dụng (sẽ hút nếu thư viện khác chỉ định các cài đặt trình biên dịch khác).

Câu hỏi của tôi là liệu C ++ 11 có cố gắng làm bất cứ điều gì để giải quyết những vấn đề này không?


3
Tôi không biết câu trả lời cho câu hỏi của bạn, nhưng tôi có thể nói rằng mối quan tâm của bạn được chia sẻ; chúng là chìa khóa cho lý do tại sao tôi sẽ không sử dụng C ++ trong các dự án của mình, vì chúng tôi đánh giá cao sự ổn định của ABI trong việc vắt kiệt mọi chu kỳ hiệu quả tiềm năng cuối cùng.
Donal Fellows

2
Hãy phân biệt. Đó là khó khăn giữa DLLs. Giữa SOs nó luôn hoạt động tốt.
Jan Hudec

1
Nói đúng ra, đây không phải là vấn đề duy nhất của C ++. Có thể có vấn đề này với các ngôn ngữ khác.
MrFox

2
@JanHudec Tôi có thể đảm bảo rằng giữa các SO không hoạt động gần như kỳ diệu như bạn dường như chỉ ra. Khả năng hiển thị biểu tượng và cách xáo trộn tên thường hoạt động, bạn có thể được cách ly nhiều hơn khỏi một vấn đề, nhưng biên dịch một .so với các cờ khác nhau, v.v., và giả sử bạn có thể liên kết nó trong một chương trình với các cờ khác là một người nhận thảm họa.
sdg

3
@sdg: Với các cờ mặc định và khả năng hiển thị mặc định, nó hoạt động. Nếu bạn thay đổi chúng và gặp rắc rối, đó là vấn đề của bạn và không ai khác.
Jan Hudec

Câu trả lời:


20

Bạn đúng rằng mọi thứ STL - thực ra, mọi thứ từ bất kỳ thư viện bên thứ ba nào được tạo khuôn mẫu - tốt nhất nên tránh trong mọi API C ++ công khai. Bạn cũng muốn tuân theo danh sách dài các quy tắc tại http://www.ros.org/reps/rep-0009.html#def định để ngăn chặn sự phá vỡ ABI khiến việc lập trình API C ++ công khai trở thành một việc vặt.

Và câu trả lời liên quan đến C ++ 11 là không, tiêu chuẩn này không chạm vào điều đó. Thú vị hơn là tại sao không? Câu trả lời là bởi vì C ++ 17 rất cảm động về điều đó và để các Mô-đun C ++ được triển khai, chúng ta cần các mẫu đã xuất để hoạt động và để chúng ta cần một trình biên dịch kiểu LLVM như clang có thể đổ AST đầy đủ vào đĩa và sau đó thực hiện tra cứu phụ thuộc vào người gọi để xử lý nhiều trường hợp vi phạm ODR trong bất kỳ dự án C ++ lớn nào - nhân tiện, bao gồm rất nhiều mã GCC và ELF.

Cuối cùng, tôi thấy rất nhiều MSVC ghét và bình luận ủng hộ GCC. Đây là những thông tin rất sai lệch - GCC trên ELF về cơ bản và không thể tin được, không có khả năng tạo mã C ++ hợp lệ và chính xác. Lý do cho điều này rất nhiều và quân đoàn, nhưng tôi sẽ nhanh chóng trích dẫn một ví dụ điển hình: GCC trên ELF không thể tạo ra các phần mở rộng Python được viết bằng Boost.Python trong đó có nhiều hơn một phần mở rộng dựa trên Boost.Python được tải vào Python. Đó là bởi vì ELF với bảng ký hiệu C toàn cầu của nó chỉ đơn giản là không có khả năng bằng cách thiết kế ngăn chặn vi phạm ODR gây ra sự phân tách, trong khi PE và MachO và thực tế là đặc tả Mô-đun C ++ được đề xuất đều sử dụng bảng ký hiệu trên mỗi mô-đun - điều này cũng có nghĩa là thời gian xử lý nhanh hơn rất nhiều. Và còn nhiều vấn đề nữa: hãy xem một StackOverflow tôi đã trả lời gần đây tạihttps://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-rp4-error/14364055#14364055, ví dụ như các cú ném ngoại lệ C ++ bị phá vỡ một cách cơ bản trên ELF.

Điểm cuối cùng: liên quan đến việc xen kẽ các STL khác nhau, đây là một nỗi đau lớn đối với nhiều người dùng doanh nghiệp lớn đang cố gắng trộn các thư viện của bên thứ ba được tích hợp chặt chẽ với một số triển khai STL. Giải pháp duy nhất là một cơ chế mới để C ++ xử lý interop STL, và trong khi chúng ở đó, bạn cũng có thể sửa lỗi trình biên dịch xen kẽ để bạn có thể (ví dụ) trộn các tệp đối tượng được biên dịch MSVC, GCC và clang và tất cả chỉ hoạt động . Tôi sẽ xem nỗ lực của C ++ 17 và xem những gì sẽ xuất hiện trong vài năm tới - Tôi sẽ ngạc nhiên nếu không có gì.


Phản ứng tuyệt vời! Tôi chỉ hy vọng Clang cải thiện khả năng tương thích của windows và nó có thể thiết lập trình biên dịch chuẩn mặc định tốt. Hệ thống bao gồm / tiêu đề văn bản của C ++ thật kinh khủng, tôi mong đến ngày các mô-đun đơn giản hóa tổ chức mã C ++, tăng tốc độ thời gian biên dịch và cải thiện khả năng tương tác của trình biên dịch với các lệnh bắt vi phạm ODR.
Alessandro Stamatto

3
Cá nhân, tôi thực sự mong đợi một sự gia tăng đáng kể về thời gian biên dịch. Việc truy cập AST nội bộ một cách nhanh chóng rất khó khăn và có lẽ chúng ta sẽ cần một bộ nhớ cache chia sẻ trong bộ nhớ của nó. Tuy nhiên, hầu hết mọi thứ xấu khác đều trở nên tốt hơn. BTW, các tệp tiêu đề chắc chắn nằm xung quanh, các mô-đun C ++ hiện tại có các tệp giao diện ánh xạ từ 1 đến 1 thành các tệp tiêu đề. Ngoài ra, các tệp giao diện được tạo tự động sẽ là C ++ hợp pháp, do đó, một tiêu đề kế thừa chỉ đơn giản là các macro C được lọc ra và nhổ ra như một tệp giao diện. Đẹp hả
Niall Douglas

Mát mẻ! Tôi có rất nhiều nghi ngờ về các mô-đun. Hệ thống mô-đun sẽ xem xét Bao gồm văn bản so với bao gồm biểu tượng? Với hiện tại bao gồm chỉ thị, trình biên dịch phải biên dịch lại hàng chục ngàn dòng mã nhiều lần cho mỗi tệp nguồn. Hệ thống mô-đun sẽ cho phép mã một ngày nào đó mà không cần khai báo chuyển tiếp? Nó sẽ cải thiện / dễ dàng các công cụ xây dựng?
Alessandro Stamatto

2
-1 để đề xuất rằng tất cả các mẫu của bên thứ ba đều bị nghi ngờ. Thay đổi cấu hình là độc lập cho dù thứ đang được cấu hình là một mẫu.
DeadMG

1
@Alessandro: Các mô-đun C ++ được đề xuất vô hiệu hóa rõ ràng các macro C. Bạn có thể sử dụng các mẫu, hoặc ngay bây giờ. Các giao diện được đề xuất là C ++ hợp pháp, chỉ đơn thuần là được tạo tự động và có thể được biên dịch tùy ý cho tốc độ sửa chữa, tức là không mong đợi bất kỳ sự tăng tốc nào so với các tiêu đề được biên dịch trước hiện có. Hai câu hỏi cuối cùng, tôi thực sự không biết: nó phụ thuộc :)
Niall Douglas

8

Các đặc điểm kỹ thuật không bao giờ có vấn đề này. Đó là bởi vì nó có khái niệm gọi là "một quy tắc định nghĩa", quy định bắt buộc rằng mỗi biểu tượng có chính xác một định nghĩa trong quy trình đang chạy.

Windows DLL vi phạm yêu cầu này. Đó là lý do tại sao có tất cả những vấn đề này. Vì vậy, tùy thuộc vào Microsoft để sửa nó, không phải ủy ban tiêu chuẩn hóa C ++. Unix không bao giờ gặp vấn đề này, bởi vì các thư viện dùng chung hoạt động khác ở đó và theo mặc định tuân thủ một quy tắc định nghĩa (bạn rõ ràng có thể phá vỡ nó, nhưng rõ ràng bạn chỉ làm nếu bạn biết bạn có đủ khả năng và cần phải loại bỏ vài chu kỳ bổ sung).

Windows DLL vi phạm một quy tắc định nghĩa vì:

  • Chúng mã hóa từ thư viện động mà một biểu tượng sẽ được sử dụng trong thời gian liên kết tĩnh và giải quyết các biểu tượng tĩnh trong thư viện xác định chúng. Vì vậy, nếu cùng một biểu tượng yếu được tạo trong nhiều thư viện dùng chung và các thư viện đó được sử dụng trong một quy trình đơn lẻ, thì trình liên kết động không có cơ hội hợp nhất các biểu tượng đó. Thông thường các ký hiệu như vậy là các thành viên tĩnh hoặc trở ngại lớp của các thể hiện khuôn mẫu và nó gây ra vấn đề khi chuyển các thể hiện giữa các mã trong các DLL khác nhau.
  • Họ mã hóa cho dù biểu tượng sẽ được nhập từ thư viện động đã trong quá trình biên dịch. Do đó, mã được liên kết với một số thư viện tĩnh không tương thích với mã được liên kết với cùng một thư viện.

Unix sử dụng định dạng xuất ELF nhập ngầm tất cả các ký hiệu đã xuất để tránh sự cố đầu tiên và không phân biệt giữa các ký hiệu được giải quyết tĩnh và động cho đến thời gian liên kết tĩnh để tránh lần thứ hai.


Vấn đề khác là cờ biên dịch. Vấn đề đó tồn tại đối với bất kỳ chương trình nào được soạn từ nhiều đơn vị biên dịch, các thư viện động không phải tham gia. Tuy nhiên, nó tệ hơn nhiều trên Windows. Trên Unix, việc bạn liên kết tĩnh hay động không quan trọng, dù sao đi nữa, không ai liên kết thời gian chạy tiêu chuẩn tĩnh (trong Linux, nó thậm chí có thể là bất hợp pháp) và không có thời gian chạy gỡ lỗi đặc biệt, vì vậy một bản dựng là đủ tốt. Nhưng cách Microsoft triển khai liên kết tĩnh và động, gỡ lỗi và giải phóng thời gian chạy và một số tùy chọn khác có nghĩa là chúng gây ra sự bùng nổ tổ hợp của các biến thể thư viện cần thiết. Một lần nữa vấn đề nền tảng chứ không phải vấn đề ngôn ngữ C ++.


2
@DougT.: GCC không có gì để làm với nó. Nền tảng ABI có. Trong ELF, định dạng đối tượng được sử dụng bởi hầu hết các Unices, thư viện dùng chung xuất tất cả các biểu tượng hiển thị và nhập tất cả các biểu tượng mà chúng xuất. Vì vậy, nếu một cái gì đó được tạo ra trong nhiều thư viện, trình liên kết động sẽ sử dụng định nghĩa đầu tiên cho tất cả. Đơn giản, thanh lịch và làm việc.
Jan Hudec

1
@MartinBa: Không có gì để hợp nhất, nhưng nó không quan trọng miễn là nó giống nhau và miễn là nó không được hợp nhất ở nơi đầu tiên. Có, nếu bạn sử dụng các cài đặt trình biên dịch không tương thích trên nền tảng ELF, bạn sẽ gặp phải tình trạng lộn xộn giống như mọi nơi và mọi nơi. Ngay cả khi không sử dụng các thư viện chia sẻ, do đó, nó hơi lạc đề ở đây.
Jan Hudec

1
@Jan - nó có liên quan đến câu trả lời của bạn. Bạn viết: "... một quy tắc định nghĩa ... Windows DLL vi phạm yêu cầu này ... thư viện dùng chung hoạt động khác [trên UNix] ..." nhưng câu hỏi được hỏi liên quan đến các vấn đề với công cụ std-lib (được xác định trong tiêu đề) và lý do không có vấn đề gì với Unix không liên quan gì đến SO so với DLL nhưng với thực tế, trên Unix (rõ ràng) chỉ có một phiên bản tương thích của thư viện chuẩn trong khi trên Windows MS chọn có phiên bản (gỡ lỗi) không tương thích (với kiểm tra mở rộng, vv).
Martin Ba

1
@MartinBa: Không, lý do chính có vấn đề trên Windows là cơ chế xuất / nhập được sử dụng trên Windows không thể hợp nhất chính xác các thành viên tĩnh và trở ngại lớp của các lớp mẫu trong mọi trường hợp và không thể hợp nhất các ký hiệu được liên kết tĩnh và động. Hơn nhiều biến thể thư viện trở nên tồi tệ hơn nhiều, nhưng vấn đề chính là C ++ cần sự linh hoạt từ trình liên kết mà trình liên kết động Windows không có.
Jan Hudec

4
Tôi nghĩ rằng điều này hàm ý rằng đặc tả DLL bị hỏng và nhu cầu tương ứng cho Msft để 'sửa nó' bị đặt sai chỗ. Thực tế là các DLL không hỗ trợ các tính năng nhất định của C ++ không phải là khiếm khuyết của đặc tả DLL. DLL là một cơ chế đóng gói trung lập với ngôn ngữ, trung lập với nhà cung cấp và ABI để hiển thị các điểm nhập vào mã máy ('gọi hàm') và các đốm dữ liệu. Chúng không bao giờ có ý định hỗ trợ các tính năng nâng cao của bất kỳ ngôn ngữ cụ thể nào. Đó không phải là lỗi của Msft, hay đặc tả của DLL mà một số người muốn chúng là một cái gì đó khác.
Euro Micelli

6

Không.

Có rất nhiều công việc đang diễn ra để thay thế hệ thống tiêu đề, tính năng được gọi là Mô-đun và có thể có tác động đến điều này, nhưng chắc chắn không phải là một vấn đề lớn.


2
Tôi không nghĩ hệ thống tiêu đề sẽ có bất kỳ tác động nào trong việc này. Vấn đề là các DLL của Windows vi phạm một quy tắc định nghĩa (có nghĩa là chúng không tuân theo thông số C ++, vì vậy ủy ban C ++ không thể làm gì về nó) và có rất nhiều biến thể của thời gian chạy tiêu chuẩn trong Windows, mà ủy ban C ++ có thể ' t làm bất cứ điều gì về một trong hai.
Jan Hudec

1
Không, họ không. Làm thế nào họ có thể, đặc điểm kỹ thuật thậm chí không đề cập đến một cái gì đó loại đó. Ngoài ra, khi một chương trình (Windows) được liên kết với các dll Windows, ODR được thỏa mãn: tất cả các biểu tượng hiển thị (xuất) phải tuân theo ODR.
Paul Michalik

@PaulMichalik C ++ không bao gồm liên kết (giai đoạn 9) và đối với tôi, ít nhất là liên kết thời gian tải của DLL / SO nằm trong giai đoạn 9. Điều đó có nghĩa là các biểu tượng có liên kết ngoài (dù được xuất hay không) nên được liên kết và tuân thủ ODR. Liên kết động với LoadL Library / dlopen rõ ràng không thuộc các yêu cầu đó.
bames53

@ bames53: IMHO, thông số kỹ thuật quá yếu để cho phép các tuyên bố thuộc loại đó. Một dll / .so có thể được xem như là một "chương trình" của chính nó. Hơn, các quy tắc đã được thỏa mãn. Một cái gì đó giống như tải các "chương trình" khác trong thời gian chạy là rất thấp bởi tiêu chuẩn mà bất kỳ tuyên bố nào liên quan đến điều này là khá tùy tiện.
Paul Michalik

@PaulMichalik Nếu một thực thi yêu cầu liên kết thời gian tải thì trước khi liên kết thời gian tải có các thực thể bên ngoài không được giải quyết và thiếu thông tin cần thiết để thực thi.
LoadL Library
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.