Wrapping verschiedene Versionen von statischer Bibliothek in dynamischen Bibliotheken
-
25-09-2019 - |
Frage
In meinem Projekt gibt es eine Abhängigkeit von einer statischen Bibliothek (nur genannt libsomething
von jetzt an) von einer dritten Partei. Vor kurzem libsomething
hat in einer anderen Version verfügbar ist. Meine Aufgabe ist es, meine Software mit Unterstützung für die alte und die neue Version zur Verfügung zu stellen. Nur eine Version von libsomething
wird zur Laufzeit zu einem bestimmten Zeitpunkt verwendet, aber welche Version sollte dies zwischen Programm läuft sein konfigurierbar ist.
Ich bin mit MSVC2005 auf WinXP, ein sekundäres Ziel ist vorbereitet zu werden, um Linux und GCC zu wechseln.
Da beide Versionen von libsomething
sind die gleichen Symbole verwendet, welches sie verbinden beide in meine ausführbaren Datei ist nicht in Frage, da die Symbole beiden Versionen werden alle auf Link-Zeit über kollidieren.
Während ich zwei ausführbare Dateien erstellen könnte (eine Verknüpfung mit der alten Version, die andere die neue Version verwendet wird), kann ich keine Entscheidung implementieren, auf dem ausführbaren Datei in der letzten Implementierungsumgebung zu nennen (legacy Gründe).
kam ich auf die Idee, eine dynamische Bibliothek Wrapper für jede Version von libsomething
zu schaffen und deren Verknüpfung zur Laufzeit abhängig von einigen Konfigurationsdatei. Mit MSCV, würde dies bedeuten, die Straße hinunter ging der Verwendung LoadLibrary()
, GetProcAddress()
usw., während auf Linux ich Gebrauch dlopen()
und dlsym()
hat.
Ich verstehe, dass libtool
mit (das heißt libtldl
) wickelt diese Plattform-Abhängigkeit für gemeinsam genutzte Bibliotheken. Ist dies ein geeigneter Weg zu folgen? Gibt es bessere (oder zumindest verschiedene) Arten? Haben Alternativen für libtldl
exist als Open-Source?
Lösung
Es ist nun einige Jahre her, aber ich möchte eine andere Lösung für Vollständigkeit erwähnen. Anstelle des manuellen dlopen
und dlsym
könnten Sie einfache Stubs für alle notwendigen Funktionen erzeugen und auf den ersten Anruf (oder beim Programmstart) entscheiden, welche Version der Bibliothek benötigt wird, wird sie und die Adressen auflösen.
Sie können ein Skript speziell für Ihr Projekt zugeschnitten schreiben oder verwenden Sie Implib.so -Tool:
# This will generate mylib.so.init.c and mylib.so.tramp.S
# which implement stubs. These need to be linked to your
# executable.
$ implib-gen.py mylib.so
Implib.so ist Linux-only atm sollte aber auf Windows leicht anpassbar sein.
Andere Tipps
Ich weiß, Sie sagen, Sie nicht zwei ausführbare Dateien aufgrund der Entscheidung, welche ausführen verwenden konnten, konnten aber nicht Sie exec
hin und her zwischen ausführbaren Dateien je nachdem, welcher Version bei der Konfiguration ausgewählt wird?
Unter Linux wäre es einfacher für Sie, um eine Verknüpfung zu gemeinsam genutzten Bibliothek und Verwendung Symlinks auf korrekte Version -. IMO ist es viel einfacher als die Verwendung von dlopen()
+ dlsym()
So würden Sie die alten und neuen Versionen Ihrer Bibliothek gemeinsam genutzten Bibliotheken für erstellen:
g++ -shared -o libshared.so.1.1 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.old -Wl,-no-whole-archive
und
g++ -shared -o libshared.so.1.2 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.new -Wl,-no-whole-archive
die Symlinks:
ln -s libshared.so.1.1 libshared.so.1
ln -s libshared.so.1 libshared.so
Erstellen Sie Ihre Anwendung, um es in der alten Version der Bibliothek zu verknüpfen. Ich nehme beide Versionen sind binärkompatibel (ABI nicht gebrochen), aber die neue man konnte einige neue Symbole haben.
g++ -o myapp myapp.cpp -L. -lshared
Da die gemeinsame Bibliothek SONAME
ist libshared.so.1
Ihre Anwendung auf sie abhängen und libshared.so.1
in Pfaden von /etc/ld.so.conf
oder LD_LIBRARY_PATH
Bevor Sie Ihre Anwendung ausführen können Sie den libshared.so.1
Symlink Punkt auf libshared.so.1.2
oder libshared.so.1.1
gesetzt.
Wenig Informationen über die Linker-Optionen verwendeten hier:
- Ganz Archiv
Für jedes Archiv in der Befehlszeile nach der --whole-Archiv Option erwähnt, umfasst jede Objektdatei im Archiv in der Link, anstatt das Archiv für die erforderlichen Objektdateien zu suchen. Dies wird normalerweise verwendet, um eine Archivdatei in einen gemeinsam genutzten drehen Bibliothek und zwingt jedes Objekt werden in der resultierenden gemeinsam genutzten Bibliothek enthalten. Diese Option kann mehrfach verwendet werden.
Zwei Anmerkungen, wenn Sie diese Option aus gcc: Erstens, gcc weiß nicht, über diese Option, so dass Sie verwenden müssen -Wl, -ganz-Archiv. Zweitens, nicht vergessen -Wl zu verwenden, -NO-ganze-Archiv nach der Liste der Archive, weil gcc seine eigene Liste von Archiven hinzufügen, wird Ihre Link und Sie können nicht wollen, dass diese Flagge diese ebenfalls beeinflussen.-soname = name
Beim Erstellen eines ELF Objekt geteilt wird, setzen die interne DT_SONAME Feld zu dem angegebenen Namen. Wenn eine ausführbare Datei mit einem verknüpften gemeinsames Objekt, das eine DT_SONAME Feld hat, dann, wenn die ausführbare betrieben, um den dynamischen Linker versuchen wird, das gemeinsame Objekt zu laden, durch das DT_SONAME Feld angegeben, anstatt der Verwendung des Dateinamens an den Linker gegeben.