web-dev-qa-db-de.com

Wann werden dynamische und statische Bibliotheken verwendet?

Beim Erstellen einer Klassenbibliothek in C++ können Sie zwischen dynamischem (.dll, .so) und statisch (.lib, .a) Bibliotheken. Was ist der Unterschied zwischen ihnen und wann ist es angebracht, welche zu verwenden?

421

Statische Bibliotheken vergrößern den Code in Ihrer Binärdatei. Sie werden immer geladen und mit welcher Version des Codes Sie kompiliert haben, ist die Version des Codes, der ausgeführt wird.

Dynamische Bibliotheken werden separat gespeichert und versioniert. Es ist möglich, dass eine Version der dynamischen Bibliothek geladen wird, die nicht die ursprüngliche ist, die mit Ihrem Code geliefert wurde falls Das Update wird als binär kompatibel mit der ursprünglichen Version angesehen.

Außerdem sind dynamische Bibliotheken nicht unbedingt geladen - sie werden normalerweise beim ersten Aufruf geladen - und können von Komponenten gemeinsam genutzt werden, die dieselbe Bibliothek verwenden (mehrere Daten werden geladen, ein Code wird geladen).

Dynamische Bibliotheken galten die meiste Zeit als der bessere Ansatz, aber ursprünglich hatten sie einen großen Fehler (google DLL hell)), der von neueren Windows-Betriebssystemen (Windows =) so gut wie beseitigt wurde XP insbesondere).

290
Orion Adrian

Andere haben hinreichend erklärt, was eine statische Bibliothek ist, aber ich möchte auf einige der Vorbehalte bei der Verwendung statischer Bibliotheken hinweisen, zumindest unter Windows:

  • Singletons: Wenn etwas global/statisch und eindeutig sein muss, sollten Sie sehr vorsichtig sein, wenn Sie es in eine statische Bibliothek stellen. Wenn mehrere DLLs mit dieser statischen Bibliothek verknüpft sind, erhält jeder eine eigene Kopie des Singletons. Wenn es sich bei Ihrer Anwendung jedoch um eine einzelne EXE-Datei ohne benutzerdefinierte DLLs handelt, ist dies möglicherweise kein Problem.

  • Entfernen von nicht referenziertem Code: Wenn Sie eine Verknüpfung zu einer statischen Bibliothek herstellen, werden nur die Teile der statischen Bibliothek, auf die Ihre DLL/EXE verweist, mit Ihrer verknüpft DLL/EXE.

    Wenn beispielsweise mylib.liba.obj Und b.obj Enthält und Ihre DLL/EXE nur auf Funktionen oder Variablen aus a.obj Verweist, wird die Gesamtheit von b.obj wird vom Linker verworfen. Wenn b.obj Globale/statische Objekte enthält, werden deren Konstruktoren und Destruktoren nicht ausgeführt. Wenn diese Konstruktoren/Destruktoren Nebenwirkungen haben, können Sie durch ihre Abwesenheit enttäuscht sein.

    Wenn die statische Bibliothek spezielle Eintrittspunkte enthält, müssen Sie möglicherweise auch darauf achten, dass diese tatsächlich enthalten sind. Ein Beispiel hierfür in der eingebetteten Programmierung (okay, nicht Windows) wäre ein Interrupt-Handler, der als an einer bestimmten Adresse markiert ist. Sie müssen den Interrupt-Handler auch als einen Eintrittspunkt markieren, um sicherzustellen, dass er nicht verworfen wird.

    Eine weitere Konsequenz daraus ist, dass eine statische Bibliothek möglicherweise Objektdateien enthält, die aufgrund nicht aufgelöster Verweise völlig unbrauchbar sind. Sie verursacht jedoch erst dann einen Linker-Fehler, wenn Sie auf eine Funktion oder Variable aus diesen Objektdateien verweisen. Dies kann lange nach dem Schreiben der Bibliothek geschehen.

  • Debugsymbole: Möglicherweise möchten Sie einen separaten PDB für jede statische Bibliothek, oder Sie möchten, dass die Debugsymbole in den Objektdateien platziert werden, damit sie abgerufen werden in die PDB für die DLL/EXE gerollt. In der Visual C++ - Dokumentation wird die erforderlichen Optionen erläutert.

  • RTTI: Wenn Sie eine einzelne statische Bibliothek mit mehreren DLLs verknüpfen, erhalten Sie möglicherweise mehrere type_info - Objekte für dieselbe Klasse. Wenn Ihr Programm davon ausgeht, dass type_info "Einzelne" Daten sind und &typeid() oder type_info::before() verwendet, erhalten Sie möglicherweise unerwünschte und überraschende Ergebnisse.

185
bk1e

Eine lib ist eine Codeeinheit, die in der ausführbaren Datei Ihrer Anwendung enthalten ist.

Eine DLL ist eine eigenständige Einheit aus ausführbarem Code. Es wird dabei nur geladen, wenn ein Aufruf in diesen Code erfolgt. Eine DLL kann von mehreren Anwendungen verwendet und in mehreren Prozessen geladen werden, während sich immer noch nur eine Kopie des Codes auf der Festplatte befindet.

Dll Pro: kann verwendet werden, um Code zwischen mehreren Produkten wiederzuverwenden/zu teilen; Laden Sie den Prozessspeicher bei Bedarf und können Sie ihn entladen, wenn Sie ihn nicht benötigen. kann unabhängig vom Rest des Programms aktualisiert werden.

Dll cons: Leistungseinbußen beim Laden von DLLs und beim erneuten Basieren von Code; Versionsprobleme ("dll hell")

Lib Pro: Keine Beeinträchtigung der Leistung, da Code immer in den Prozess geladen und nicht neu basiert wird. Keine Versionsprobleme.

lib cons: ausführbare Datei/Prozess "aufblähen" - Der gesamte Code befindet sich in Ihrer ausführbaren Datei und wird beim Start des Prozesses geladen. Keine Wiederverwendung/Weitergabe - jedes Produkt verfügt über eine eigene Kopie des Codes.

60
Franci Penov

Neben den technischen Implikationen von statischen und dynamischen Bibliotheken (statische Dateien bündeln alles in einer großen binären und dynamischen Bibliothek, die die gemeinsame Nutzung von Code zwischen verschiedenen ausführbaren Dateien ermöglichen) gibt es die rechtlichen Implikationen.

Wenn Sie beispielsweise LGPL-lizenzierten Code verwenden und statisch mit einer LGPL-Bibliothek verknüpfen (und somit eine große Binärdatei erstellen), wird Ihr Code automatisch zu Open Sourced ( frei wie in Freiheit) LGPL-Code. Wenn Sie eine Verknüpfung zu einem freigegebenen Objekt herstellen, müssen Sie nur die Verbesserungen/Fehlerbehebungen, die Sie an der LGPL-Bibliothek selbst vorgenommen haben, mit der LGPL durchführen.

Dies wird ein weitaus wichtigeres Problem, wenn Sie sich für die Kompilierung Ihrer mobilen Anwendungen entscheiden (in Android Sie haben die Wahl zwischen statisch und dynamisch, in iOS ist dies nicht der Fall - es ist immer statisch ).

22
rburhum

Erstellen einer statischen Bibliothek

$$:~/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]>

erstellen einer dynamischen Bibliothek

$$:~/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]>
20
Vijay

C++ - Programme bestehen aus zwei Phasen

  1. Kompilierung - Erzeugt Objektcode (.obj)
  2. Verknüpfen - Erzeugt ausführbaren Code (.exe oder .dll)

Statische Bibliothek (.lib) ist nur ein Bündel von .obj-Dateien und daher kein vollständiges Programm. Es hat nicht die zweite (Verknüpfungs-) Phase der Programmerstellung durchlaufen. Dlls sind dagegen wie Exes und daher vollständige Programme.

Wenn Sie eine statische Bibliothek erstellen, ist diese noch nicht verknüpft. Daher müssen Benutzer Ihrer statischen Bibliothek denselben Compiler verwenden, den Sie verwendet haben (wenn Sie g ++ verwendet haben, müssen sie g ++ verwenden).

Wenn Sie stattdessen eine DLL erstellt haben (und diese erstellt haben richtig ), haben Sie ein vollständiges Programm erstellt, das alle Konsumenten verwenden können, unabhängig davon, welchen Compiler sie verwenden. Es gibt jedoch verschiedene Einschränkungen beim Exportieren aus einer DLL, wenn die Kompatibilität mit anderen Compilern gewünscht wird.

19
tcb

Sie sollten sorgfältig über Änderungen im Laufe der Zeit, Versionierung, Stabilität, Kompatibilität usw. nachdenken.

Wenn es zwei Apps gibt, die den gemeinsam genutzten Code verwenden, möchten Sie diese Apps zwingen, sich gemeinsam zu ändern, falls sie miteinander kompatibel sein müssen? Dann benutze die dll. Alle Exes verwenden den gleichen Code.

Oder möchten Sie sie voneinander isolieren, damit Sie eines ändern und sicher sein können, dass Sie das andere nicht zerstört haben. Dann benutze die statische Bibliothek.

DLL Hölle ist, wenn Sie wahrscheinlich eine statische Bibliothek verwendet haben SOLLTEN, aber Sie haben stattdessen eine DLL verwendet, und nicht alle Exes sind damit kompatibel.

13
Corey Trager

Eine statische Bibliothek wird in den Client kompiliert. Eine .lib wird zur Kompilierungszeit verwendet und der Inhalt der Bibliothek wird Teil der ausführbaren Datei.

Eine dynamische Bibliothek wird zur Laufzeit geladen und nicht in die Client-Programmdatei kompiliert. Dynamische Bibliotheken sind flexibler, da mehrere ausführbare Client-Dateien eine DLL laden und deren Funktionalität nutzen können. Dadurch werden auch die Gesamtgröße und die Wartbarkeit Ihres Client-Codes auf ein Minimum beschränkt.

12
Jordan Parmer

Eine statische Bibliothek muss mit der endgültigen ausführbaren Datei verknüpft sein. es wird Teil der ausführbaren Datei und folgt ihr, wo immer sie hingeht. Bei jeder Ausführung der ausführbaren Datei wird eine dynamische Bibliothek geladen, die von der ausführbaren Datei als DLL Datei getrennt bleibt.

Sie würden eine DLL verwenden, wenn Sie die von der Bibliothek bereitgestellte Funktionalität ändern möchten, ohne die ausführbare Datei erneut verknüpfen zu müssen (ersetzen Sie einfach die DLL Datei, ohne die ausführbare Datei ersetzen zu müssen).

Sie würden eine statische Bibliothek immer dann verwenden, wenn Sie keinen Grund haben, eine dynamische Bibliothek zu verwenden.

9
spotcatbug

Ulrich Dreppers Artikel über " Wie schreibe ich gemeinsam genutzte Bibliotheken? " ist auch eine gute Ressource, die ausführlich beschreibt, wie man gemeinsam genutzte Bibliotheken am besten nutzt, oder was er als "Dynamic Shared Objects" (DSOs) bezeichnet. Es konzentriert sich mehr auf gemeinsam genutzte Bibliotheken im Binärformat ELF , aber einige Diskussionen eignen sich auch für Windows-DLLs.

7
Void

Lesen Sie für eine hervorragende Diskussion dieses Themas diesen Artikel von Sun.

Es bietet alle Vorteile, einschließlich der Möglichkeit, zwischengeschaltete Bibliotheken einzufügen. Weitere Informationen zum Einfügen finden Sie in dieser Artikel hier .

5
Rob Wells

Der Kompromiss, den Sie (in einem großen Projekt) eingehen, besteht in der anfänglichen Ladezeit. Die Bibliotheken werden zu der einen oder anderen Zeit verknüpft. Die Entscheidung, die getroffen werden muss, ist, dass die Verknüpfung lange genug dauert, die der Compiler benötigt die Kugel zu beißen und es vorne zu tun, oder kann der dynamische Linker es zum Ladezeitpunkt tun.

4
pfranza

Wenn Ihre Bibliothek von mehreren ausführbaren Dateien gemeinsam genutzt werden soll, ist es häufig sinnvoll, sie dynamisch zu gestalten, um die Größe der ausführbaren Dateien zu verringern. Ansonsten machen Sie es auf jeden Fall statisch.

Die Verwendung einer DLL hat mehrere Nachteile. Es gibt zusätzlichen Aufwand für das Laden und Entladen. Es gibt auch eine zusätzliche Abhängigkeit. Wenn Sie die DLL so ändern, dass sie nicht mehr mit Ihren Executalbes kompatibel ist, funktionieren sie nicht mehr. Wenn Sie dagegen eine statische Bibliothek ändern, sind Ihre kompilierten ausführbaren Dateien, die die alte Version verwenden, nicht betroffen.

3
Dima

Wenn die Bibliothek statisch ist, wird der Code zum Zeitpunkt der Verknüpfung mit Ihrer ausführbaren Datei verknüpft. Dies macht Ihre ausführbare Datei größer (als wenn Sie die dynamische Route gegangen sind).

Wenn die Bibliothek dynamisch ist, werden zum Zeitpunkt der Verknüpfung Verweise auf die erforderlichen Methoden in Ihre ausführbare Datei integriert. Dies bedeutet, dass Sie Ihre ausführbare Datei und die dynamische Bibliothek versenden müssen. Sie sollten auch überlegen, ob der gemeinsame Zugriff auf den Code in der Bibliothek sicher ist, unter anderem die bevorzugte Ladeadresse.

Wenn Sie mit der statischen Bibliothek leben können, gehen Sie mit der statischen Bibliothek.

3
Seb Rose

Statische Bibliotheken sind Archive, die den Objektcode für die Bibliothek enthalten, wenn sie mit einer Anwendung verknüpft sind, deren Code in der ausführbaren Datei kompiliert wird. Freigegebene Bibliotheken unterscheiden sich darin, dass sie nicht in die ausführbare Datei kompiliert werden. Stattdessen durchsucht der dynamische Linker einige Verzeichnisse nach der/den benötigten Bibliothek (en) und lädt diese dann in den Speicher. Mehr als eine ausführbare Datei kann dieselbe gemeinsam genutzte Bibliothek gleichzeitig verwenden, wodurch die Speichernutzung und die Größe der ausführbaren Datei verringert werden. In diesem Fall müssen jedoch weitere Dateien mit der ausführbaren Datei verteilt werden. Sie müssen sicherstellen, dass die Bibliothek auf dem verwendeten System an einem Ort installiert ist, an dem der Linker sie finden kann. Durch statisches Verknüpfen wird dieses Problem behoben, es wird jedoch eine größere ausführbare Datei erstellt.

2
Terence Simpson

Wir verwenden viele DLLs (> 100) in unserem Projekt. Diese DLLs sind voneinander abhängig und daher haben wir die Einrichtung der dynamischen Verknüpfung gewählt. Es hat jedoch folgende Nachteile:

  • langsamer Start (> 10 Sekunden)
  • DLLs mussten versioniert werden, da Windows Module nach Eindeutigkeit der Namen lädt. Eigene geschriebene Komponenten würden andernfalls die falsche Version der DLL (d. H. Die bereits geladene anstelle der eigenen verteilten Menge) erhalten.
  • optimierer kann nur innerhalb von DLL Grenzen optimieren. Beispielsweise versucht der Optimierer, häufig verwendete Daten und Code nebeneinander zu platzieren, dies funktioniert jedoch nicht über DLL Grenzen

Vielleicht war es besser, alles eine statische Bibliothek zu erstellen (und daher haben Sie nur eine ausführbare Datei). Dies funktioniert nur, wenn keine Code-Duplizierung stattfindet. Ein Test scheint diese Annahme zu stützen, aber ich konnte kein offizielles MSDN-Zitat finden. Also mache zum Beispiel 1 exe mit:

  • exe verwendet shared_lib1, shared_lib2
  • shared_lib1 benutze shared_lib2
  • shared_lib2

Der Code und die Variablen von shared_lib2 sollten nur einmal in der endgültigen zusammengeführten ausführbaren Datei vorhanden sein. Kann jemand diese Frage unterstützen?

2
gast128

Wenn Sie an eingebetteten Projekten oder speziellen Plattformen arbeiten, sind statische Bibliotheken der einzige Weg, und oftmals ist das Kompilieren in Ihre Anwendung weniger mühsam. Auch Projekte und Makefiles, die alles enthalten, machen das Leben glücklicher.

2
Robert Gould

Ich gebe eine allgemeine Faustregel an: Wenn Sie eine große Codebasis haben, die alle auf Bibliotheken niedrigerer Ebenen (z. B. einem Utils- oder Gui-Framework) basiert, die Sie in besser verwaltbare Bibliotheken unterteilen möchten, dann machen Sie sie zu statischen Bibliotheken. Dynamische Bibliotheken kaufen Ihnen nichts und es gibt weniger Überraschungen - es wird zum Beispiel nur eine Instanz von Singletons geben.

Wenn Sie eine Bibliothek haben, die sich vollständig von der übrigen Codebasis unterscheidet (z. B. eine Bibliothek eines Drittanbieters), sollten Sie in Erwägung ziehen, sie zu einer DLL zu machen. Wenn es sich bei der Bibliothek um eine LGPL handelt, müssen Sie aufgrund der Lizenzbedingungen möglicherweise ohnehin eine DLL verwenden.

1
the_mandrill