Apakah alamat C ++ 11 menyangkut pengalihan objek std lib antara batas perpustakaan dinamis / bersama? (Yaitu dll dan sebagainya)?

34

Salah satu keluhan utama saya tentang C ++ adalah seberapa sulit dalam praktiknya untuk melewati objek perpustakaan std di luar perpustakaan dinamis (yaitu dll / jadi) batas.

Perpustakaan std sering hanya header-saja. Yang bagus untuk melakukan beberapa optimasi yang luar biasa. Namun, untuk dll, mereka sering dibangun dengan pengaturan kompiler berbeda yang dapat berdampak pada struktur internal / kode wadah perpustakaan std. Sebagai contoh, di MSVC satu dll dapat dibangun dengan iterator debugging sementara yang lain membangun dengan itu. Kedua dll ini mungkin mengalami masalah ketika melewati wadah std. Jika saya mengekspos std::stringdi antarmuka saya, saya tidak dapat menjamin kode yang digunakan klien adalah std::stringcocok dengan perpustakaan saya std::string.

Hal ini menyebabkan sulitnya men-debug masalah, sakit kepala, dll. Anda dapat secara kaku mengontrol pengaturan kompiler di organisasi Anda untuk mencegah masalah ini atau Anda menggunakan antarmuka C sederhana yang tidak akan memiliki masalah ini. Atau tentukan kepada klien Anda pengaturan kompiler yang diharapkan yang harus mereka gunakan (yang menyebalkan jika perpustakaan lain menentukan pengaturan kompiler lain).

Pertanyaan saya adalah apakah C ++ 11 mencoba melakukan sesuatu untuk menyelesaikan masalah ini?

Doug T.
sumber
3
Saya tidak tahu jawaban atas pertanyaan Anda, tetapi saya dapat mengatakan bahwa kekhawatiran Anda dibagi; mereka adalah kunci mengapa saya tidak akan menggunakan C ++ dalam proyek saya, karena kami menghargai stabilitas ABI dari setiap siklus terakhir dari efisiensi potensial.
Donal Fellows
2
Tolong bedakan. Sulit di antara DLLs. Antara SOitu selalu bekerja dengan baik.
Jan Hudec
1
Sebenarnya, ini bukan masalah C ++ saja. Dimungkinkan untuk memiliki masalah ini dengan bahasa lain.
MrFox
2
@ JanHudec Saya dapat menjamin bahwa antara SO tidak bekerja secara ajaib seperti yang Anda tunjukkan. Diberikan visibilitas simbol dan bagaimana sering nama mangling bekerja, Anda mungkin lebih terisolasi dari masalah, tetapi mengompilasi satu .so dengan bendera yang berbeda / etc., Dan dengan asumsi Anda dapat menautkannya dalam suatu program dengan bendera lain adalah penerima bencana.
sdg
3
@ SDG: Dengan bendera standar dan visibilitas default berfungsi. Jika Anda mengubahnya dan mendapat masalah, itu masalah Anda dan bukan orang lain.
Jan Hudec

Jawaban:

20

Anda benar bahwa apa pun STL - sebenarnya, apa pun dari pustaka pihak ketiga mana pun yang templated - sebaiknya dihindari di sembarang API C ++ publik. Anda juga ingin mengikuti daftar panjang aturan di http://www.ros.org/reps/rep-0009.html#definition untuk menghambat kerusakan ABI yang menjadikan pemrograman publik C ++ API menjadi tugas.

Dan jawaban tentang C ++ 11 adalah tidak, standar ini tidak menyentuh itu. Lebih menarik kenapa tidak? Jawabannya adalah karena C ++ 17 sangat menyentuh itu, dan untuk C ++ Modul yang akan dilaksanakan kita perlu template yang diekspor untuk bekerja, dan untuk itu kita memerlukan kompiler tipe LLVM seperti dentang yang dapat membuang AST penuh ke disk dan kemudian lakukan pencarian tergantung-penelepon untuk menangani banyak kasus pelanggaran ODR di setiap proyek C ++ besar - yang, omong-omong, mencakup banyak kode GCC dan ELF.

Terakhir, saya melihat banyak kebencian MSVC dan komentar pro-GCC. Ini sangat salah informasi - GCC pada ELF pada dasarnya, dan tidak dapat diperbaiki lagi, tidak mampu menghasilkan kode C ++ yang valid dan benar. Alasannya banyak dan banyak, tetapi saya akan dengan cepat mengutip satu contoh kasus: GCC pada ELF tidak dapat dengan aman menghasilkan ekstensi Python yang ditulis menggunakan Boost.Python di mana lebih dari satu ekstensi berdasarkan Boost.Python dimuat ke Python. Itu karena ELF dengan tabel simbol C globalnya tidak mampu untuk mencegah pelanggaran ODR yang menyebabkan segfault, sedangkan PE dan MachO dan spesifikasi Modul C ++ yang diusulkan semuanya menggunakan tabel simbol per-modul - yang notabene juga berarti proses yang jauh lebih cepat di kali. Dan ada banyak masalah lagi: lihat StackOverflow saya jawab baru-baru ini dihttps://stackoverflow.com/questions/14268736/symbol-visibility-exceptions-runtime-error/14364055#14364055 misalnya di mana lemparan pengecualian C ++ secara fundamental diperbaiki pada ELF.

Poin terakhir: mengenai interoping berbagai STL, ini adalah rasa sakit yang besar bagi banyak pengguna perusahaan besar yang mencoba untuk menggabungkan perpustakaan pihak ketiga yang terintegrasi erat dengan beberapa implementasi STL. Satu-satunya solusi adalah mekanisme baru untuk C ++ untuk menangani STL interop, dan sementara mereka berada di sana Anda mungkin juga memperbaiki kompiler interop juga sehingga Anda dapat (misalnya) mencampur file objek yang dikompilasi MSVC, GCC dan dentang dan semuanya hanya berfungsi . Saya akan menonton upaya C ++ 17 dan melihat apa yang muncul di sana dalam beberapa tahun mendatang - saya akan terkejut jika tidak ada yang berhasil.

Niall Douglas
sumber
Respon yang bagus! Saya hanya berharap Clang meningkatkan kompatibilitas windows, dan mungkin menetapkan kompiler standar default yang bagus. Sistem inklusi / header teks dari C ++ mengerikan, saya menantikan hari ketika modul menyederhanakan organisasi kode C ++, mempercepat waktu kompilasi, dan meningkatkan interoperabilitas kompiler dengan tangkapan yang melanggar ODR.
Alessandro Stamatto
3
Secara pribadi, saya sebenarnya mengharapkan peningkatan substansial dalam waktu kompilator. Melintasi AST intra-modul dengan cepat sangat sulit, dan kita mungkin membutuhkan cache memori bersama dalam-memori. Namun, hampir semua hal lain yang buruk menjadi lebih baik. BTW, file header pasti tetap ada, modul C ++ saat ini memiliki file antarmuka memetakan 1-ke-1 untuk file header. Selain itu, file antarmuka yang dibuat secara otomatis akan menjadi C ++ legal, jadi header lawas hanya membuat makro C difilter dan dimuntahkan sebagai file antarmuka. Bagus kan?
Niall Douglas
Keren! Saya memiliki banyak keraguan tentang modul. Akankah sistem modul mempertimbangkan Inklusi Teks vs Inklusi Simbolik? Dengan direktif sekarang termasuk kompiler harus mengkompilasi ulang puluhan ribu baris kode berulang untuk setiap file sumber. Apakah sistem modul memungkinkan kode suatu hari tanpa deklarasi maju? Apakah akan meningkatkan / memudahkan alat bangunan?
Alessandro Stamatto
2
-1 untuk menyarankan bahwa semua templat pihak ketiga dicurigai. Mengubah konfigurasi tidak tergantung apakah hal yang sedang dikonfigurasikan adalah templat.
DeadMG
1
@Alessandro: Modul C ++ yang diusulkan secara eksplisit menonaktifkan makro C. Anda dapat menggunakan templat, atau nowt. Antarmuka yang diusulkan adalah legal C ++, hanya autogenerated, dan dapat secara opsional dikompilasi untuk kecepatan reparasi yaitu jangan berharap ada percepatan atas header yang sudah dikompilasi sebelumnya. Dua pertanyaan terakhir, saya sebenarnya tidak tahu: itu tergantung :)
Niall Douglas
8

Spesifikasi tidak pernah memiliki masalah ini. Itu karena ia memiliki konsep yang disebut "aturan satu definisi", yang mengamanatkan bahwa setiap simbol memiliki tepat satu definisi dalam proses yang sedang berjalan.

Windows DLL melanggar persyaratan ini. Itu sebabnya ada semua masalah ini. Jadi terserah Microsoft untuk memperbaikinya, bukan komite standardisasi C ++. Unix tidak pernah memiliki masalah ini, karena pustaka bersama bekerja secara berbeda di sana dan secara default sesuai dengan satu aturan definisi (Anda dapat secara eksplisit melanggarnya, tetapi Anda jelas hanya melakukannya jika Anda tahu Anda mampu dan perlu memeras beberapa siklus tambahan).

Windows DLL melanggar satu aturan definisi karena:

  • Mereka hardcode dari mana perpustakaan dinamis simbol akan digunakan selama waktu tautan statis dan menyelesaikan simbol secara statis di dalam perpustakaan yang mendefinisikan mereka. Jadi jika simbol lemah yang sama dihasilkan di beberapa pustaka bersama dan pustaka tersebut daripada digunakan dalam proses tunggal, penghubung dinamis tidak memiliki kesempatan untuk menggabungkan simbol-simbol itu. Biasanya simbol tersebut adalah anggota statis atau kelas hambatan dari contoh template dan itu menyebabkan masalah ketika melewati contoh antara kode dalam DLL yang berbeda.
  • Mereka meng-hardcode apakah simbol akan diimpor dari perpustakaan dinamis yang sudah ada selama kompilasi. Dengan demikian kode yang terhubung dengan beberapa pustaka secara statis tidak sesuai dengan kode yang ditautkan dengan pustaka yang sama secara dinamis.

Unix menggunakan ekspor format ELF secara implisit mengimpor semua simbol yang diekspor untuk menghindari masalah pertama dan tidak membedakan antara simbol yang diselesaikan secara statis dan dinamis hingga waktu tautan statis untuk menghindari yang kedua.


Masalah lainnya adalah flag compiler. Masalah itu ada untuk setiap program yang terdiri dari beberapa unit kompilasi, pustaka dinamis tidak harus terlibat. Namun itu jauh lebih buruk di Windows. Di Unix tidak masalah apakah Anda menautkan secara statis atau dinamis, tidak ada yang menautkan runtime standar secara statis (di Linux bahkan mungkin ilegal) dan tidak ada runtime debug khusus, sehingga satu build cukup bagus. Tetapi cara Microsoft menerapkan penghubung statis dan dinamis, debug, dan pelepasan runtime dan beberapa opsi lain berarti mereka menyebabkan ledakan kombinasi varian perpustakaan yang diperlukan. Sekali lagi masalah platform daripada masalah bahasa C ++.

Jan Hudec
sumber
2
@ DougT .: GCC tidak ada hubungannya dengan itu. Platform yang dimiliki ABI. Di ELF, format objek yang digunakan oleh sebagian besar Unices, pustaka bersama mengekspor semua simbol yang terlihat dan mengimpor semua simbol yang mereka ekspor. Jadi, jika sesuatu dihasilkan di banyak pustaka, penghubung dinamis akan menggunakan definisi pertama untuk semua. Sederhana, elegan, dan bekerja.
Jan Hudec
1
@ MartinBa: Tidak ada yang bisa digabung, tapi itu tidak masalah asalkan itu sama dan selama itu tidak seharusnya digabungkan. Ya, jika Anda menggunakan pengaturan kompiler yang tidak kompatibel pada platform ELF, Anda mendapatkan kekacauan yang sama seperti di mana saja dan di mana saja. Bahkan jika tidak menggunakan perpustakaan bersama, jadi agak di luar topik di sini.
Jan Hudec
1
@ Jan - ini relevan dengan jawaban Anda. Anda menulis: "... satu aturan definisi ... Windows DLL melanggar persyaratan ini ... pustaka bersama berfungsi berbeda [di UNix] ..." tetapi pertanyaan yang diajukan berkaitan dengan masalah dengan hal std-lib (didefinisikan dalam header) dan alasan tidak ada masalah pada Unix tidak ada hubungannya dengan SO vs DLL tetapi dengan fakta, bahwa pada Unix (tampaknya) hanya ada satu versi yang kompatibel dari perpustakaan standar sementara pada Windows MS memilih untuk memiliki versi yang tidak kompatibel (debug) (dengan pemeriksaan lanjutan dll.)
Martin Ba
1
@MartinBa: Tidak, alasan utama ada masalah pada Windows adalah bahwa mekanisme ekspor / impor yang digunakan pada Windows tidak dapat menggabungkan anggota statis dan kelas dengan benar dari kelas templat di semua kasus dan tidak dapat menggabungkan simbol yang terhubung secara statis dan dinamis. Daripada diperburuk oleh beberapa varian pustaka, tetapi masalah utamanya adalah C ++ membutuhkan fleksibilitas dari linker yang tidak dimiliki Windows dynamic linker.
Jan Hudec
4
Saya pikir ini implikasi bahwa spesifikasi DLL rusak dan permintaan yang sesuai untuk Msft untuk 'memperbaikinya' salah tempat. Fakta bahwa DLL tidak mendukung fitur-fitur tertentu dari C ++ bukanlah cacat dari spesifikasi DLL. DLL adalah bahasa-netral, mekanisme pengemasan vendor-netral dan ABI untuk mengekspos titik-titik masuk ke kode mesin ('panggilan fungsi') dan gumpalan data. Mereka tidak pernah dimaksudkan untuk secara asli mendukung fitur-fitur canggih dari bahasa tertentu. Itu bukan Msft, atau kesalahan spesifikasi DLL yang membuat beberapa orang menginginkannya menjadi sesuatu yang lain.
Euro Micelli
6

Tidak.

Ada banyak pekerjaan yang terjadi untuk mengganti sistem header, fitur yang disebut Modul dan yang dapat berdampak pada hal ini, tetapi tentu saja bukan yang besar.

Klaim
sumber
2
Saya tidak berpikir sistem header akan berdampak pada ini. Masalahnya adalah bahwa Windows DLL melanggar satu aturan definisi (yang berarti mereka tidak mengikuti spesifikasi C ++, jadi komite C ++ tidak dapat melakukan apa-apa tentang itu) dan bahwa ada begitu banyak varian runtime standar di Windows, yang mana komite C ++ dapat ' t melakukan apa pun tentang keduanya.
Jan Hudec
1
Tidak, mereka tidak. Bagaimana mungkin mereka, spesifikasinya bahkan tidak menyebutkan sesuatu seperti itu. Selain itu, ketika program (Windows) dihubungkan dengan Windows dll, ODR puas: semua simbol yang terlihat (diekspor) harus mematuhi ODR.
Paul Michalik
@PaulMichalik C ++ tidak mencakup penautan (fase 9) dan menurut saya setidaknya penautan waktu-beban DLL / SO berada dalam fase 9. Itu berarti bahwa simbol dengan tautan eksternal (apakah diekspor atau tidak) harus dihubungkan dan sesuai dengan ODR. Menghubungkan dinamis dengan LoadLibrary / dlopen jelas tidak termasuk dalam persyaratan tersebut.
bames53
@ bames53: IMHO, spesifikasi terlalu lemah untuk memungkinkan pernyataan seperti itu. Sebuah .dll / .so bisa dilihat sebagai "program" sendiri. Daripada, aturan dipenuhi. Sesuatu seperti memuat "program" lain pada saat run-time sangat underspecd oleh standar sehingga pernyataan tentang hal ini cukup sewenang-wenang.
Paul Michalik
@ PaulMichalik Jika sebuah executable memerlukan penautan waktu-load maka sebelum penautan waktu-buka ada entitas eksternal yang belum terselesaikan dan informasi yang diperlukan untuk eksekusi tidak ada. LoadLibrary dan dlopen berada di luar spec, tetapi waktu-tautan yang menghubungkan dengan jelas harus menjadi bagian dari fase 9.
bames53