Podczas tworzenia biblioteki klas w C ++ możesz wybierać między bibliotekami dynamicznymi ( .dll
, .so
) i statycznymi ( .lib
, .a
). Jaka jest różnica między nimi i kiedy należy użyć której?
c++
dll
shared-libraries
static-linking
dynamic-linking
Morten Christiansen
źródło
źródło
Odpowiedzi:
Biblioteki statyczne zwiększają rozmiar kodu w pliku binarnym. Są zawsze ładowane, a dowolna wersja skompilowanego kodu jest wersją kodu, który zostanie uruchomiony.
Biblioteki dynamiczne są przechowywane i wersjonowane osobno. Możliwe jest załadowanie wersji biblioteki dynamicznej, która nie była oryginalną wersją dostarczoną z Twoim kodem, jeśli aktualizacja zostanie uznana za binarnie zgodną z wersją oryginalną.
Ponadto biblioteki dynamiczne niekoniecznie są ładowane - zwykle są ładowane przy pierwszym wywołaniu - i mogą być współużytkowane przez komponenty korzystające z tej samej biblioteki (wiele ładowań danych, jedno ładowanie kodu).
Biblioteki dynamiczne były przez większość czasu uważane za lepsze podejście, ale pierwotnie miały poważną wadę (piekło DLL Google), która została prawie całkowicie wyeliminowana przez nowsze systemy operacyjne Windows (w szczególności Windows XP).
źródło
Inni odpowiednio wyjaśnili, czym jest biblioteka statyczna, ale chciałbym zwrócić uwagę na niektóre zastrzeżenia dotyczące korzystania z bibliotek statycznych, przynajmniej w systemie Windows:
Singletony: Jeśli coś musi być globalne / statyczne i niepowtarzalne, należy bardzo uważać na umieszczenie go w bibliotece statycznej. Jeśli wiele bibliotek DLL jest połączonych z tą statyczną biblioteką, każda z nich otrzyma własną kopię singletonu. Jeśli jednak twoja aplikacja to pojedynczy plik EXE bez niestandardowych bibliotek DLL, może to nie stanowić problemu.
Usuwanie kodu bez odniesień: Podczas łączenia z biblioteką statyczną tylko części biblioteki statycznej, do których odwołuje się biblioteka DLL / EXE, zostaną połączone z biblioteką DLL / EXE.
Na przykład, jeśli
mylib.lib
zawiera,a.obj
ab.obj
twoja biblioteka DLL / EXE odwołuje się tylko do funkcji lub zmiennycha.obj
, całośćb.obj
zostanie odrzucona przez linker. Jeślib.obj
zawiera obiekty globalne / statyczne, ich konstruktory i destruktory nie zostaną wykonane. Jeśli ci konstruktorzy / destruktory mają skutki uboczne, możesz być rozczarowany ich nieobecnością.Podobnie, jeśli biblioteka statyczna zawiera specjalne punkty wejścia, może być konieczne zadbanie o to, aby były one uwzględnione. Przykładem tego w programowaniu wbudowanym (w porządku, nie w systemie Windows) może być moduł obsługi przerwań oznaczony jako znajdujący się pod określonym adresem. Musisz także zaznaczyć moduł obsługi przerwań jako punkt wejścia, aby upewnić się, że nie zostanie odrzucony.
Inną konsekwencją tego jest to, że biblioteka statyczna może zawierać pliki obiektowe, które są całkowicie bezużyteczne z powodu nierozwiązanych odwołań, ale nie spowoduje to błędu linkera, dopóki nie odwołasz się do funkcji lub zmiennej z tych plików obiektowych. Może się to zdarzyć długo po napisaniu biblioteki.
Symbole debugowania: Możesz chcieć osobnego PDB dla każdej biblioteki statycznej lub możesz chcieć, aby symbole debugowania były umieszczane w plikach obiektowych, aby były one wtaczane do PDB dla DLL / EXE. Dokumentacja Visual C ++ wyjaśnia niezbędne opcje .
RTTI: Możesz skończyć z wieloma
type_info
obiektami dla tej samej klasy, jeśli połączysz jedną bibliotekę statyczną z wieloma bibliotekami DLL. Jeśli twój program zakłada, żetype_info
są to dane „singleton” i wykorzystuje&typeid()
lubtype_info::before()
, możesz uzyskać niepożądane i zaskakujące wyniki.źródło
Lib to jednostka kodu zawarta w pliku wykonywalnym aplikacji.
Dll jest samodzielną jednostką kodu wykonywalnego. Jest on ładowany w procesie tylko wtedy, gdy do tego kodu zostanie wywołane wywołanie. Biblioteka DLL może być używana przez wiele aplikacji i ładowana w wielu procesach, a jednocześnie ma tylko jedną kopię kodu na dysku twardym.
Dll pros : może być użyty do ponownego użycia / współdzielenia kodu między kilkoma produktami; ładowanie do pamięci procesu na żądanie i może być rozładowane, gdy nie jest potrzebne; można zaktualizować niezależnie od reszty programu.
Wady dll : wpływ na ładowanie dll i zmiany kodu; problemy z wersjonowaniem („dll hell”)
Lib plus : brak wpływu na wydajność, ponieważ kod jest zawsze ładowany w procesie i nie jest ponownie bazowany; brak problemów z wersjonowaniem.
Lib Cons : plik wykonywalny / proces „wzdęcia” - cały kod znajduje się w pliku wykonywalnym i jest ładowany przy uruchomieniu procesu; bez ponownego użycia / udostępniania - każdy produkt ma własną kopię kodu.
źródło
Oprócz technicznych implikacji bibliotek statycznych vs. dynamicznych (pliki statyczne zawierają wszystko w jednej dużej bibliotece binarnej vs. dynamicznej, które umożliwiają współdzielenie kodu między kilkoma różnymi plikami wykonywalnymi), istnieją implikacje prawne .
Na przykład, jeśli korzystasz z kodu licencjonowanego LGPL i łączysz się statycznie z biblioteką LGPL (i w ten sposób tworzysz jeden duży plik binarny), Twój kod automatycznie staje się Open Sourced ( darmowy jak na wolności) kodem LGPL typu . Jeśli łączysz się z obiektami współużytkowanymi, musisz tylko LGPL ulepszeń / poprawek błędów, które wprowadziłeś do samej biblioteki LGPL.
Staje się to o wiele ważniejszym problemem, jeśli decydujesz na przykład, jak skompilować swoje aplikacje mobilne (w Androidzie masz wybór statyczny vs dynamiczny, w iOS nie - zawsze jest statyczny).
źródło
Programy C ++ są zbudowane w dwóch fazach
Biblioteka statyczna (.lib) jest tylko pakietem plików .obj i dlatego nie jest kompletnym programem. Nie przeszedł on drugiej (łączącej) fazy budowania programu. Z drugiej strony biblioteki DLL są podobne do plików exe i dlatego są kompletnymi programami.
Jeśli zbudujesz bibliotekę statyczną, nie jest ona jeszcze połączona i dlatego konsumenci twojej biblioteki statycznej będą musieli użyć tego samego kompilatora, którego użyłeś (jeśli użyłeś g ++, będą musieli użyć g ++).
Jeśli zamiast tego zbudowałeś bibliotekę DLL (i poprawnie ją zbudowałeś ), zbudowałeś kompletny program, z którego mogą korzystać wszyscy konsumenci, bez względu na to, jakiego kompilatora używają. Istnieje jednak kilka ograniczeń dotyczących eksportu z biblioteki dll, jeśli wymagana jest kompatybilność z wieloma kompilatorami.
źródło
consumers of your static library will have to use the same compiler that you used
jeśli biblioteka statyczna korzysta z biblioteki C ++, takiej jak#include <iostream>
.Tworzenie biblioteki statycznej
tworzenie biblioteki dynamicznej
źródło
Biblioteka statyczna jest kompilowana do klienta. Plik .lib jest używany podczas kompilacji, a zawartość biblioteki staje się częścią konsumującego pliku wykonywalnego.
Biblioteka dynamiczna jest ładowana w czasie wykonywania i nie jest kompilowana w pliku wykonywalnym klienta. Biblioteki dynamiczne są bardziej elastyczne, ponieważ wiele plików wykonywalnych klienta może załadować bibliotekę DLL i wykorzystać jej funkcjonalność. Dzięki temu ogólny rozmiar i łatwość konserwacji kodu klienta są minimalne.
źródło
Powinieneś dokładnie przemyśleć zmiany w czasie, wersjonowanie, stabilność, kompatybilność itp.
Jeśli istnieją dwie aplikacje korzystające ze wspólnego kodu, czy chcesz zmusić te aplikacje do zmiany razem, na wypadek, gdyby musiały być ze sobą kompatybilne? Następnie użyj biblioteki dll. Wszystkie pliki exe będą używać tego samego kodu.
A może chcesz je oddzielić od siebie, abyś mógł je zmienić i mieć pewność, że nie złamiesz drugiego. Następnie użyj statycznej biblioteki lib.
Piekło DLL ma miejsce wtedy, gdy prawdopodobnie POWINIENEŚ użyć statycznej biblioteki lib, ale zamiast tego użyłeś biblioteki dll i nie wszystkie exy są z nią kompatybilne.
źródło
Biblioteka statyczna musi być połączona z końcowym plikiem wykonywalnym; staje się częścią pliku wykonywalnego i podąża za nim, gdziekolwiek się znajduje. Biblioteka dynamiczna jest ładowana za każdym razem, gdy plik wykonywalny jest wykonywany i pozostaje oddzielna od pliku wykonywalnego jako plik DLL.
Korzystasz z biblioteki DLL, jeśli chcesz mieć możliwość zmiany funkcjonalności dostarczanej przez bibliotekę bez konieczności ponownego łączenia pliku wykonywalnego (wystarczy zastąpić plik DLL, bez konieczności zastępowania pliku wykonywalnego).
Korzystasz z biblioteki statycznej, gdy nie masz powodu, aby używać biblioteki dynamicznej.
źródło
Artykuł Ulricha Dreppera na temat „ Jak pisać biblioteki współdzielone ” jest również dobrym zasobem, który szczegółowo opisuje, jak najlepiej korzystać z bibliotek współdzielonych lub co określa jako „dynamiczne obiekty współdzielone” (DSO). Koncentruje się bardziej na bibliotekach współdzielonych w formacie binarnym ELF , ale niektóre dyskusje są odpowiednie również dla bibliotek DLL systemu Windows.
źródło
Aby uzyskać doskonałą dyskusję na ten temat, przeczytaj ten artykuł od Sun.
Ma wszystkie zalety, w tym możliwość wstawiania bibliotek wstawiających. Więcej szczegółów na temat interpozycji można znaleźć w tym artykule tutaj .
źródło
Naprawdę kompromis, który podejmujesz (w dużym projekcie), polega na początkowym czasie ładowania, biblioteki będą się łączyły w tym czy innym czasie, decyzja, którą należy podjąć, to czy połączenie zajmie wystarczająco dużo czasu, którego potrzebuje kompilator ugryźć pocisk i zrobić to z góry, lub dynamiczny linker może to zrobić w czasie ładowania.
źródło
Jeśli twoja biblioteka ma być współużytkowana przez kilka plików wykonywalnych, często warto nadać jej dynamiczny charakter, aby zmniejszyć rozmiar plików wykonywalnych. W przeciwnym razie zdecydowanie uczyń go statycznym.
Istnieje kilka wad korzystania z biblioteki dll. Dodatkowe obciążenie związane jest z załadunkiem i rozładunkiem. Istnieje również dodatkowa zależność. Jeśli zmienisz bibliotekę DLL, aby była niezgodna z plikami wykonywalnymi, przestaną działać. Z drugiej strony, jeśli zmienisz bibliotekę statyczną, nie wpłynie to na skompilowane pliki wykonywalne przy użyciu starej wersji.
źródło
Jeśli biblioteka jest statyczna, to w czasie łączenia kod jest łączony z plikiem wykonywalnym. Dzięki temu plik wykonywalny jest większy (niż gdybyś wybrał ścieżkę dynamiczną).
Jeśli biblioteka jest dynamiczna, wówczas w czasie łączenia w pliku wykonywalnym są wbudowane odwołania do wymaganych metod. Oznacza to, że musisz wysłać plik wykonywalny i bibliotekę dynamiczną. Należy również rozważyć, czy współużytkowany dostęp do kodu w bibliotece jest bezpieczny, preferowany adres ładowania między innymi.
Jeśli możesz żyć z biblioteką statyczną, przejdź do biblioteki statycznej.
źródło
W naszym projekcie używamy wielu bibliotek DLL (> 100). Te biblioteki DLL są od siebie zależne, dlatego wybraliśmy konfigurację dynamicznego łączenia. Ma jednak następujące wady:
Być może lepszą konfiguracją było uczynienie wszystkiego statyczną biblioteką (a zatem masz tylko jeden plik wykonywalny). Działa to tylko wtedy, gdy nie ma miejsca powielanie kodu. Test wydaje się potwierdzać to założenie, ale nie mogłem znaleźć oficjalnej wyceny MSDN. Na przykład zrób 1 exe z:
Kod i zmienne shared_lib2 powinny być obecne w końcowym scalonym pliku wykonywalnym tylko raz. Czy ktoś może poprzeć to pytanie?
źródło
Biblioteki statyczne to archiwa zawierające kod obiektowy biblioteki, gdy są połączone z aplikacją, kod ten jest wkompilowany w plik wykonywalny. Biblioteki współdzielone różnią się tym, że nie są wkompilowane w plik wykonywalny. Zamiast tego dynamiczny linker przeszukuje niektóre katalogi w poszukiwaniu potrzebnych bibliotek, a następnie ładuje je do pamięci. Więcej niż jeden plik wykonywalny może jednocześnie korzystać z tej samej biblioteki współużytkowanej, co zmniejsza zużycie pamięci i rozmiar pliku wykonywalnego. Istnieje jednak więcej plików do rozpowszechnienia w pliku wykonywalnym. Musisz upewnić się, że biblioteka jest zainstalowana w systemie użytkownika w miejscu, w którym linker może ją znaleźć, statyczne łączenie eliminuje ten problem, ale skutkuje większym plikiem wykonywalnym.
źródło
Jeśli pracujesz nad projektami osadzonymi lub na wyspecjalizowanych platformach, biblioteki statyczne są jedyną drogą, którą możesz wykonać, również wiele razy mniej kłopotów z kompilacją w twojej aplikacji. Posiadanie projektów i plików mak, które zawierają wszystko, sprawia, że życie jest szczęśliwsze.
źródło
Podałbym ogólną zasadę, że jeśli masz dużą bazę kodu, wszystkie zbudowane na bibliotekach niższego poziomu (np. Frameworku Utils lub Gui), które chcesz podzielić na łatwiejsze do zarządzania biblioteki, a następnie uczyń je bibliotekami statycznymi. Biblioteki dynamiczne tak naprawdę nic nie kupują i jest mniej niespodzianek - na przykład będzie tylko jedna instancja singletonów.
Jeśli masz bibliotekę, która jest całkowicie oddzielna od reszty bazy kodu (np. Biblioteka strony trzeciej), rozważ utworzenie dll. Jeśli biblioteką jest LGPL, może być konieczne użycie biblioteki DLL ze względu na warunki licencyjne.
źródło