Avvolgendo diverse versioni di libreria statica a librerie dinamiche
-
25-09-2019 - |
Domanda
Nel mio progetto c'è una dipendenza da una libreria statica (appena chiamato libsomething
d'ora in poi) da un 3rd party. Recentemente, libsomething
è diventato disponibile in un'altra versione. Il mio compito è quello di fornire il mio software con il supporto per la vecchia e la nuova versione. viene utilizzata solo una versione di libsomething
a run-time in un dato momento, ma quale versione si tratta dovrebbe essere configurabile tra programma viene eseguito.
Sto usando MSVC2005 su WinXP, un obiettivo secondario è quello di diventare pronti a passare a Linux e GCC.
Dal momento che entrambe le versioni di libsomething
stanno usando gli stessi simboli, che collega tutti e due nella mia eseguibile è fuori discussione, come i simboli di entrambe le versioni stanno andando a scontrarsi in tutto al link-tempo.
Mentre ho potuto creare due file eseguibili (uno che collegano contro la vecchia versione, l'altra con la nuova versione), non posso implementare una decisione su quale eseguibile per chiamare in ambiente di distribuzione finale (motivi di eredità).
mi è venuta l'idea di creare un wrapper libreria dinamica per ogni versione di libsomething
e il loro collegamento in fase di esecuzione in base su alcuni file di configurazione. Con MSCV, questo significherebbe andare giù per la strada di usare LoadLibrary()
, GetProcAddress()
, ecc, mentre su Linux avrei dovuto all'uso dlopen()
e dlsym()
.
capisco che usando libtool
(vale a dire, libtldl
) è avvolgente questa piattaforma dipendenza per l'utilizzo di librerie condivise. Si tratta di un percorso appropriato da seguire? ci sono meglio (o, almeno, diversi modi)? Fare alternative per libtldl
esistiamo come open-source?
Soluzione
E 'stato alcuni anni, ma mi piacerebbe parlare di un'altra soluzione per completezza. Invece di dlopen
manuale e dlsym
si potrebbe generare stub semplici per tutte le funzioni necessarie e in prima convocazione (o all'avvio del programma) decidere quale versione della libreria è necessario, caricarlo e risolvere gli indirizzi.
Si potrebbe scrivere uno script specificamente pensati per il vostro progetto o utilizzare Implib.so strumento:
# 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 è solo Linux atm ma dovrebbe essere facilmente adattabile a Windows.
Altri suggerimenti
So che hai detto che non è possibile utilizzare due file eseguibili a causa della decisione di cui si desidera eseguire, ma non si potrebbe exec
avanti e indietro tra gli eseguibili a seconda di quale viene selezionata la versione a configurazione?
In Linux sarebbe più facile per voi di link alla biblioteca e uso comune collegamenti simbolici alla versione corretta -. IMO è molto più facile che usare dlopen()
+ dlsym()
librerie modo si creerebbe in comune per le vecchie e nuove versioni della libreria:
g++ -shared -o libshared.so.1.1 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.old -Wl,-no-whole-archive
e
g++ -shared -o libshared.so.1.2 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.new -Wl,-no-whole-archive
Crea i link simbolici:
ln -s libshared.so.1.1 libshared.so.1
ln -s libshared.so.1 libshared.so
Costruisci la tua applicazione, che lo collega alla vecchia versione della libreria. Suppongo che entrambe le versioni sono compatibili a livello binario (ABI non rotto), ma il nuovo si potrebbe avere alcuni nuovi simboli.
g++ -o myapp myapp.cpp -L. -lshared
Dal SONAME
della libreria condivisa è libshared.so.1
l'applicazione dipenderà su di esso e cercherà libshared.so.1
nei percorsi da /etc/ld.so.conf
o LD_LIBRARY_PATH
Prima di eseguire l'applicazione è possibile impostare il collegamento simbolico libshared.so.1
al punto da libshared.so.1.2
o libshared.so.1.1
.
Poco informazioni sulle opzioni di linker usato qui:
- intero archivio
Per ogni archivio menzionato sulla riga di comando dopo l'opzione --whole-archivio, includere ogni file oggetto nell'archivio nella collegamento, piuttosto che cercare l'archivio per i file oggetto necessari. Questo è normalmente usato per trasformare un file di archivio in una condivisa biblioteca, costringendo ogni oggetto da inserire nella libreria condivisa risultante. Questa opzione può essere utilizzata più di una volta.
Due note quando si utilizza questa opzione dal gcc: In primo luogo, GCC non sapere di questa opzione, quindi bisogna usare -Wl, -Tutto-archivio. In secondo luogo, non dimenticare di usare -Wl, -no-tutta-archivio dopo l'elenco degli archivi, perché gcc aggiungerà una propria lista degli archivi al vostro link e potrebbe non voler questo flag di influenzare quelli pure.-soname = nome
Quando si crea un oggetto ELF condivise, impostare il campo DT_SONAME interna al nome specificato. Quando un file eseguibile è collegato con una oggetto condiviso cui campo DT_SONAME, allora quando l'eseguibile viene eseguito il linker dinamico tenterà di caricare l'oggetto condiviso specificato dal campo DT_SONAME piuttosto che il nome del file utilizzando il dato al linker.