Angenommen, Sie haben eine Klasse Unuseful
wie folgt definiert:
Datei Unuseful.h
:
class Unuseful {
public:
void printUnusefulStatement();
};
Datei Unuseful.cpp
:
#include "unuseful.h"
#include <iostream>
void Unuseful::printUnusefulStatement()
{
std::cout << "Hello world!" << std::endl;
}
Jetzt haben Sie eine andere Klasse, die nicht nützliche Anweisungen drucken muss:
Unuseful u;
u.printUnusefulStatement();
Dies bedeutet, dass Sie eine externe Bibliothek verwenden möchten, die die spezifische Implementierung ( printUnusefulStatement
) enthält, die Sie in Ihren Code aufnehmen möchten.
Sie können diese Bibliothek auf zwei Arten verwenden:
- Durch Bereitstellung des Quellcodes für den Compiler
- Durch Bereitstellen einer Binärdatei (die zuvor für Ihre Architektur kompiliert wurde) für den Linker
Fall 1: Verwenden einer Bibliothek zur Kompilierungszeit
Dies ist der einfachste Fall. Sie haben den Quellcode der Bibliothek, die Sie verwenden müssen, und müssen ihn einfach zusammen mit Ihrem vorhandenen Code (z. B. main.cpp
Datei) kompilieren . In der Regel sind Sie der Autor und Benutzer der Bibliothek (eine Klasse, die eine von Ihnen benötigte Aufgabe erfüllt).
Kompilieren mit diesem Befehl:
g++ main.cpp unuseful.cpp
ermöglicht es Ihnen, die Implementierung zu verwenden, die Sie in Ihrer main.cpp
Datei benötigen .
Fall 2: Verknüpfen einer Bibliothek
In den meisten Fällen als in Fall 1 verfügen Sie nicht über den Quellcode der Bibliothek, die Sie verwenden möchten. Sie haben nur die Header-Datei ( Unuseful.h
um mit dem Beispiel fortzufahren) und eine statische oder gemeinsam genutzte Bibliothek (wahrscheinlich [*] libunuseful.a
bzw. libunuseful.so
Dateien).
Die statische Bibliothek ist ein Archiv von Objektdateien ( *.o
), die in Ihren endgültigen ausführbaren Dateien verknüpft sind. Die gemeinsam genutzten Bibliotheken werden stattdessen dynamisch geladen - zur Laufzeit (auf dieser Seite finden Sie ein besseres Verständnis des Unterschieds).
Statische Bibliotheken werden durch einfaches Archivieren der *.o
Dateien mit dem ar
Programm erstellt:
# Create the object files (only one here)
g++ -c unuseful.cpp
# Create the archive (insert the lib prefix)
ar rcs libunuseful.a unuseful.o
Freigegebene Bibliotheken werden mit der g++
-shared
Option erstellt:
# Create the object file with Position Independent Code[**]
g++ -fPIC -c unuseful.cpp
# Crate the shared library (insert the lib prefix)
g++ -shared -o libunuseful.so unuseful.o
Nehmen wir an, Sie haben jetzt die Unuseful.h
Datei und die gemeinsam genutzte Bibliothek ( libunuseful.so
Datei) und eine main.cpp
Datei, die ein Unuseful
Objekt instanziiert und die printUnusefulStatement
Methode aufruft .
Wenn Sie versuchen, diese Datei ( g++ main.cpp
) zu kompilieren, beschwert sich der Linker, weil er das printUnusefulStatement
Symbol nicht finden kann .
Es ist Zeit, die Bibliothek zu benutzen:
g++ main.cpp -L. -lunuseful
Die -L
Option teilt dem Linker mit, wo nach Bibliotheksdateien gesucht werden soll, und das -l
Flag teilt dem Linker den Namen der zu verwendenden Bibliotheken mit (ohne lib
Präfix).
Jetzt wird die ausführbare Datei erstellt ( a.out
da ich keinen anderen Namen angegeben habe), und Sie haben eine Bibliothek verwendet, um eine von Ihnen benötigte Funktionalität zu implementieren ( printUnusefulStatement
).
Da die gemeinsam genutzte Bibliothek zur Laufzeit geladen wird, schlägt die Ausführung der a.out
ausführbaren Datei möglicherweise fehl, da das System die Bibliothek nicht finden kann. In der Regel kann dies gelöst werden, indem eine Umgebungsvariable festgelegt wird, die angibt, welche Pfade für die Suche nach dynamischen Bibliotheken verwendet werden sollen:
# Set the LD_LIBRARY_PATH [*]
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
Fertig, jetzt wurde Ihre ausführbare Datei kompiliert und sie kann die benötigte Bibliothek ausführen und laden.
Fazit
Dies ist ein schneller Überblick über Bibliotheken, von denen ich hoffe, dass sie Ihnen helfen können, zu verstehen, wie sie verwendet und anderen zur Verfügung gestellt werden.
Es gibt viele, viele Aspekte, die bei Interesse genauer untersucht werden sollten: g++
Optionen beim Erstellen von gemeinsam genutzten Bibliotheken, ar
Optionen, Umgebungsvariablen, das Format für gemeinsam genutzte Bibliotheken usw.
[*]: In einer Unix-Umgebung
[**]: Wenn dies für den Zielcomputer unterstützt wird, geben Sie positionsunabhängigen Code aus, der für die dynamische Verknüpfung geeignet ist und eine Begrenzung der Größe der globalen Versatztabelle vermeidet. Diese Option macht einen Unterschied bei m68k, PowerPC und SPARC. Positionsunabhängiger Code erfordert spezielle Unterstützung und funktioniert daher nur auf bestimmten Computern. [Von der g ++ Manpage]
std::cout << "Hello World";
Sie eine Bibliothek. Könnten Sie genauer sein?