367 Stimmen

Unterschied zwischen gemeinsamen Objekten (.so), statischen Bibliotheken (.a) und DLLs (.so)?

Ich habe mich an einigen Diskussionen über Bibliotheken in Linux beteiligt und möchte einige Dinge bestätigen.

Nach meinem Verständnis (bitte korrigieren Sie mich, wenn ich falsch liege, und ich werde meinen Beitrag später bearbeiten) gibt es zwei Möglichkeiten, Bibliotheken bei der Erstellung einer Anwendung zu verwenden:

  1. Statische Bibliotheken (.a-Dateien): Zum Zeitpunkt der Verknüpfung wird eine Kopie der gesamten Bibliothek in die endgültige Anwendung eingefügt, so dass die Funktionen der Bibliothek für die aufrufende Anwendung immer verfügbar sind.
  2. Gemeinsam genutzte Objekte (.so-Dateien): Zum Zeitpunkt der Verknüpfung wird das Objekt lediglich anhand seiner API über die entsprechende Header-Datei (.h) überprüft. Die Bibliothek wird erst zur Laufzeit verwendet, wenn sie benötigt wird.

Der offensichtliche Vorteil statischer Bibliotheken besteht darin, dass sie es ermöglichen, die gesamte Anwendung in sich geschlossen zu halten, während der Vorteil dynamischer Bibliotheken darin besteht, dass die ".so"-Datei ersetzt werden kann (z. B. wenn sie aufgrund eines Sicherheitsfehlers aktualisiert werden muss), ohne dass die Basisanwendung neu kompiliert werden muss.

Ich habe gehört, dass einige Leute einen Unterschied zwischen Shared Objects und Dynamic Link Libraries (DLLs) machen, obwohl beides ".so"-Dateien sind. Gibt es einen Unterschied zwischen Shared Objects und DLLs, wenn es um die Entwicklung von C/C++ unter Linux oder einem anderen POSIX-kompatiblen Betriebssystem (z. B. MINIX, UNIX, QNX usw.) geht? Mir wurde gesagt, dass ein Hauptunterschied (bisher) darin besteht, dass Shared Objects nur zur Laufzeit verwendet werden, während DLLs zuerst mit dem Aufruf dlopen() innerhalb der Anwendung geöffnet werden müssen.

Schließlich habe ich von einigen Entwicklern gehört, dass sie von "Shared Archives" sprechen, die nach meinem Verständnis ebenfalls statische Bibliotheken sind, aber nie direkt von einer Anwendung verwendet werden. Stattdessen werden andere statische Bibliotheken gegen die "Shared Archives" gelinkt, um einige (aber nicht alle) Funktionen/Ressourcen aus dem Shared Archive in die zu erstellende statische Bibliothek zu ziehen.

Ich danke Ihnen allen im Voraus für Ihre Unterstützung.

Update


In dem Kontext, in dem mir diese Begriffe zur Verfügung gestellt wurden, handelte es sich tatsächlich um falsche Begriffe, die von einem Team von Windows-Entwicklern verwendet wurden, die Linux lernen mussten. Ich habe versucht, sie zu korrigieren, aber die (falschen) Sprachnormen blieben hängen.

  1. Gemeinsames Objekt: Eine Bibliothek, die beim Programmstart automatisch in ein Programm eingebunden wird und als eigenständige Datei existiert. Die Bibliothek wird zur Kompilierzeit in die Verknüpfungsliste aufgenommen (d.h.: LDOPTS+=-lmylib für eine Bibliotheksdatei mit dem Namen mylib.so ). Die Bibliothek muss zur Kompilierzeit und beim Start der Anwendung vorhanden sein.
  2. Statische Bibliothek: Eine Bibliothek, die bei der Erstellung einer einzelnen (größeren) Anwendung in das eigentliche Programm eingebunden wird. Sie enthält den Anwendungscode und den Bibliothekscode, der automatisch in ein Programm gelinkt wird, wenn das Programm erstellt wird, und die endgültige Binärdatei, die sowohl das Hauptprogramm als auch die Bibliothek selbst enthält, existiert als einzelne, eigenständige Binärdatei. Die Bibliothek wird zur Kompilierzeit in die Linking-Liste aufgenommen (d.h.: LDOPTS+=-lmylib für eine Bibliotheksdatei mit dem Namen mylib.a ). Die Bibliothek muss zur Kompilierzeit vorhanden sein.
  3. DLL: Im Wesentlichen dasselbe wie ein gemeinsam genutztes Objekt, aber anstatt zur Kompilierungszeit in die Verknüpfungsliste aufgenommen zu werden, wird die Bibliothek über dlopen() / dlsym() Befehle, so dass die Bibliothek zur Kompilierungszeit nicht vorhanden sein muss, um das Programm zu kompilieren. Außerdem muss die Bibliothek nicht (unbedingt) beim Start der Anwendung oder beim Kompilieren vorhanden sein. da sie nur in dem Moment benötigt wird, in dem die dlopen / dlsym Anrufe getätigt werden.
  4. Gemeinsames Archiv: Im Wesentlichen dasselbe wie eine statische Bibliothek, wird aber mit den Optionen "export-shared" und " -fPIC Flaggen". Die Bibliothek wird zur Kompilierzeit in die Verknüpfungsliste aufgenommen (d.h.: LDOPTS+=-lmylibS für eine Bibliotheksdatei mit dem Namen mylibS.a ). Der Unterschied zwischen den beiden besteht darin, dass dieses zusätzliche Flag erforderlich ist, wenn ein gemeinsam genutztes Objekt oder eine DLL das gemeinsam genutzte Archiv statisch in den eigenen Code einbinden UND die Funktionen des gemeinsam genutzten Objekts anderen Programmen zur Verfügung stellen will, anstatt sie nur intern in der DLL zu verwenden. Dies ist nützlich, wenn Ihnen jemand eine statische Bibliothek zur Verfügung stellt und Sie diese als SO neu verpacken möchten. Die Bibliothek muss zur Kompilierzeit vorhanden sein.

Zusätzliches Update

Die Unterscheidung zwischen " DLL " und " shared library " war nur eine (faule, ungenaue) Redewendung in dem Unternehmen, in dem ich damals arbeitete (Windows-Entwickler wurden gezwungen, auf Linux-Entwicklung umzusteigen, und der Begriff blieb hängen), die den oben genannten Beschreibungen entsprach.

Außerdem wird das nachgestellte " S " nach dem Bibliotheksnamen war im Fall von "shared archives" nur eine Konvention, die in diesem Unternehmen und nicht in der Branche allgemein verwendet wurde.

269voto

aleroot Punkte 68601

A statische Bibliothek(.a) ist eine Bibliothek, die direkt in die endgültige, vom Linker erzeugte ausführbare Datei gelinkt werden kann. Sie ist darin enthalten, und es besteht keine Notwendigkeit, die Bibliothek in das System einzubringen, in dem die ausführbare Datei eingesetzt wird.

A gemeinsame Bibliothek(.so) ist eine Bibliothek, die verlinkt, aber nicht in die endgültige ausführbare Datei eingebettet ist. Sie wird geladen, wenn die ausführbare Datei gestartet wird, und muss auf dem System vorhanden sein, auf dem die ausführbare Datei bereitgestellt wird.

A dynamische Verknüpfungsbibliothek unter Windows(.dll) ist wie eine Shared Library(.so) unter Linux, aber es gibt einige Unterschiede zwischen den beiden Implementierungen, die mit dem Betriebssystem zusammenhängen (Windows vs. Linux):

A DLL kann zwei Arten von Funktionen definieren: exportierte und interne. Die exportierten Funktionen sind dafür vorgesehen, von anderen Modulen sowie innerhalb der DLL, in der sie definiert sind, aufgerufen zu werden. Interne Funktionen sind in der Regel nur innerhalb der DLL, in der sie definiert sind, aufrufbar.

Eine SO Bibliothek unter Linux benötigt keine spezielle Export-Anweisung, um exportierbare Symbole anzugeben, da alle Symbole für einen abfragenden Prozess verfügbar sind.

124voto

Matthew Walton Punkte 9563

Ich habe immer gedacht, dass DLLs und gemeinsam genutzte Objekte nur verschiedene Begriffe für dieselbe Sache sind - Windows nennt sie DLLs, während sie auf UNIX-Systemen gemeinsam genutzte Objekte sind, wobei der allgemeine Begriff - dynamisch verknüpfte Bibliothek - beide abdeckt (sogar die Funktion zum Öffnen einer .so-Datei auf UNIX heißt dlopen() nach "dynamische Bibliothek").

Sie werden in der Tat nur beim Start der Anwendung verknüpft, aber Ihre Vorstellung von der Überprüfung anhand der Header-Datei ist falsch. Die Header-Datei definiert Prototypen, die erforderlich sind, um den Code zu kompilieren, der die Bibliothek verwendet, aber zur Link-Zeit schaut der Linker in die Bibliothek selbst, um sicherzustellen, dass die benötigten Funktionen tatsächlich vorhanden sind. Der Linker muss die Funktionskörper zur Linkzeit irgendwo finden, sonst gibt er einen Fehler aus. Er tut das auch zur Laufzeit, denn wie Sie richtig bemerken, könnte sich die Bibliothek selbst seit der Kompilierung des Programms geändert haben. Das ist der Grund, warum die ABI-Stabilität bei Plattformbibliotheken so wichtig ist, denn die ABI-Änderung ist es, die bestehende Programme, die gegen ältere Versionen kompiliert wurden, kaputt macht.

Statische Bibliotheken sind einfach Bündel von Objektdateien, die direkt aus dem Compiler kommen, genau wie die, die Sie selbst als Teil der Kompilierung Ihres Projekts erstellen. Sie werden also auf genau dieselbe Weise eingezogen und dem Linker zugeführt, und unbenutzte Bits werden auf genau dieselbe Weise gelöscht.

48voto

JoGusto Punkte 873

Ich kann die Details von DLLs in Windows näher erläutern, um meinen Freunden hier im *NIX-Land zu helfen, diese Rätsel zu lösen...

Eine DLL ist wie eine Shared Object Datei. Beide sind Bilder, die vom Programmlader des jeweiligen Betriebssystems in den Speicher geladen werden können. Die Bilder werden von verschiedenen Metadaten begleitet, die Linkern und Ladern dabei helfen, die notwendigen Assoziationen herzustellen und die Code-Bibliothek zu verwenden.

Windows-DLLs haben eine Exporttabelle. Die Exporte können nach Namen oder nach Tabellenposition (numerisch) erfolgen. Die letztere Methode gilt als "old school" und ist viel anfälliger - die DLL neu zu erstellen und die Position einer Funktion in der Tabelle zu ändern, wird in einer Katastrophe enden, während es kein wirkliches Problem gibt, wenn die Verknüpfung von Einstiegspunkten nach Namen erfolgt. Vergessen Sie das also als Problem, aber seien Sie sich dessen bewusst, wenn Sie mit "Dinosaurier"-Code arbeiten, wie z.B. mit Bibliotheken von Drittanbietern.

Windows-DLLs werden durch Kompilieren und Verknüpfen erstellt, genau wie bei einer EXE (ausführbaren Anwendung), aber die DLL soll nicht für sich alleine stehen, genau wie eine SO von einer Anwendung verwendet werden soll, entweder durch dynamisches Laden oder durch Binden zur Link-Zeit (der Verweis auf die SO ist in den Metadaten der Anwendung eingebettet, und der Programmlader des Betriebssystems lädt die referenzierten SOs automatisch). DLLs können auf andere DLLs verweisen, so wie SOs auf andere SOs verweisen können.

Unter Windows stellen die DLLs nur bestimmte Einstiegspunkte zur Verfügung. Diese werden "Exporte" genannt. Der Entwickler kann entweder ein spezielles Compiler-Schlüsselwort verwenden, um ein Symbol nach außen sichtbar zu machen (für andere Linker und den dynamischen Lader), oder die Exporte können in einer Modul-Definitionsdatei aufgeführt werden, die zur Link-Zeit verwendet wird, wenn die DLL selbst erstellt wird. Die moderne Praxis besteht darin, die Funktionsdefinition mit dem Schlüsselwort für den Export des Symbolnamens zu schmücken. Es ist auch möglich, Header-Dateien mit Schlüsselwörtern zu erstellen, die das Symbol als eines deklarieren, das von einer DLL außerhalb der aktuellen Kompiliereinheit importiert werden soll. Schlagen Sie die Schlüsselwörter __declspec(dllexport) und __declspec(dllimport) für weitere Informationen nach.

Eine der interessanten Eigenschaften von DLLs ist, dass sie eine Standard-Handler-Funktion "beim Laden/Entladen" deklarieren können. Jedes Mal, wenn die DLL geladen oder entladen wird, kann die DLL eine Initialisierung oder Bereinigung durchführen. Dies lässt sich gut mit einer DLL als objektorientiertem Ressourcenmanager, wie z. B. einem Gerätetreiber oder einer gemeinsamen Objektschnittstelle, verbinden.

Wenn ein Entwickler eine bereits erstellte DLL verwenden möchte, muss er entweder auf eine "Exportbibliothek" (*.LIB) verweisen, die vom DLL-Entwickler bei der Erstellung der DLL erstellt wurde, oder er muss die DLL zur Laufzeit explizit laden und die Adresse des Einstiegspunkts über die Mechanismen LoadLibrary() und GetProcAddress() namentlich anfordern. In den meisten Fällen werden DLLs durch das Linken gegen eine LIB-Datei (die lediglich die Linker-Metadaten für die exportierten Einstiegspunkte der DLL enthält) verwendet. Dynamisches Laden ist in der Regel für die Implementierung von "Polymorphismus" oder "Laufzeitkonfigurierbarkeit" im Programmverhalten reserviert (Zugriff auf Add-ons oder später definierte Funktionalität, auch "Plugins" genannt).

Die Art und Weise, wie Windows die Dinge handhabt, kann manchmal etwas Verwirrung stiften; das System verwendet die Erweiterung .LIB sowohl für normale statische Bibliotheken (Archive, wie POSIX *.a-Dateien) als auch für die "Export-Stub"-Bibliotheken, die benötigt werden, um eine Anwendung zur Link-Zeit an eine DLL zu binden. Man sollte also immer nachsehen, ob eine *.LIB-Datei eine gleichnamige *.DLL-Datei hat; wenn nicht, stehen die Chancen gut, dass es sich bei der *.LIB-Datei um ein statisches Bibliotheksarchiv handelt und nicht um Export-Bindungsmetadaten für eine DLL.

7voto

rapadura Punkte 4996

Sie haben Recht, dass statische Dateien werden zum Zeitpunkt der Verknüpfung in die Anwendung kopiert und dass Gemeinsame Dateien werden nur zur Link-Zeit überprüft und zur Laufzeit geladen .

En dlopen Aufruf ist nicht nur für gemeinsam genutzte Objekte, wenn die Anwendung dies zur Laufzeit in ihrem Namen wünscht, ansonsten werden die gemeinsam genutzten Objekte automatisch beim Start der Anwendung geladen. DLLS und .so sind ein und dasselbe. die dlopen existiert, um noch feiner abgestufte dynamische Ladefähigkeiten für Prozesse hinzuzufügen. Sie müssen nicht dlopen um die DLLs zu öffnen/zu verwenden, geschieht dies ebenfalls beim Starten der Anwendung.

-1voto

Raymond Jennings Punkte 109

Ich vermute, dass es sich hier um ein Missverständnis handelt, aber Header-Dateien, zumindest die .h-Variante, die für die Kompilierung von Quellcode verwendet wird, werden definitiv NICHT während der Link-Zeit überprüft.

.h- und .c/.cpp-Dateien sind nur während der Kompilierungsphase beteiligt, die die Vorverarbeitung einschließt. Sobald der Objektcode erstellt wurde, ist die Header-Datei längst verschwunden, bevor sich der Linker mit der Sache befasst.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X