Dinamik ve statik kitaplıklar ne zaman kullanılır?


Yanıtlar:


299

Statik kütüphaneler, ikili kodunuzdaki kodun boyutunu artırır. Her zaman yüklenir ve derlediğiniz kodun herhangi bir sürümü çalışacak kodun sürümüdür.

Dinamik kütüphaneler ayrı olarak saklanır ve versiyonlanır. Güncellemenin orijinal sürümle ikili olarak uyumlu olduğu kabul edilirse , dinamik kitaplığın bir sürümünün kodunuzla birlikte gönderilen orijinal olmayan yüklenmesi mümkündür .

Ayrıca, dinamik kitaplıklar mutlaka yüklenmez - genellikle ilk çağrıldığında yüklenir - ve aynı kitaplığı kullanan bileşenler arasında paylaşılabilir (birden çok veri yükü, bir kod yükü).

Dinamik kütüphaneler çoğu zaman daha iyi bir yaklaşım olarak kabul edildi, ancak başlangıçta daha yeni Windows işletim sistemleri (özellikle Windows XP) tarafından ortadan kaldırılan ancak büyük bir kusurları (google DLL cehennemi) vardı.


71
Windows / Mac'te (paket yöneticisi yok), dinamik kitaplıkları statik üzerinden kullanmak için gerçekten iyi bir neden yoktur. Windows DLL'leri yeniden yerleştirilemediğinden, kod paylaşımı genellikle çalışmaz (ve genellikle her uygulama yine de kütüphanenin kendi sürümlerini kullanır ve kullanır). Tek gerçek fayda, kütüphaneyi güncellemenin daha kolay olmasıdır.
Zifre

5
Mac'te çok sayıda dinamik kitaplık kullanıyorum. örneğin, mac os x'te sqlite3 gömme vardır. performans depolama için sqlite3 veritabanı özelliği olan bir program oluşturdum. Ancak, nadiren kullanıldığı için dinamik bağlantı derleme süresinde tasarruf sağlar, testi kolaylaştırır / hızlandırır, ancak bir yayın sürümü
oluştursaydım

6
@Zifre: relocatable = farklı sanal adrese yüklenebilir. DLL kesinlikle bunu destekler.
dma_k

20
@dma_k: Windows DLL'leri farklı adreslere yüklenebilir, ancak yalnızca bağlayıcı tüm kodu kopyalayıp adres numaralarını değiştirdiği için. Paylaşılan nesnelerde, tüm adres başvuruları görelidir, bu nedenle birden çok işlem paylaşılan nesne için aynı belleği paylaşabilir. Başka bir deyişle, Windows'ta, 3 program tarafından kullanılan 1 MB'lık bir DLL = 3 MB. Linux'ta 3 program tarafından kullanılan bir MB SO = 1 MB.
Zifre

7
Hem Windows hem de Linux, paylaşılan kitaplıkların yükü zaman içinde yer değiştirmesi kavramına sahiptir eli.thegreenplace.net/2011/08/25/… Bağımsız Konum Koduna izin veren en büyük şey Linux'a özel bir şey değildi, RIP'e göre adresleme eklendi x64 komut seti ile; hem Windows hem de Linux RIP göreli adreslemeden yararlanabilir ve kütüphanelerin yerini değiştirirken düzeltmelerin sayısını azaltır.
clemahieu

194

Diğerleri statik bir kitaplığın ne olduğunu yeterince açıkladı, ancak en azından Windows'da statik kitaplık kullanmanın bazı uyarılarına dikkat çekmek istiyorum:

  • Singletons: Bir şeyin global / statik ve benzersiz olması gerekiyorsa, statik bir kütüphaneye koymaya çok dikkat edin. Bu statik kütüphaneye birden fazla DLL bağlıysa, her biri kendi singleton kopyasını alır. Ancak, uygulamanız hiçbir özel DLL ile tek bir EXE ise, bu bir sorun olmayabilir.

  • Referans dışı kod kaldırma: Statik bir kütüphaneye bağlandığınızda , yalnızca statik kütüphanenin DLL / EXE tarafından başvurulan kısımları DLL / EXE'nize bağlanacaktır.

    Örneğin, eğer mylib.libiçeren a.objve b.objve DLL / EXE dosyalarınız yalnızca işlevlere veya değişkenlere başvuruyorsa a.obj, tamamı b.objbağlayıcı tarafından atılır. Eğer b.objküresel / statik nesneleri içeren, kendi kurucular ve yokediciler idam olmaz. Bu kurucuların / yıkıcıların yan etkileri varsa, yokluklarından hayal kırıklığına uğrayabilirsiniz.

    Benzer şekilde, statik kitaplık özel giriş noktaları içeriyorsa, bunların gerçekten dahil edilmesine dikkat etmeniz gerekebilir. Gömülü programlamada bunun bir örneği (tamam, Windows değil), belirli bir adreste olduğu belirtilen bir kesme işleyicisi olabilir. Ayrıca, atılmadığından emin olmak için kesme işleyicisini bir giriş noktası olarak işaretlemeniz gerekir.

    Bunun bir başka sonucu, statik bir kitaplığın, çözümlenemeyen başvurular nedeniyle tamamen kullanılamayan nesne dosyaları içerebilmesidir, ancak bu nesne dosyalarından bir işleve veya değişkene başvuru yapana kadar bir bağlayıcı hatasına neden olmaz. Bu kütüphane yazıldıktan çok sonra olabilir.

  • Hata ayıklama sembolleri: Her statik kitaplık için ayrı bir PDB isteyebilirsiniz veya hata ayıklama simgelerinin nesne dosyalarına yerleştirilmesini ve böylece DLL / EXE için PDB'ye aktarılmasını isteyebilirsiniz. Visual C ++ belgeleri gerekli seçenekleri açıklar .

  • RTTI:type_info Tek bir statik kitaplığı birden çok DLL'ye bağlarsanız , aynı sınıf için birden çok nesne kullanabilirsiniz. Programınız bunun type_info"singleton" verisi olduğunu varsayarsa &typeid()veya veya kullanırsa type_info::before(), istenmeyen ve şaşırtıcı sonuçlar alabilirsiniz.


23
Singleton'la ilgili noktaya gelince, bir DLL'in birden çok kez yüklenebileceğini (aynı sürüm veya çoklu sürümler) ve hala tek bir garanti olmadığını unutmayın.
Orion Adrian

Referans gösterilmeyen kod kaldırma hakkında ek nokta: DLL'lere yapılan çağrılar, başvurulan DLL dosyasının yüklenmesini zorlamak için gerçek bir çağrı gerektirir. Referans olarak eklemek, ancak referans veren herhangi bir çağrı içermemek, size hiçbir şey çağırmayan statik bir libary ile aynı sonucu verecektir. Tek fark, aslında neyin gönderildiği. Her iki durumda da statik yapıcılar ve yıkıcılar ateşlenmez.
Orion Adrian

@ bk1e Bu olmamalı. .a her zaman inşa edildiği tüm sembolleri içerecektir. Uygulamanıza statik olarak bağlandığında, evet yalnızca kullanılan semboller bağlanır.
Miles Rout

62

Bir lib, uygulamanızın yürütülebilir dosyası içinde paketlenmiş bir kod birimidir.

Bir dll bağımsız bir yürütülebilir kod birimidir. Bu koda yalnızca bir çağrı yapıldığında sürece yüklenir. Bir dll, birden çok uygulama tarafından kullanılabilir ve sabit sürücüde kodun yalnızca bir kopyasına sahipken birden çok işlemde yüklenebilir.

Dll artıları : birkaç ürün arasında kodu yeniden kullanmak / paylaşmak için kullanılabilir; talep üzerine işlem belleğine yüklenir ve ihtiyaç duyulmadığında boşaltılabilir; programın geri kalanından bağımsız olarak yükseltilebilir.

Dll eksileri : dll yükleme ve kod yeniden basma performans etkisi; sürüm sorunları ("dll cehennem")

Lib artıları : Kod her zaman süreçte yüklendiğinden ve yeniden temel alınmadığından performans etkisi yoktur; sürüm sorunu yok.

Lib eksileri : yürütülebilir / süreç "bloat" - tüm kod yürütülebilir dosyasındadır ve işlem başladıktan sonra yüklenir; yeniden kullanım / paylaşım yok - her ürünün kendi kod kopyası vardır.


Yeniden oluşturma ayrıca rebase.exe kullanarak veya link.exe'ye / BASE seçeneğini geçerek de yapılabilir. Bunun etkili olup olmadığı, çalışma zamanında beklenmedik adres alanı çakışmaları olup olmadığına bağlıdır.
bk1e

24

Statik ve dinamik kitaplıkların teknik sonuçlarının yanı sıra (statik dosyalar, birçok farklı yürütülebilir dosya arasında kod paylaşımına izin veren bir büyük ikili ve dinamik kitaplıklardaki her şeyi bir araya getirir), yasal sonuçları vardır .

Örneğin, LGPL lisanslı kod kullanıyorsanız ve statik olarak bir LGPL kitaplığına bağlarsanız (ve böylece bir büyük ikili dosya oluşturursanız), kodunuz otomatik olarak Açık Kaynaklı ( özgürlükte olduğu gibi ücretsiz) LGPL kodu haline gelir . Paylaşılan nesnelere bağlanırsanız, LGPL kitaplığının kendisine yaptığınız iyileştirmeleri / hata düzeltmelerini yapmanız yeterlidir.

Örneğin mobil uygulamalarınızı nasıl derleyeceğinize karar verirseniz, bu çok daha önemli bir sorun haline gelir (Android'de statik ve dinamik seçenekleriniz vardır, iOS'ta yoktur - her zaman statiktir).


23

C ++ programları iki aşamada oluşturulmuştur

  1. Derleme - nesne kodu (.obj) üretir
  2. Bağlama - yürütülebilir kod üretir (.exe veya .dll)

Statik kütüphane (.lib) sadece .obj dosyalarının bir paketidir ve bu nedenle tam bir program değildir. Bir program oluşturmanın ikinci (bağlantı) aşamasına geçmedi. Dll, diğer taraftan, exe gibidir ve bu nedenle tam programlar.

Statik bir kitaplık oluşturursanız, henüz bağlanmamıştır ve bu nedenle statik kitaplığınızın tüketicileri kullandığınızla aynı derleyiciyi kullanmalıdır (g ++ kullandıysanız, g ++ kullanmaları gerekir).

Bunun yerine bir dll oluşturduysanız (ve doğru şekilde oluşturduysanız ), hangi derleyiciyi kullanıyor olursa olsun, tüm tüketicilerin kullanabileceği eksiksiz bir program oluşturdunuz. Çapraz derleyici uyumluluğu isteniyorsa, bir dll dışa aktarma konusunda çeşitli kısıtlamalar vardır.


1
Bu benim için bir haber. DLL'leri kullanırken çapraz derleyicilerde ne gibi kısıtlamalar vardır? Aynı araç zincirine ihtiyaç duymadan programcı oluşturmak, DLL'ler için büyük bir artı gibi görünüyor
Dan

1
Bu cevap bilgilendiricidir. Küçük uyarı ekleme: consumers of your static library will have to use the same compiler that you usedstatik kitaplık gibi C ++ kitaplığı kullanıyorsa #include <iostream>.
truthadjustr

aynı derleyici kullanılmadıkça bir c ++ dll tüketemez (standart c ++ abi olmadığından, semboller farklı şekillerde karıştırılır). Hem dll hem de istemci modülü aynı derleyici ve aynı derleme ayarlarını kullanmalıdır
kcris

19

Statik kütüphane oluşturma

$$:~/static [32]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/static [33]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H

void foo();

#endif
$$:~/static [34]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/static [35]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H

void foo2();

#endif
$$:~/static [36]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/static [37]> cat makefile
hello: hello.o libtest.a
        cc -o hello hello.o -L. -ltest
hello.o: hello.c
        cc -c hello.c -I`pwd`
libtest.a:foo.o foo2.o
        ar cr libtest.a foo.o foo2.o
foo.o:foo.c
        cc -c foo.c
foo2.o:foo.c
        cc -c foo2.c
clean:
        rm -f foo.o foo2.o libtest.a hello.o

$$:~/static [38]>

dinamik bir kütüphane oluşturma

$$:~/dynamic [44]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/dynamic [45]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H

void foo();

#endif
$$:~/dynamic [46]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/dynamic [47]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H

void foo2();

#endif
$$:~/dynamic [48]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/dynamic [49]> cat makefile
hello:hello.o libtest.sl
        cc -o hello hello.o -L`pwd` -ltest
hello.o:
        cc -c -b hello.c -I`pwd`
libtest.sl:foo.o foo2.o
        cc -G -b -o libtest.sl foo.o foo2.o
foo.o:foo.c
        cc -c -b foo.c
foo2.o:foo.c
        cc -c -b foo2.c
clean:
        rm -f libtest.sl foo.o foo

2.o hello.o
$$:~/dynamic [50]>

13

Statik bir kütüphane istemciye derlenir. Derleme sırasında bir .lib kullanılır ve kitaplığın içeriği tüketilen yürütülebilir dosyanın bir parçası haline gelir.

Dinamik bir kütüphane çalışma zamanında yüklenir ve istemci yürütülebilir dosyasına derlenmez. Birden çok istemci yürütülebilir dosyası bir DLL dosyasını yükleyebildiğinden ve işlevselliğini kullanabildiğinden dinamik kitaplıklar daha esnektir. Bu, istemci kodunuzun genel boyutunu ve sürdürülebilirliğini de minimumda tutar.


13

Zaman içindeki değişiklikler, sürüm oluşturma, kararlılık, uyumluluk vb. Hakkında dikkatlice düşünmelisiniz.

Paylaşılan kodu kullanan iki uygulama varsa, birbirleriyle uyumlu olmaları gerektiğinde bu uygulamaları birlikte değiştirmeye zorlamak ister misiniz? Sonra dll kullanın. Tüm exe'ler aynı kodu kullanacaktır.

Yoksa bunları birbirinden izole etmek mi istiyorsunuz, böylece birini değiştirebilir ve diğerini kırmadığınızdan emin olabilirsiniz. Ardından statik lib kullanın.

DLL cehennem muhtemelen statik bir lib kullanmış olmalısınız, ancak bunun yerine bir dll kullandınız ve tüm exes onunla comaptible değildir.


9

Statik bir kütüphane son çalıştırılabilir dosyaya bağlanmalıdır; çalıştırılabilir dosyanın bir parçası olur ve gittiği her yerde onu takip eder. Yürütülebilir dosya yürütüldüğünde dinamik kitaplık yüklenir ve yürütülebilir dosyadan DLL dosyası olarak ayrı kalır.

Yürütülebilir dosyayı yeniden bağlamak zorunda kalmadan kitaplık tarafından sağlanan işlevselliği değiştirmek istediğinizde bir DLL kullanabilirsiniz (yürütülebilir dosyayı değiştirmek zorunda kalmadan yalnızca DLL dosyasını değiştirin).

Dinamik kitaplık kullanma nedeniniz olmadığında statik kitaplık kullanırsınız.


Birden fazla uygulama aynı işlevi kullandığında bir DLL de kullanabilirsiniz - bu, kapladığı alanı azaltabilir.
Tim

Ayrıca, daha sonra yeniden oluşturmak veya yeniden yayınlamak zorunda kalmadan eklenmiş / bilinmeyen işlevselliğe izin vermek istediğiniz ilk konsept olan "eklenti" mimarisini genişletmek, yalnızca dinamik kütüphanelerle yapılabilir.
Tim

8

Ulrich Drepper'ın " Paylaşılan Kitaplıkların Yazılması" konulu makalesi de, paylaşılan kitaplıklardan en iyi nasıl yararlanılacağını veya "Dinamik Paylaşılan Nesneler" (DSO) olarak adlandırdığı şeyleri ayrıntılarıyla anlatan iyi bir kaynaktır. Daha çok ELF ikili biçimindeki paylaşılan kitaplıklara odaklanır , ancak bazı tartışmalar Windows DLL'leri için de uygundur.



4

Gerçekten yaptığınız işlem (büyük bir projede) ilk yükleme süresinde, kütüphaneler bir seferde birbirine bağlanacak, yapılması gereken karar, derleyicinin ihtiyaç duyduğu kadar uzun sürecek bağlantı mermi ısırmak ve önden yapmak için, ya da dinamik bağlayıcı bunu yükleme zamanında yapabilir.


3

Kitaplığınız birkaç yürütülebilir dosya arasında paylaşılacaksa, yürütülebilir dosyaların boyutunu azaltmak için dinamik hale getirmek genellikle mantıklıdır. Aksi takdirde, kesinlikle statik hale getirin.

Bir dll kullanmanın birkaç dezavantajı vardır. Yükleme ve boşaltma için ek yük vardır. Ayrıca ek bir bağımlılık var. Eğer dll executalbes ile uyumsuz yapmak için değiştirirseniz, onlar çalışma durur. Öte yandan, statik bir kitaplığı değiştirirseniz, eski sürümü kullanan derlenmiş yürütülebilir dosyalarınız etkilenmez.


3

Kütüphane statik ise, bağlantı sırasında kod çalıştırılabilir öğenize bağlanır. Bu, yürütülebilir dosyanızı büyütür (dinamik rotaya gittiğinizden daha).

Kütüphane dinamikse, bağlantı sırasında gerekli yöntemlere yapılan başvurular yürütülebilir dosyaya yerleştirilir. Bu, yürütülebilir dosyanızı ve dinamik kitaplığı göndermeniz gerektiği anlamına gelir. Ayrıca, kitaplıktaki koda paylaşılan erişimin güvenli, tercih edilen yükleme adresi olup olmadığını da göz önünde bulundurmalısınız.

Statik kitaplıkla yaşayabiliyorsanız, statik kitaplığa gidin.


3

Projemizde çok sayıda DLL (> 100) kullanıyoruz. Bu DLL'lerin birbirlerine bağımlılıkları vardır ve bu nedenle dinamik bağlantı kurulumunu seçtik. Bununla birlikte, aşağıdaki dezavantajlara sahiptir:

  • yavaş başlatma (> 10 saniye)
  • Windows modülleri adların benzersizliği üzerine yüklediğinden DLL'lerin sürümlendirilmesi gerekiyordu. Kendi yazılı bileşenleri aksi takdirde DLL yanlış sürümünü (yani kendi dağıtılmış kümesi yerine zaten yüklü olan) alacak
  • optimizer yalnızca DLL sınırları içinde optimizasyon yapabilir. Örneğin, iyileştirici sık kullanılan veri ve kodu yan yana yerleştirmeye çalışır, ancak bu DLL sınırları boyunca çalışmaz

Belki daha iyi bir kurulum, her şeyi statik bir kütüphane yapmaktı (ve bu nedenle sadece bir yürütülebilir dosya var). Bu, yalnızca kod çoğaltma yapılmazsa çalışır. Bir test bu varsayımı destekliyor gibi görünüyor, ancak resmi bir MSDN teklifi bulamadım. Yani örneğin 1 exe yapın:

  • exe paylaşılan_lib1, paylaşılan_lib2 kullanır
  • shared_lib1 kullanımı shared_lib2
  • shared_lib2

Shared_lib2 kodu ve değişkenleri son birleştirilmiş yürütülebilir dosyada yalnızca bir kez bulunmalıdır. Bu soruyu kimse destekleyebilir mi?


Kod çoğaltmasını önlemek için derleyici öncesi bazı yönergeleri kullanmak istemiyor musunuz?
Paceman

Afaiac ön derleme sadece modül başına (exe / dll / lib) bazda çalışır. Ön derleme öncelikle derlemeyi hızlandırmak içindir, ancak bir derleme birimi içinde birden fazla kapanmayı da önler. Ancak korumalar bu etkiyi elde etmenin daha iyi bir yoludur.
gast128

2

Statik kitaplıklar, kodun yürütülebilir dosyaya derlendiği bir uygulamaya bağlandığında kitaplığın nesne kodunu içeren arşivlerdir. Paylaşılan kitaplıklar, yürütülebilir dosyada derlenmemesi bakımından farklıdır. Bunun yerine dinamik bağlayıcı, ihtiyaç duyduğu kütüphaneyi / kütüphaneleri arayan bazı dizinleri arar ve bunu belleğe yükler. Birden fazla yürütülebilir dosya aynı anda aynı paylaşılan kütüphaneyi kullanabilir ve böylece bellek kullanımını ve yürütülebilir boyutu azaltabilir. Ancak, yürütülebilir dosyayla birlikte dağıtılacak daha fazla dosya vardır. Kütüphanenin, bağlayıcının bulabileceği bir yerde kullanım sistemine yüklendiğinden emin olmanız gerekir, statik bağlantı bu sorunu ortadan kaldırır, ancak daha büyük bir yürütülebilir dosyaya neden olur.


2

Gömülü projeler veya özel platformlar üzerinde çalışıyorsanız, statik kütüphaneler tek yoluysa, çoğu zaman uygulamanızda derleme zorluğu da azalır. Ayrıca, her şeyi içeren projeler ve makefile sahip olmak hayatı mutlu eder.


2

Genel bir kural olarak, tümünün daha düşük düzeyli kitaplıkların (örn. Utils veya Gui çerçevesi) üzerine kurulmuş, daha sonra yönetilebilir kitaplıklara bölmek ve bunları statik kitaplıklar haline getirmek istediğinizde genel bir kural veririm. Dinamik kütüphaneler size gerçekten hiçbir şey satın almaz ve daha az sürpriz vardır - örneğin yalnızca bir tane singleton örneği olacaktır.

Eğer tamamen kod temeli geri kalanı için ayrı bir kütüphane (örneğin bir üçüncü taraf kütüphane) varsa o zaman bir dll yapmayı düşünün. Kütüphane LGPL ise, lisans koşulları nedeniyle yine de bir dll kullanmanız gerekebilir.

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.