Cosa devo fare se ho due librerie che forniscono funzioni con nomi equivalenti?
vorbis_...
, sf_...
, sdl_...
). Questo è essenzialmente ciò che fa C ++ ai nomi dei simboli per le funzioni con spazio dei nomi.
Cosa devo fare se ho due librerie che forniscono funzioni con nomi equivalenti?
vorbis_...
, sf_...
, sdl_...
). Questo è essenzialmente ciò che fa C ++ ai nomi dei simboli per le funzioni con spazio dei nomi.
Risposte:
A proposito dei commenti: Con "export" intendo rendere visibile ai moduli che si collegano alla libreria --- equivalente alla extern
parola chiave nell'ambito del file. Il modo in cui viene controllato dipende dal sistema operativo e dal linker. Ed è qualcosa che devo sempre cercare.
È possibile rinominare i simboli in un file oggetto usando objcopy --redefine-sym old=new file
(vedi man objcopy).
Quindi chiama le funzioni usando i loro nuovi nomi e collegali al nuovo file oggetto.
In Windows, è possibile utilizzare LoadLibrary () per caricare una di quelle librerie in memoria e quindi utilizzare GetProcAddress () per ottenere l'indirizzo di ciascuna funzione necessaria per chiamare e chiamare le funzioni tramite un puntatore a funzione.
per esempio
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);
otterrebbe l'indirizzo di una funzione chiamata bar in foo.dll e la chiamerebbe.
So che i sistemi Unix supportano funzionalità simili, ma non riesco a pensare ai loro nomi.
dlopen
dlsym
, e dlclose
. Tuttavia, l'incapsulamento su Unix potrebbe non essere efficace come su Windows.
Ecco un pensiero. Apri una delle librerie incriminate in un editor esadecimale e modifica tutte le occorrenze delle stringhe incriminate in qualcos'altro. Dovresti quindi essere in grado di utilizzare i nuovi nomi in tutte le chiamate future.
AGGIORNAMENTO: l' ho appena fatto su questa parte e sembra funzionare. Ovviamente, non l'ho testato a fondo: potrebbe essere solo un ottimo modo per far saltare una gamba con un fucile hexedit.
Supponendo che tu usi Linux devi prima aggiungere
#include <dlfcn.h>
Dichiarare la variabile del puntatore a funzione nel contesto appropriato, ad esempio,
int (*alternative_server_init)(int, char **, char **);
Come ha dichiarato Ferruccio in https://stackoverflow.com/a/678453/1635364 , carica esplicitamente la libreria che desideri utilizzare eseguendo (scegli i tuoi flag preferiti)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Leggi l'indirizzo della funzione che desideri chiamare in seguito
sym = dlsym(dlhandle, "conflicting_server_init");
assegnare e lanciare come segue
alternative_server_init = (int (*)(int, char**, char**))sym;
Chiama in modo simile all'originale. Infine, scarica eseguendo
dlclose(dlhandle);
Non dovresti usarli insieme. Se ricordo bene, il linker genera un errore in questo caso.
Non ho provato, ma una soluzione potrebbe essere con dlopen()
, dlsym()
e dlclose()
che permettono di gestire a livello di programmazione librerie dinamiche. Se non sono necessarie le due funzioni contemporaneamente, è possibile aprire la prima libreria, utilizzare la prima funzione e chiudere la prima libreria prima di utilizzare la seconda libreria / funzione.
Se hai file .o lì, una buona risposta qui: https://stackoverflow.com/a/6940389/4705766
Sommario:
objcopy --prefix-symbols=pre_string test.o
per rinominare i simboli nel file .o o
objcopy --redefine-sym old_str=new_str test.o
per rinominare il simbolo specifico nel file .o.Questo problema è la ragione per cui c ++ ha spazi dei nomi. Non c'è davvero una grande soluzione in c per 2 librerie di terze parti con lo stesso nome.
Se è un oggetto dinamico, potresti essere in grado di caricare esplicitamente gli oggetti condivisi (LoadLibrary / dlopen / ecc.) E chiamarli in quel modo. In alternativa, se non hai bisogno di entrambe le librerie contemporaneamente nello stesso codice, puoi forse fare qualcosa con il collegamento statico (se hai i file .lib / .a).
Nessuna di queste soluzioni si applica a tutti i progetti, ovviamente.
Giurare? Per quanto ne so, non c'è molto che puoi fare se hai due librerie che espongono punti di collegamento con lo stesso nome e devi collegarti a entrambi.
Dovresti scrivere una libreria wrapper attorno a uno di essi. La tua libreria wrapper dovrebbe esporre simboli con nomi univoci e non esporre i simboli dei nomi non univoci.
L'altra opzione è rinominare il nome della funzione nel file di intestazione e rinominare il simbolo nell'archivio oggetti della libreria.
Ad ogni modo, per usarli entrambi, sarà un lavoro da hacker.
La domanda si avvicina a un decennio fa, ma ci sono sempre nuove ricerche ...
Come già risposto, objcopy con il flag --redefine-sym è una buona scelta in Linux. Vedere, ad esempio, https://linux.die.net/man/1/objcopy per la documentazione completa. È un po 'goffo perché stai essenzialmente copiando l'intera libreria mentre apporti modifiche e ogni aggiornamento richiede che questo lavoro venga ripetuto. Ma almeno dovrebbe funzionare.
Per Windows, caricare dinamicamente la libreria è una soluzione e permanente come l'alternativa dlopen in Linux sarebbe. Tuttavia, sia dlopen () che LoadLibrary () aggiungono codice extra che può essere evitato se l'unico problema sono i nomi duplicati. Qui la soluzione Windows è più elegante rispetto all'approccio objcopy: basta dire al linker che i simboli in una libreria sono conosciuti con un altro nome e usare quel nome. Ci sono alcuni passaggi per farlo. È necessario creare un file def e fornire la traduzione del nome nella sezione ESPORTAZIONI. Vedi https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, alla fine verrà sostituito da versioni più recenti) o http://www.digitalmars.com/ctg/ctgDefFiles.html(probabilmente più permanente) per i dettagli completi della sintassi di un file def. Il processo sarebbe creare un file def per una delle librerie, quindi utilizzare questo file def per creare un file lib e quindi collegarlo a quel file lib. (Per le DLL di Windows, i file lib vengono utilizzati solo per il collegamento, non per l'esecuzione del codice.) Vedere Come creare un file .lib quando si dispone di un file .dll e di un file di intestazione per il processo di creazione del file lib. Qui l'unica differenza è l'aggiunta degli alias.
Sia per Linux che per Windows, rinominare le funzioni nelle intestazioni della libreria i cui nomi sono stati alias. Un'altra opzione che dovrebbe funzionare sarebbe, nei file che fanno riferimento ai nuovi nomi, #define old_name new_name, #include le intestazioni della libreria le cui esportazioni sono sottoposte ad alias e quindi #undef old_name nel chiamante. Se sono presenti molti file che utilizzano la libreria, un'alternativa più semplice è creare un'intestazione o più intestazioni che racchiudono le definizioni, le inclusioni e l'annullamento delle definizioni e quindi utilizzare tale intestazione.
Spero che questa informazione sia stata utile!
Non ho mai usato dlsym, dlopen, dlerror, dlclose, dlvsym, ecc., Ma sto guardando la pagina man e fornisce un esempio di apertura di libm.so ed estrazione della funzione cos. Dlopen passa attraverso il processo di ricerca delle collisioni? In caso contrario, l'OP potrebbe caricare manualmente entrambe le librerie e assegnare nuovi nomi a tutte le funzioni fornite dalle sue librerie.