Dynamisches Linken

Wie besprochen wollen wir den Code aus dem vorherigen Beispiel dynamisch zu unserem Programm linken. Als Programm können wir folgendes verwenden:

Datei: main.cpp

#include <iostream>
 
#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.