====== Dynamisches Linken ======
Wie besprochen wollen wir den Code aus dem [[user:glocke:cpp:extlibs|vorherigen Beispiel]] dynamisch zu unserem Programm linken. Als Programm können wir folgendes verwenden:
=== Datei: main.cpp ===
#include
#include "point.hpp"
int main() {
Point p1(13.4f, 3.7f, -0.4f);
std::cout << "X-Koordinate: " << p1.getX() << std::endl;
p1.setX(p1.getY() * p1.getZ());
std::cout << "X-Koordinate: " << p1.getX() << std::endl;
}
Es unterscheidet sich von der bisher gewöhnten Vorgehensweise nicht von den bisherigen Programmen.
===== Linux mit GCC =====
Zunächst müssen wir aus unserer ''Point''-Implementierung zur dynamischen Library kompilieren. Das klingt wesentlich komplizierter, als es ist:
g++ -fPIC -shared -o libpoint.so point.cpp
Dabei **muss** der Dateiname der Library mit ''lib'' beginnen und auf ''.so'' enden. Entweder kopieren wir dieses Shared Object in den Standard-SharedObjekt-Ordner, oder müssen später den lokalen Pfad verwenden. Wie gewohnt können wir unser Programm erst einmal kompilieren:
g++ -c main.cpp
Der letzte Schritt ist auch hier das Linken. Dabei brauchen wir den Namen der Library (das zwischen ''lib'' und ''.so'' steht, in unserem Falle ''point'') und verwenden den Kommandoparameter ''-lBIBLIOTHEKSNAME''. Weitehrin müssen wir beachten, ob sich die Library im Standard-Pfad befindet oder nicht. Linken wir z.B. SDL, so genügt in der Regel ''-lSDL'', da sich die ''libSDL.so'' dank Paketverwaltung im Standardpfad befindet. Dann sehe unser Fall so aus:
g++ -o main main.o -lpoint
Anschließend kann das Programm ''main'' normal gestartet werden. Dabei muss sich die ''libpoint.so'' sich im Standard-Ordner für SharedObjects befinden, sonst verweigert unser Programm den Betrieb.
Liegt das SharedObject lokal, müssen wir den Suchpfad mit angeben. Dies geschieht durch ''-L/pfad/zum/sharedobject/''. Auf linux-basierten Systemen können wir die Variable ''$PWD'' verwenden, um das aktuelle Arbeitsverzeichnis zu ermitteln. Dies ist nützlich um sich Schreibarbeit zu ersparen.
g++ -o main main.o -lpoint -L$PWD
Anschließend könnten wir das Programm ''main'' starten, werden aber die gleiche Meldung erhalten wie bereits angesprochen.
==== Lokales Verzeichnis nach SharedObject durchsuchen =====
Auf Linux-Systemen wird in der Regel nie das Standardverzeichnis nach SharedObjects durchsucht. Jedoch lässt sich dieses Verhalten erzwingen:
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$PWD
Damit wird der Such-Pfad des Linkers ''ld'' um das aktuelle Verzeichnis erweitert. Beispielsweise wird aus dem alten Suchpfad ''/usr/libs'' so ''/usr/libs/:/opt/stuff/'', wenn wir uns im Verzeichnis ''/opt/stuff/'' befinden. Anschließend startet ''main'' ohne Ärger zu machen. Da diese Änderung des Suchpfades aber nicht dauerhaft ist, bleiben effektiv zwei Möglichkeiten
(a) Den Suchpfad dauerhaft zu ändern. Davon rate ich ab: geht man davon zu unbedacht um, verlangsamt dies das Laden anderer Programme, die dann verschiedene andere Suchpfade durchsuchen müssen.
(b) Den Suchpfad durch ein Shellskript modifizieren. So könnte beim Starten das lokale Verzeichnis hinzugefügt und nach Beendigung des Programms entfernt werden.
#/bin/bash
# eine etwas "bashige" Variante des substring-Klassikers
if [ "${LD_LIBRARY_PATH#*$PWD}" == "$LD_LIBRARY_PATH" ]; then
# Lokales Verzeichnis hinzufügen
export LD_LIBRARY_PATH=$PATH:$PWD
fi
# Eigentliches Programm aufrufen
./main
# ggf. lokales Verzeichnis wieder aus dem Suchpfad entfernen
# ... todo
**Hinweis:** ''chmod +x'' nicht vergessen, damit das Skript ausführbar ist ;-)
===== Windows mit MinGW ====
**Hinweise:** Ich habe das folgende mit Wine probiert, da ich kein Windows mehr habe. Sollte sich die Vorgehensweise von einem echten Windows unterscheiden, kann ich das folgende gern noch einmal überarbeiten :)
Zunächst müssen wir aus unserer ''Point''-Implementierung zur dynamischen Library kompilieren. Das klingt wesentlich komplizierter, als es ist:
g++ -shared -o point.dll point.cpp -lmingw32
Anders als unter Linux kann der Dateiname der Library beliebig sein, muss jedoch auf ''.dll'' enden. Dennoch muss die DLL auch hier im Standardverzeichnis liegen - oder man hilft beim Linken nach.
Wie gewohnt können wir unser Programm erst einmal kompilieren:
g++ -c main.cpp
Der letzte Schritt ist auch hier das Linken. Dabei brauchen wir den Namen der Library (ohne ''.dll''). Dazu sollte die DLL im Standardverzeichnis liegen.
g++ -o main.exe main.o -lpoint -lmingw32
Liegt die DLL nicht im Standardverzeichnis, müssen wir den Pfad angeben. Dies geschieht durch ''-LC:\pfad\zur\dll\''. Auf Windows-Systemen können wir die Variable ''%CD%'' verwenden, um das aktuelle Arbeitsverzeichnis zu ermitteln. Dies ist nützlich um sich Schreibarbeit zu ersparen.
g++ -o main.exe main.o -L%CD% -lpoint -lmingw32
Anschließend kann das Programm ''main.exe'' normal gestartet werden. Dabei kann sich die ''point.dll'' sich im Standard-Ordner für DLLs befinden - muss sie aber nicht! Windows-Programme suchen auch im lokalen Verzeichnis nach DLLs. Somit bleibt uns ein Shell-Skript (vgl. unter Linux) erspart: unser Programm läuft auch so.