Ada banyak masalah portabilitas dengan C ++, yang hanya karena kurangnya standarisasi di tingkat biner.
Saya tidak berpikir ini sesederhana ini. Jawaban yang diberikan sudah memberikan dasar pemikiran yang sangat baik tentang kurangnya fokus pada standardisasi, tetapi C ++ mungkin terlalu kaya bahasa sehingga tidak cocok untuk benar-benar bersaing dengan C sebagai standar ABI.
Kita dapat menggunakan nama mangling yang dihasilkan dari fungsi yang berlebihan, ketidakcocokan vtable, ketidakcocokan dengan pengecualian yang melintasi batas-batas modul, dll. Semua ini benar-benar menyusahkan, dan saya berharap mereka setidaknya bisa menstandardisasi tata letak vtable.
Tetapi standar ABI bukan hanya tentang membuat C ++ dylibs yang diproduksi dalam satu kompiler yang mampu digunakan oleh biner lain yang dibangun oleh kompiler yang berbeda. ABI digunakan lintas bahasa . Akan lebih baik jika mereka setidaknya bisa membahas bagian pertama, tetapi tidak ada cara saya melihat C ++ benar-benar bersaing dengan C pada tingkat ABI universal yang sangat penting untuk membuat dylib yang paling kompatibel secara luas.
Bayangkan sepasang fungsi sederhana yang diekspor seperti ini:
void f(Foo foo);
void f(Bar bar, int val);
... dan bayangkan Foo
dan Bar
adalah kelas-kelas dengan konstruktor berparameter, menyalin konstruktor, memindahkan konstruktor, dan destruktor non-sepele.
Kemudian ambil skenario dari Python / Lua / C # / Java / Haskell / etc. pengembang mencoba mengimpor modul ini dan menggunakannya dalam bahasa mereka.
Pertama kita akan membutuhkan standar nama mangling untuk cara mengekspor simbol menggunakan fungsi overloading. Ini adalah bagian yang lebih mudah. Namun seharusnya tidak benar-benar menjadi nama "mangling". Karena pengguna dylib harus mencari simbol berdasarkan nama, kelebihan di sini harus mengarah ke nama yang tidak terlihat berantakan. Mungkin nama simbolnya bisa seperti itu "f_Foo"
"f_Bar_int"
atau semacamnya. Kami harus memastikan mereka tidak dapat berbenturan dengan nama yang sebenarnya ditentukan oleh pengembang, mungkin menyimpan beberapa simbol / karakter / konvensi untuk penggunaan ABI.
Tapi sekarang skenario yang lebih sulit. Bagaimana pengembang Python, misalnya, memanggil konstruktor bergerak, menyalin konstruktor, dan destruktor? Mungkin kita bisa mengekspornya sebagai bagian dari dylib. Tetapi bagaimana jika Foo
dan Bar
diekspor dalam modul yang berbeda? Haruskah kita menduplikasi simbol dan implementasi yang terkait dengan dylib ini atau tidak? Saya sarankan kita lakukan, karena mungkin sangat menjengkelkan sangat cepat kalau tidak untuk mulai harus terlibat dalam beberapa antarmuka dylib hanya untuk membuat objek di sini, kirimkan di sini, salin di sana, hancurkan di sini. Sementara perhatian dasar yang sama agak dapat diterapkan dalam C (hanya lebih secara manual / eksplisit), C cenderung menghindari ini hanya karena sifat cara orang memprogram dengannya.
Ini hanyalah contoh kecil dari kecanggungan. Apa yang terjadi ketika salah satu f
fungsi di atas melempar BazException
(juga kelas C ++ dengan konstruktor dan destruktor dan menurunkan std :: exception) ke dalam JavaScript?
Paling-paling saya pikir kita hanya bisa berharap untuk membakukan ABI yang bekerja dari satu biner yang dihasilkan oleh satu kompiler C ++ ke biner lain yang diproduksi oleh yang lain. Itu akan bagus, tentu saja, tetapi saya hanya ingin menunjukkan ini. Biasanya menyertai masalah seperti itu untuk mendistribusikan perpustakaan umum yang bekerja lintas-kompiler juga sering keinginan untuk membuatnya benar-benar umum dan lintas-bahasa yang kompatibel.
Solusi yang Disarankan
Solusi saya yang disarankan setelah berjuang untuk menemukan cara untuk menggunakan antarmuka C ++ untuk API / ABI selama bertahun-tahun dengan antarmuka gaya COM adalah menjadi pengembang "C / C ++" (pun).
Gunakan C untuk membuat ABI universal tersebut, dengan C ++ untuk implementasinya. Kita masih bisa melakukan hal-hal seperti fungsi ekspor yang mengembalikan pointer ke kelas C ++ yang buram dengan fungsi eksplisit untuk membuat dan menghancurkan objek seperti itu di heap. Cobalah untuk jatuh cinta dengan estetika C itu dari perspektif ABI bahkan jika kita benar-benar menggunakan C ++ untuk implementasinya. Antarmuka abstrak dapat dimodelkan menggunakan tabel pointer fungsi. Sangat membosankan untuk membungkus barang-barang ini menjadi C API, tetapi manfaat dan kompatibilitas distribusi yang menyertainya akan cenderung membuatnya sangat berharga.
Kemudian jika kita tidak suka menggunakan antarmuka ini secara langsung (kita mungkin tidak seharusnya setidaknya karena alasan RAII), kita dapat membungkusnya semua yang kita inginkan di pustaka C ++ yang terhubung secara statis yang kami kirimkan dengan SDK. Klien C ++ dapat menggunakannya.
Klien Python tidak ingin menggunakan antarmuka C atau C ++ secara langsung karena tidak ada cara untuk membuat pythonique tersebut. Mereka ingin membungkusnya dengan antarmuka pythonique mereka sendiri, jadi sebenarnya hal yang baik bahwa kita hanya mengekspor minimum C API / ABI untuk membuatnya semudah mungkin.
Saya pikir banyak industri C ++ akan mendapat manfaat dari melakukan ini lebih daripada mencoba keras kepala mengirimkan antarmuka gaya COM dan sebagainya. Itu juga akan membuat seluruh hidup kita lebih mudah karena pengguna dylibs ini tidak perlu repot dengan ABI yang canggung. C membuatnya sederhana, dan kesederhanaan dari perspektif ABI memungkinkan kita untuk membuat API / ABI yang bekerja secara alami dan dengan minimalisme untuk semua jenis FFI.