Was soll ich tun, wenn ich zwei Bibliotheken habe, die Funktionen mit gleichwertigen Namen bereitstellen?
vorbis_...
, sf_...
, sdl_...
). Dies ist im Wesentlichen das, was C ++ mit den Symbolnamen für Funktionen mit Namespace macht.
Was soll ich tun, wenn ich zwei Bibliotheken habe, die Funktionen mit gleichwertigen Namen bereitstellen?
vorbis_...
, sf_...
, sdl_...
). Dies ist im Wesentlichen das, was C ++ mit den Symbolnamen für Funktionen mit Namespace macht.
Antworten:
Apropos die Kommentare: Mit "exportieren" meine ich für Module sichtbar zu machen, die mit der Bibliothek verknüpft sind - entspricht dem extern
Schlüsselwort im Dateibereich. Wie dies gesteuert wird, hängt vom Betriebssystem und vom Linker ab. Und das muss ich immer nachschlagen.
Es ist möglich, Symbole in einer Objektdatei mit umzubenennen objcopy --redefine-sym old=new file
(siehe man objcopy).
Rufen Sie dann einfach die Funktionen mit ihren neuen Namen auf und verknüpfen Sie sie mit der neuen Objektdatei.
Unter Windows können Sie mit LoadLibrary () eine dieser Bibliotheken in den Speicher laden und dann mit GetProcAddress () die Adresse jeder Funktion abrufen, die Sie aufrufen müssen, und die Funktionen über einen Funktionszeiger aufrufen.
z.B
HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);
würde die Adresse einer Funktion namens bar in foo.dll erhalten und sie aufrufen.
Ich weiß, dass Unix-Systeme ähnliche Funktionen unterstützen, aber ich kann mir ihre Namen nicht vorstellen.
dlopen
dlsym
und dlclose
. Die Kapselung unter Unix ist jedoch möglicherweise nicht so effektiv wie unter Windows.
Hier ist ein Gedanke. Öffnen Sie eine der fehlerhaften Bibliotheken in einem Hex-Editor und ändern Sie alle Vorkommen der fehlerhaften Zeichenfolgen in etwas anderes. Sie sollten dann in der Lage sein, die neuen Namen in allen zukünftigen Anrufen zu verwenden.
UPDATE: Ich habe es gerade zu diesem Zweck gemacht und es scheint zu funktionieren. Natürlich habe ich das nicht gründlich getestet - es ist möglicherweise nur eine wirklich gute Möglichkeit, Ihr Bein mit einer Hexedit-Schrotflinte abzublasen.
Angenommen, Sie verwenden Linux, müssen Sie zuerst hinzufügen
#include <dlfcn.h>
Deklarieren Sie die Funktionszeigervariable im richtigen Kontext, z.
int (*alternative_server_init)(int, char **, char **);
Laden Sie, wie Ferruccio unter https://stackoverflow.com/a/678453/1635364 angegeben hat , explizit die Bibliothek, die Sie verwenden möchten, indem Sie sie ausführen (wählen Sie Ihre Lieblingsflags aus).
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Lesen Sie die Adresse der Funktion, die Sie später aufrufen möchten
sym = dlsym(dlhandle, "conflicting_server_init");
zuweisen und wie folgt besetzen
alternative_server_init = (int (*)(int, char**, char**))sym;
Rufen Sie auf ähnliche Weise wie das Original an. Zum Schluss durch Ausführen entladen
dlclose(dlhandle);
Sie sollten sie nicht zusammen verwenden. Wenn ich mich richtig erinnere, gibt der Linker in einem solchen Fall einen Fehler aus.
Ich habe nicht versucht, aber eine Lösung kann sein mit dlopen()
, dlsym()
und dlclose()
die es erlauben Sie programmatisch dynamische Bibliotheken handhaben . Wenn Sie die beiden Funktionen nicht gleichzeitig benötigen, können Sie die erste Bibliothek öffnen, die erste Funktion verwenden und die erste Bibliothek schließen, bevor Sie die zweite Bibliothek / Funktion verwenden.
Wenn Sie dort .o-Dateien haben, finden Sie hier eine gute Antwort: https://stackoverflow.com/a/6940389/4705766
Zusammenfassung:
objcopy --prefix-symbols=pre_string test.o
um die Symbole in der .o-Datei umzubenennen oder
objcopy --redefine-sym old_str=new_str test.o
um das spezifische Symbol in der .o-Datei umzubenennen.Dieses Problem ist der Grund, warum c ++ Namespaces hat. Es gibt in c keine wirklich gute Lösung für 2 Bibliotheken von Drittanbietern mit demselben Namen.
Wenn es sich um ein dynamisches Objekt handelt, können Sie die freigegebenen Objekte (LoadLibrary / dlopen / etc) möglicherweise explizit laden und auf diese Weise aufrufen. Wenn Sie nicht beide Bibliotheken gleichzeitig im selben Code benötigen, können Sie möglicherweise etwas mit statischer Verknüpfung tun (wenn Sie die .lib / .a-Dateien haben).
Keine dieser Lösungen gilt natürlich für alle Projekte.
Schwören? Soweit mir bekannt ist, können Sie nicht viel tun, wenn Sie zwei Bibliotheken haben, die Verknüpfungspunkte mit demselben Namen verfügbar machen, und Sie müssen gegen beide verknüpfen.
Sie sollten eine Wrapper-Bibliothek um eine von ihnen schreiben. Ihre Wrapper-Bibliothek sollte Symbole mit eindeutigen Namen und nicht die Symbole der nicht eindeutigen Namen verfügbar machen.
Sie können auch den Funktionsnamen in der Header-Datei umbenennen und das Symbol im Archiv des Bibliotheksobjekts umbenennen.
So oder so, um beides zu nutzen, wird es ein Hack-Job.
Die Frage nähert sich einem Jahrzehnt, aber es gibt ständig neue Suchanfragen ...
Wie bereits beantwortet, ist objcopy mit dem Flag --redefine-sym unter Linux eine gute Wahl. Eine vollständige Dokumentation finden Sie beispielsweise unter https://linux.die.net/man/1/objcopy . Es ist etwas umständlich, da Sie im Wesentlichen die gesamte Bibliothek kopieren, während Sie Änderungen vornehmen, und jedes Update erfordert, dass diese Arbeit wiederholt wird. Aber zumindest sollte es funktionieren.
Für Windows ist das dynamische Laden der Bibliothek eine Lösung und eine dauerhafte Lösung wie die dlopen-Alternative unter Linux. Sowohl dlopen () als auch LoadLibrary () fügen jedoch zusätzlichen Code hinzu, der vermieden werden kann, wenn das einzige Problem doppelte Namen sind. Hier ist die Windows-Lösung eleganter als der objcopy-Ansatz: Sagen Sie dem Linker einfach, dass die Symbole in einer Bibliothek unter einem anderen Namen bekannt sind, und verwenden Sie diesen Namen. Es gibt ein paar Schritte dazu. Sie müssen eine def-Datei erstellen und die Namensübersetzung im Abschnitt EXPORTS bereitstellen. Siehe https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015 wird möglicherweise durch neuere Versionen ersetzt) oder http://www.digitalmars.com/ctg/ctgDefFiles.html(wahrscheinlich dauerhafter) für vollständige Syntaxdetails einer def-Datei. Der Prozess wäre, eine Def-Datei für eine der Bibliotheken zu erstellen und diese Def-Datei dann zu verwenden, um eine Lib-Datei zu erstellen und dann mit dieser Lib-Datei zu verknüpfen. (Bei Windows-DLLs werden lib-Dateien nur zum Verknüpfen und nicht zur Codeausführung verwendet.) Weitere Informationen zum Erstellen der lib-Datei finden Sie unter Erstellen einer .lib-Datei, wenn eine DLL-Datei und eine Header- Datei vorhanden sind. Hier besteht der einzige Unterschied darin, die Aliase hinzuzufügen.
Benennen Sie unter Linux und Windows die Funktionen in den Headern der Bibliothek um, deren Namen als Alias verwendet werden. Eine andere Option, die funktionieren sollte, wäre, in Dateien, die sich auf die neuen Namen beziehen, # alten_Namen neuen_Namen zu definieren, # die Header der Bibliothek einzuschließen, deren Exporte aliasiert werden, und dann #undef alten_namen im Aufrufer. Wenn die Bibliothek viele Dateien verwendet, besteht eine einfachere Alternative darin, einen oder mehrere Header zu erstellen, die die Definitionen, Includes und Undefs umschließen, und diesen Header dann zu verwenden.
Hoffe diese Info war hilfreich!
Ich habe noch nie dlsym, dlopen, dlerror, dlclose, dlvsym usw. verwendet, aber ich schaue auf die Manpage und sie enthält ein Beispiel für das Öffnen von libm.so und das Extrahieren der cos-Funktion. Geht dlopen nach Kollisionen? Wenn dies nicht der Fall ist, kann das OP beide Bibliotheken einfach manuell laden und allen Funktionen, die seine Bibliotheken bereitstellen, neue Namen zuweisen.