Paylaşılan nesneler (.so), statik kitaplıklar (.a) ve DLL'ler (.so) arasındaki fark nedir?


273

Linux'taki kütüphanelerle ilgili bazı tartışmalara katıldım ve bazı şeyleri doğrulamak istiyorum.

Anladığım kadarıyla (eğer yanlışsam lütfen düzeltin ve daha sonra yazımı düzenleyeceğim), bir uygulama oluştururken kütüphaneleri kullanmanın iki yolu vardır:

  1. Statik kitaplıklar (.a dosyaları): Bağlantı zamanında, kitaplığın içindeki işlevlerin her zaman çağıran uygulama tarafından kullanılabilmesi için tüm kitaplığın bir kopyası son uygulamaya yerleştirilir.
  2. Paylaşılan nesneler (.so dosyaları): Bağlantı zamanında nesne, ilgili başlık (.h) dosyası aracılığıyla API'sına göre doğrulanır. Kütüphane, gerekli olan çalışma zamanına kadar kullanılmaz.

Statik kütüphanelerin bariz avantajı, uygulamanın tamamının kendi içinde kalmasına izin vermesidir, dinamik kütüphanelerin yararı ise ".so" dosyasının değiştirilebilmesidir (yani: bir güvenlik nedeniyle güncellenmesi gerektiğinde) bug) temel uygulamanın yeniden derlenmesini gerektirmeden.

Her ikisi de ".so" dosyaları olmasına rağmen bazı kişilerin paylaşılan nesneler ve dinamik bağlantılı kütüphaneler (DLL) arasında bir ayrım yaptığını duydum. Linux'ta C / C ++ geliştirme veya POSIX uyumlu herhangi bir işletim sistemi (yani: MINIX, UNIX, QNX, vb.) Söz konusu olduğunda paylaşılan nesneler ve DLL'ler arasında herhangi bir ayrım var mı? Ben bir anahtar fark (şimdiye kadar) paylaşılan nesneler sadece çalışma zamanında kullanılan olduğunu söylenir, DLL ilk uygulama içinde dlopen () çağrısı kullanılarak açılması gerekir.

Son olarak, bazı geliştiricilerin, benim anlayışımla, aynı zamanda statik kütüphanelerin kendileri olan, ancak hiçbir zaman doğrudan bir uygulama tarafından kullanılmayan "paylaşılan arşivlerden" bahsettiklerini de duydum. Bunun yerine, diğer statik kütüphaneler, paylaşılan arşivden bazı (ancak hepsi değil) işlevleri / kaynakları oluşturulan statik kütüphaneye çekmek için "paylaşılan arşivlere" bağlanır.

Yardımınız için şimdiden teşekkür ederiz.

Güncelleme


Bu terimlerin bana sağlandığı bağlamda, Linux öğrenmek zorunda olan bir Windows geliştiricileri ekibi tarafından kullanılan hatalı terimlerdi. Onları düzeltmeye çalıştım, ancak (yanlış) dil normları sıkıştı.

  1. Paylaşılan Nesne: Program başladığında otomatik olarak bir programa bağlanan ve bağımsız bir dosya olarak var olan bir kütüphane. Kütüphane derleme zamanında bağlantı listesine dahil edilir (yani: LDOPTS+=-lmylibadlı bir kütüphane dosyası için mylib.so). Kitaplık derleme zamanında ve uygulama başladığında mevcut olmalıdır.
  2. Statik Kitaplık: Uygulama kodu ve program oluşturulduğunda otomatik olarak bir programa otomatik olarak bağlanan kütüphane kodu ve her ikisini içeren son ikili dosya için tek bir (daha büyük) uygulama için derleme sırasında gerçek programın kendisine birleştirilen kitaplık ana program ve kütüphanenin kendisi tek bir bağımsız ikili dosya olarak bulunur. Kütüphane derleme zamanında bağlantı listesine dahil edilir (yani: LDOPTS+=-lmylibmylib.a adlı bir kütüphane dosyası için). Kütüphane derleme zamanında hazır bulunmalıdır.
  3. DLL: Temelde paylaşılan bir nesne ile aynıdır, ancak derleme zamanında bağlantı listesine dahil olmak yerine, kütüphane dlopen()/ dlsym()komutları aracılığıyla yüklenir, böylece programın derlenmesi için kitaplığın derleme zamanında hazır olması gerekmez. Ayrıca, kütüphanenin uygulama başlangıcında veya derleme zamanında (zorunlu olarak) bulunması gerekmez , çünkü yalnızca dlopen/ dlsymçağrıları yapılırken gereklidir .
  4. Paylaşılan Arşiv: Temelde statik bir kütüphane ile aynıdır, ancak "dışa aktarma-paylaşımlı" ve "-fPIC" bayrakları ile derlenmiştir. Kütüphane derleme zamanında bağlantı listesine dahil edilir (yani: LDOPTS+=-lmylibSadlı bir kütüphane dosyası için mylibS.a). İkisi arasındaki fark, paylaşılan bir nesne veya DLL, paylaşılan arşivi statik olarak kendi koduna bağlamak istiyorsa ve paylaşılan nesnedeki işlevleri yalnızca bunları kullanmak yerine diğer programlar için kullanılabilir hale getirmek istiyorsa, bu ek bayrağın gerekli olmasıdır. dll için dahili. Bu, birisinin size statik bir kitaplık sağlaması ve bunu SO olarak yeniden paketlemek istediğinizde kullanışlıdır. Kütüphane derleme zamanında hazır bulunmalıdır.

Ek Güncelleme

" DLL" Ve " shared library" arasındaki ayrım , o zaman çalıştığım şirkette (tembel, yanlış) bir konuşma diliydi (Windows geliştiricileri Linux gelişimine geçmek zorunda kaldı ve sıkıştı terimi), yukarıda belirtilen açıklamalara bağlı olarak.

Ayrıca, S"paylaşılan arşivler" söz konusu olduğunda, kütüphane adından sonra gelen " " gerçek anlamında, genel olarak sektörde değil, yalnızca bu şirkette kullanılan bir konvansiyon vardı.


14
İçin .adosyalar "a" aslında "archove" anlamına gelir ve bu sadece nesne dosyalarının bir arşiv var. Modern bağlayıcılar while kütüphanesini dahil etmek zorunda kalmayacak kadar iyi olmalıdır, sadece arşivdeki gerekli olan nesne dosyaları ve hatta sadece başvurulan nesne dosyalarındaki kod / veri bölümlerini kullanabilir.
Bazı programcı dostum

4
DLL sadece Windows terminolojisidir. Unices üzerinde kullanılmaz.
R .. GitHub BUZA YARDIMCI DURDUR



2
@DevNull "arch i ve" tabii ki. :)
Bazı programcı dostum

Yanıtlar:


94

Her zaman DLL'lerin ve paylaşılan nesnelerin aynı şey için sadece farklı terimler olduğunu düşündüm - Windows DLL'leri çağırırken, UNIX sistemlerinde paylaşılan nesnelerdir, genel terim - dinamik olarak bağlı kütüphane - her ikisini de kapsayan ( UNIX'te bir .so açıldığında dlopen()'dinamik kütüphane' denir ).

Gerçekten de yalnızca uygulama başlangıcında bağlanırlar, ancak başlık dosyasına karşı doğrulama fikriniz yanlıştır. Başlık dosyası, kitaplığı kullanan kodu derlemek için gerekli olan prototipleri tanımlar, ancak bağlantı zamanında bağlayıcı, ihtiyaç duyduğu işlevlerin gerçekten orada olduğundan emin olmak için kitaplığın içine bakar. Bağlayıcı fonksiyon gövdelerini bağlantı sırasında bir yerde bulmalıdır, aksi takdirde bir hata ortaya çıkar. Aynı zamanda çalışma zamanında bunu yapar, çünkü haklı olarak işaret ettiğiniz gibi program derlendiğinden beri kütüphanenin kendisi değişmiş olabilir. Bu nedenle ABI kararlılığı platform kitaplıklarında çok önemlidir, çünkü ABI değişimi eski sürümlere karşı derlenen mevcut programları bozar.

Statik kütüphaneler, tıpkı projenizin derlemesinin bir parçası olarak kendinizi inşa ettiğiniz gibi, derleyiciden doğrudan nesne dosyaları demetidir, bu yüzden bağlayıcıya tam olarak aynı şekilde çekilir ve beslenirler ve kullanılmayan bitler aynı şekilde düştü.


1
Neden Linux'ta gördüğüm bazı projelerin ".so" dosyasındaki işlevlere erişmek için dlopen () çağrısını kullanması ve bazılarının bunu hiç yapması gerekmiyor? Bu arada teşekkür ederim!
Bulut

9
Bunu yapmayanlar, işlem yükleyici, yani linux'un elf yükleyicisi tarafından kendilerine verilen işlevleri alırlar. dlopen, uygulama bunu derlemede olmayan bir .so veya .dll dosyasını açmak ve kullanmak veya eklentiler gibi ek işlevler eklemek istiyorsa mevcuttur.
rapadura

Ancak .so derleme zamanında yoksa uygulama hiç derlenmeyecek mi? Bağlayıcıyı .so olmadan sadece son programı oluşturmaya zorlamak mümkün mü? Teşekkür ederim.
Bulut

1
Bunun .so işlevlerini nasıl kullandığınıza bağlı olduğuna inanıyorum, ama burada bu durma bilgim: / İyi sorular.
rapadura

1
Dlopen () ve işlev ailesi ile ilgili olarak, bu uygulamanın bir tüm dll boyunca belleğe yüklenmesine gerek kalmaması için programlı olarak bir dll açmak / kapatmak için kullanıldığını anlıyorum. Aksi takdirde, bağlayıcıya komut satırı argümanlarında (diğer bir deyişle makefile) kitaplığın yüklenmesini istediğinizi söylemelisiniz. Çalışma zamanında yüklenir ve uygulama çıkana kadar bellekte yüklü kalır. İşletim sistemi düzeyinde olabilecek daha fazla şey vardır, ancak uygulamanız söz konusu olduğunda kabaca olan şey budur.
Taylor Price

198

Bir statik kitaplığı (.a) bağlayıcı ile üretilen son yürütülebilir doğrudan bağlı olan bir kütüphane, içinde ihtiva edilmektedir ve yürütülebilir görevlendirilecek sisteme kütüphane için hiçbir sebep yoktur.

Bir paylaşılan kitaplık (nedenle) çalıştırılabilir başlatılır ve ihtiyaç yürütülebilir dağıtıldığında sistemde mevcut olduğu zaman çok yüklenir, bağlı ancak nihai çalıştırılabilir gömülü olmayan bir kütüphanedir.

Bir pencerelerde dinamik bağlantı kitaplığı (.dll) linux üzerinde paylaşılan kütüphane (bu nedenle) gibidir ama OS (Linux vs Windows) ile ilgili olarak iki uygulamaları arasında bazı farklar vardır:

Bir DLL iki tür işlev tanımlayabilir: dışa aktarılan ve iç. Dışa aktarılan işlevlerin, diğer modüller tarafından ve tanımlandıkları DLL içinden çağrılması amaçlanmıştır. Dahili işlevler genellikle yalnızca tanımlandıkları DLL içinden çağrılmak üzere tasarlanmıştır.

Linux üzerindeki bir SO kütüphanesi, dışa aktarılabilir sembolleri belirtmek için özel dışa aktarma ifadesine ihtiyaç duymaz, çünkü tüm semboller sorgulama işlemi için kullanılabilir.


1
+1 güzel basit açıklama. Bir işlevi, bir DLL içinde "Dahili" ilan edilirse o demek olamaz kütüphane dışında çağrılabilir?
Mike

23
Tüm sembollerin bir SO kütüphanesinde mevcut olduğu doğru değildir. Gizli semboller mümkündür ve önerilir çünkü kütüphane kullanıcılarının tüm sembollerinizi görmeleri için iyi bir neden yoktur.
Zan Lynx

3
FYI: g ++ __attribute__'ihracat' sembolleri için seçici bir sözdizimine sahiptir :#define DLLEXPORT __attribute__ ((visibility("default"))) #define DLLLOCAL __attribute__ ((visibility("hidden")))
Brian Haak

33

Bu gizemleri arkadaşlarıma * NIX-land'da açıklığa kavuşturmaya yardımcı olmak için Windows'daki DLL'lerin ayrıntılarını detaylandırabilirim ...

DLL, Paylaşılan Nesne dosyası gibidir. Her ikisi de ilgili işletim sisteminin program yükleyicisi tarafından belleğe yüklenmeye hazır görüntülerdir. Görüntüler, bağlayıcıların ve yükleyicilerin gerekli ilişkilendirmeleri yapmasına ve kod kitaplığını kullanmasına yardımcı olmak için çeşitli meta veri bitleriyle birlikte gelir.

Windows DLL dosyalarının bir dışa aktarma tablosu vardır. Dışa aktarmalar ada göre veya tablo konumuna göre (sayısal) olabilir. İkinci yöntem "eski okul" olarak kabul edilir ve çok daha kırılgandır - DLL'yi yeniden oluşturmak ve bir fonksiyonun tablodaki konumunu değiştirmek felaketle sonuçlanırken, giriş noktalarının bağlanması isimle ise gerçek bir sorun yoktur. Bu nedenle, bunu bir sorun olarak unutun, ancak 3. taraf satıcı kütüphaneleri gibi "dinozor" koduyla çalışıyorsanız orada olduğunu unutmayın.

Windows DLL'leri bir EXE (yürütülebilir uygulama) için yaptığınız gibi derleme ve bağlama yoluyla oluşturulur, ancak DLL'nin bir SO tarafından dinamik yükleme yoluyla veya bir uygulama tarafından kullanılması gerektiği gibi tek başına olmaması gerekir. bağlantı zamanı bağlama ile (SO'ya başvuru, uygulama ikili dosyasının meta verilerine gömülüdür ve OS program yükleyicisi başvurulan SO'ları otomatik olarak yükler). Tıpkı SO'lar diğer SO'lara başvurabileceği gibi, DLL'ler de diğer DLL'lere başvurabilir.

Windows'da, DLL'ler yalnızca belirli giriş noktalarını kullanılabilir hale getirir. Bunlara "ihracat" denir. Geliştirici, bir sembolü harici olarak görünür hale getirmek için özel bir derleyici anahtar sözcüğü kullanabilir (diğer bağlayıcılara ve dinamik yükleyiciye) veya dışa aktarma, DLL'nin kendisi olduğunda bağlantı zamanında kullanılan bir modül tanım dosyasında listelenebilir yaratıldı. Modern uygulama, sembol adını dışa aktarmak için fonksiyon tanımını anahtar kelimeyle dekore etmektir. Ayrıca, bu sembolün geçerli derleme biriminin dışındaki bir DLL'den içe aktarılacağını belirten anahtar sözcüklerle başlık dosyaları oluşturmak da mümkündür. Daha fazla bilgi için __declspec (dllexport) ve __declspec (dllimport) anahtar kelimelerine bakın.

DLL'lerin ilginç özelliklerinden biri, standart bir "yükleme / boşaltma" işleyici işlevi bildirebilmeleridir. DLL her yüklendiğinde veya kaldırıldığında, duruma göre bazı başlatma veya temizleme işlemleri gerçekleştirebilir. Bu, aygıt sürücüsü veya paylaşılan nesne arabirimi gibi nesne yönelimli bir kaynak yöneticisi olarak bir DLL'e sahip olmakla iyi bir şekilde eşleşir.

Bir geliştirici zaten oluşturulmuş bir DLL'i kullanmak istediğinde, DLL'i oluştururken DLL geliştiricisi tarafından oluşturulan bir "dışa aktarma kitaplığına" (* .LIB) başvurmalıdır veya DLL'i çalışma zamanında açıkça yüklemesi ve istemesi gerekir. LoadLibrary () ve GetProcAddress () mekanizmaları aracılığıyla adlarına göre giriş noktası adresi. Çoğu zaman, LIB dosyasına (yalnızca DLL'nin dışa aktarılan giriş noktaları için bağlayıcı meta verilerini içeren) bağlantı vermek DLL'lerin kullanım şeklidir. Dinamik yükleme genellikle program davranışlarında "polimorfizm" veya "çalışma zamanı yapılandırılabilirliği" (eklentilere veya daha sonra tanımlanmış işlevselliğe, diğer adıyla "eklentilere") uygulama için ayrılmıştır.

Windows'un bir şeyler yapmanın yolu bazen karışıklığa neden olabilir; sistem .LIB uzantısını hem normal statik kitaplıklara (POSIX * .a dosyaları gibi arşivler) hem de bir uygulamayı bağlantı zamanında bir DLL'e bağlamak için gereken "dışa aktarma koçanı" kitaplıklarına başvurmak için kullanır. Bu nedenle, bir * .LIB dosyasının aynı adlı * .DLL dosyasına sahip olup olmadığına her zaman bakılmalıdır; değilse, * .LIB dosyasının statik bir kütüphane arşivi olması ve bir DLL için bağlayıcı meta verilerini dışa aktarmaması ihtimali yüksektir.


4

Statik dosyaların bağlantı zamanında uygulamaya kopyalanması ve paylaşılan dosyaların bağlantı zamanında doğrulanması ve çalışma zamanında yüklenmesi konusunda haklısınız.

Dlopen çağrısı yalnızca paylaşılan nesneler için değildir, uygulama kendi adına çalışma zamanında bunu yapmak istiyorsa, aksi takdirde paylaşılan nesneler uygulama başladığında otomatik olarak yüklenir. DLL'ler ve .so aynı şeydir. dlopen, prosesler için daha da ince taneli dinamik yükleme kabiliyetleri eklemek için mevcuttur. Uygulama başlatma sırasında da gerçekleşen DLL'leri açmak / kullanmak için dlopen'i kullanmanız gerekmez.


Daha fazla yükleme kontrolü için dlopen () kullanımına örnek olarak ne gösterilebilir? SO / DLL başlangıçta otomatik olarak yüklenirse, dlopen () kapatır ve örneğin farklı izinler veya kısıtlamalarla yeniden açar mı? Teşekkür ederim.
Bulut

1
Ben dlopen eklentileri veya benzer işlevsellik için olduğuna inanıyorum. İzinler / kısıtlamalar otomatik yükleme ile aynı olmalıdır ve yine de bir dlopen bağımlı kütüphaneleri özyinelemeli olarak yükleyecektir.
rapadura

DLL ve .sovardır tam olarak aynı şey. Bu cevaba
Basile Starynkevitch
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.