C ++ ile ilgili birçok taşınabilirlik sorunu vardır, bunun nedeni sadece ikili düzeydeki standardizasyonunun olmamasıdır.
Bence bu kadar basit değil. Verilen cevaplar, standardizasyona odaklanmama konusunda mükemmel bir gerekçe oluşturuyor, ancak C ++, bir ABI standardı olarak C ile gerçekten rekabet etmek için çok uygun bir dil için çok zengin olabilir .
İşlev aşırı yüklemesi, değişken uyumsuzluklar, modül sınırlarını aşan istisnalarla uyumsuzluklardan vb. Kaynaklanan manglinge gidebiliriz. Bunların hepsi gerçek bir acıdır ve keşke en azından vtable düzenlerini standart hale getirebilseler.
Ancak bir ABI standardı sadece bir derleyicide üretilen C ++ boyacılarının farklı bir derleyici tarafından oluşturulan başka bir ikili dosya tarafından kullanılabilmesi anlamına gelmez. ABI çapraz diller kullanılır . En azından ilk kısmı kapsayabilirlerse iyi olur, ancak C ++ 'ın en yaygın uyumlu dylibs yapmak için çok önemli olan evrensel ABI seviyesinde C ile gerçekten rekabet ettiğini görmem mümkün değil.
Bu şekilde dışa aktarılan basit bir çift işlev düşünün:
void f(Foo foo);
void f(Bar bar, int val);
... ve parametreleştirilmiş kurucular, kopya kurucular, hareket kurucular ve önemsiz yıkıcılar içeren sınıflar hayal edin Foo
ve Bar
bunlardı.
Ardından bir Python / Lua / C # / Java / Haskell / etc senaryosunu alın. geliştirici bu modülü içe aktarmaya ve kendi dilinde kullanmaya çalışıyor.
Öncelikle, aşırı işlev yükünü kullanarak sembollerin nasıl dışa aktarılacağına ilişkin bir ad yönetim standardına ihtiyacımız var. Bu daha kolay bir bölüm. Yine de gerçekten "mangling" adı olmamalı. Dylib kullanıcılarının sembolleri ada göre aramaları gerektiğinden, buradaki aşırı yüklemeler tam bir karmaşaya benzemeyen isimlere yol açmalıdır. Belki sembol isimleri "f_Foo"
"f_Bar_int"
ya da buna benzer bir şey olabilir . Aslında geliştirici tarafından tanımlanmış bir adla çatışmayacaklarından emin olmalıyız, belki de ABI kullanımı için bazı sembolleri / karakterleri / kuralları saklıyorlar.
Ama şimdi daha zorlu bir senaryo. Örneğin Python geliştiricisi, hareket kurucuları, kopya kurucuları ve yıkıcıları nasıl çağırır? Belki bunları dylib'in bir parçası olarak ihraç edebiliriz. Peki ya farklı modüllerde dışa aktarılırsa Foo
ve Bar
dışa aktarılırsa? Bu dylib ile ilişkili sembolleri ve uygulamaları kopyalamalı mıyız? Yapmamızı öneririm, çünkü burada sadece bir nesne oluşturmak, buraya geçmek, oradan kopyalamak, yok etmek için birden fazla dylib arayüzüne karışmak zorunda kalmak gerçekten çok can sıkıcı olabilir. Aynı temel endişe C'de biraz daha geçerli olsa da (sadece daha manuel / açık bir şekilde), C bundan sadece insanların kendisiyle programlanma şekline bağlı olarak bundan kaçınma eğilimindedir.
Bu sadece garipliğin küçük bir örneğidir. f
Yukarıdaki işlevlerden biri BazException
JavaScript'e (ayrıca yapıcılar ve yıkıcılar ve std :: exception türetilmiş bir C ++ sınıfı) JavaScript'e attığında ne olur ?
En iyi ihtimalle sadece bir C ++ derleyicisi tarafından üretilen bir ikili dosyadan diğeri tarafından üretilen başka bir ikili dosyaya çalışan bir ABI'yi standartlaştırmayı umabileceğimizi düşünüyorum. Tabii ki bu harika olurdu, ama sadece bunu belirtmek istedim. Tipik olarak, çapraz derleyiciler çalıştıran genelleştirilmiş bir kütüphaneyi dağıtmak için bu tür endişelere eşlik etmek, onu genellikle genelleştirilmiş ve uyumlu çapraz diller haline getirme arzusudur.
Önerilen çözüm
COM tarzı arabirimlerle yıllarca API'ler / ABI'ler için C ++ arabirimlerini kullanmanın yollarını bulmaya çalıştıktan sonra önerdiğim çözüm, yalnızca bir "C / C ++" (pun) geliştiricisi olmaktır.
Uygulama için C ++ ile bu evrensel ABI'leri oluşturmak için C'yi kullanın. Yine de, yığın üzerinde bu tür nesneleri oluşturmak ve yok etmek için açık işlevlerle opak C ++ sınıflarına işaretçiler döndüren dışa aktarma işlevleri gibi şeyler yapabiliriz. Uygulama için tamamen C ++ kullanıyor olsak bile, ABI perspektifinden bu C estetiğine aşık olmaya çalışın. Soyut arayüzler fonksiyon göstergeleri tabloları kullanılarak modellenebilir. Bu şeyleri bir C API'sine sarmak sıkıcıdır, ancak bununla birlikte gelen dağıtımın faydaları ve uyumluluğu onu çok değerli hale getirecektir.
O zaman bu arayüzü bu kadar doğrudan kullanmaktan hoşlanmıyorsak (muhtemelen en azından RAII nedenleriyle olmamalıyız), SDK ile birlikte gönderdiğimiz statik olarak bağlı bir C ++ kütüphanesine istediğimiz her şeyi sarabiliriz. C ++ istemcileri bunu kullanabilir.
Python istemcileri, C veya C ++ arayüzünü doğrudan kullanmak istemeyecektir, çünkü bu pitoniği yapmanın bir yolu yoktur. Bunu kendi pitonik arayüzlerine sarmak isteyecekler, bu yüzden bunu mümkün olduğunca kolaylaştırmak için sadece minimum bir minimum C API / ABI ihraç ediyoruz.
C ++ endüstrisinin birçoğu, inatla COM tarzı arayüzler ve benzeri şeyler göndermeye çalışmak yerine bunu yapmaktan fayda sağlayacağını düşünüyorum. Bu dylibs kullanıcılarının garip ABI'lerle uğraşmak zorunda kalmaması da tüm hayatımızı kolaylaştırır. C bunu basitleştirir ve ABI perspektifinden sadeliği, her türlü FFI için doğal olarak ve minimalizmle çalışan API'ler / ABI'ler oluşturmamızı sağlar.