Der Hauptunterschied besteht darin, dass Sie statisch verknüpfte Bibliotheken in Ihre App einschließen. Sie werden verknüpft, wenn Sie Ihre App erstellen. Dynamische Bibliotheken werden zur Laufzeit verknüpft, sodass Sie sie nicht in Ihre App einschließen müssen. Heutzutage werden dynamische Bibliotheken verwendet, um die Größe von Apps zu reduzieren, indem viele dynamische Bibliotheken auf jedem Computer vorhanden sind.
Dynamische Bibliotheken ermöglichen es Benutzern auch, Bibliotheken zu aktualisieren, ohne die Client-Apps neu zu erstellen. Wenn ein Fehler in einer Bibliothek gefunden wird, die Sie in Ihrer App verwenden, und diese statisch verknüpft ist, müssen Sie Ihre App neu erstellen und sie für alle Ihre Benutzer erneut ausgeben. Wenn ein Fehler in einer dynamisch verknüpften Bibliothek gefunden wird, müssen alle Ihre Benutzer nur ihre Bibliotheken aktualisieren und Ihre App benötigt kein Update.
Wenn ein C++-Programm kompiliert wird. Es muss Verweise auf die Funktionen und den Code der C++-Bibliothek enthalten (z. B. den Code für die Bibliothek).
Angenommen, wir haben eine hypothetische gemeinsam genutzte Bibliothek namens libdyno.so
. Schließlich können Sie mit objdump
einen Blick hineinwerfen oder nm
.
objdump --syms libdyno.so
Sie können dies heute auf Ihrem System mit jeder gemeinsam genutzten Bibliothek tun. objdump
auf einem MAC heißt gobjdump
und kommt mit Gebräu im binutils
Paket. Versuchen Sie es auf einem Mac...
gobjdump --syms /usr/lib/libz.dylib
Sie können nun sehen, dass die Symbole im gemeinsamen Objekt enthalten sind. Wenn Sie link
mit dem gemeinsam genutzten Objekt verwenden Sie normalerweise so etwas wie
g++ -Wall -g -pedantic -ldyno DynoLib_main.cpp -o dyno_main
Beachten Sie die -ldyno
in diesem Befehl. Dies weist den Compiler (eigentlich den Linker ld) an, nach einer gemeinsam genutzten Objektdatei namens libdyno.so
zu suchen wo es normalerweise nach ihnen sucht. Sobald es dieses Objekt gefunden hat, kann es die benötigten Symbole finden. Es gibt keine zirkuläre Abhängigkeit, da Sie als Entwickler aufgefordert haben, die dynamische Bibliothek zu laden, indem Sie -l
angeben Flagge.
Wie und wann würden Sie eine dynamische Bibliothek verwenden? Wie macht man einen? Wie in dem spezifischen Kompilierungsbefehl, der verwendet wird, um eine solche Datei aus einer standardmäßigen .cpp-Datei zu erstellen
Erstellen Sie eine Datei namens DynoLib.cpp
#include "DynoLib.h"
DynamicLib::DynamicLib() {}
int DynamicLib::square(int a) {
return a * a;
}
Erstellen Sie eine Datei namens DynoLib.h
#ifndef DYNOLIB_H
#define DYNOLIB_H
class DynamicLib {
public:
DynamicLib();
int square(int a);
};
#endif
Kompilieren Sie sie wie folgt zu einer gemeinsam genutzten Bibliothek. Das ist linuxspezifisch...
g++ -Wall -g -pedantic -shared -std=c++11 DynoLib.cpp -o libdyno.so
Sie können dieses Objekt jetzt mit dem Befehl untersuchen, den ich zuvor gegeben habe, dh
objdump --syms libdyno.so
Erstellen Sie nun eine Datei namens DynoLib_main.cpp, die mit libdyno.so
verknüpft wird und verwenden Sie die Funktion, die wir gerade darin definiert haben.
#include "DynoLib.h"
#include <iostream>
using namespace std;
int main(void) {
DynamicLib *lib = new DynamicLib();
std::cout << "Square " << lib->square(1729) << std::endl;
return 1;
}
Kompilieren Sie es wie folgt
g++ -Wall -g -pedantic -L. -ldyno DynoLib_main.cpp -o dyno_main
./dyno_main
Square 2989441
Sie können sich auch die Hauptbinary mit nm
ansehen . Im Folgenden sehe ich, ob es etwas mit dem String square
gibt darin ist zB das Symbol das ich brauche aus libdyno.so
in irgendeiner Weise in meiner Binärdatei referenziert.
nm dyno_runner |grep square
U _ZN10DynamicLib6squareEi
Die Antwort ist ja. Der Großbuchstabe U
bedeutet undefiniert, aber dies ist der Symbolname für unsere quadratische Methode in der DynamicLib-Klasse, die wir zuvor erstellt haben. Der seltsam aussehende Name ist auf Namensverstümmelung zurückzuführen, die ein eigenes Thema ist.
Woher weiß ich, auf welche ich statisch verlinken soll, wie ich es mit einer regulären.o-Datei tun würde, und auf welche dynamisch verlinkt werden soll?
Du musst es nicht wissen. Sie geben an, womit Sie verknüpfen möchten, und lassen den Compiler (und Linker usw.) die Arbeit erledigen. Beachten Sie den -l
flag benennt die Bibliothek und den -L
sagt ihm, wo er suchen soll. Hier gibt es eine anständige Beschreibung, wie der Compiler etwas findet
gcc-Linkage-Option -L:Alternative Möglichkeiten, den Pfad zur dynamischen Bibliothek anzugeben
Oder werfen Sie einen Blick auf man ld
.
Wozu dienen die Flags -L und -l? Was bedeutet es, zum Beispiel ein -lusb-Flag in der Befehlszeile anzugeben?
Siehe den obigen Link. Dies ist von man ld
..
-L Suchverzeichnis
Fügen Sie den Pfad searchdir zur Liste der Pfade hinzu, in denen ld nach Archivbibliotheken und ld-Kontrollskripten sucht. Sie können diese Option beliebig oft verwenden. Die Verzeichnisse werden in der Reihenfolge durchsucht, in der sie auf der Kommandozeile angegeben werden. In der Befehlszeile angegebene Verzeichnisse werden vor den Standardverzeichnissen durchsucht. Alle -L-Optionen gelten für alle -l-Optionen, unabhängig von der Reihenfolge, in der die Optionen erscheinen. -L-Optionen wirken sich nicht darauf aus, wie ld nach einem Linkerskript sucht, es sei denn, die -T-Option ist angegeben.`
Wenn Sie es geschafft haben, hierher zu kommen, zahlt es sich aus, etwas über den Linker, dh ld, zu erfahren. Es spielt eine wichtige Rolle und ist die Quelle einer Menge Verwirrung, weil die meisten Leute anfangen, sich mit einem Compiler zu beschäftigen und denken, dass compiler == linker
und das ist nicht wahr.