2011-01-13 15 views
7

Supponiamo che io sono:GCC collegamento a nome del linker di un oggetto condiviso

  • /usr/lib/libsomething.so.1 sulla macchina A;
  • /usr/lib/libsomething.so.2 sulla macchina B.

Entrambe le macchine hanno /usr/lib/libsomething.so link simbolici ai rispettivi librerie.

Se collegamento mediante gcc con -lsomething (o anche /usr/lib/libsomething.so) seguirà il link simbolico, e ldd sulla macchina A produce qualcosa come:

libsomething.so.1 => /usr/lib/libsomething.so.1 

Ciò significa che non sarà in grado di trovare la libreria sulla macchina B.

Ora so che si tratta di modifiche importanti al numero di versione e so che potrebbero non essere compatibili, ma sono disposto a correre questo rischio. Quello che mi piacerebbe dire al linker è quello di cercare libsomething.so, e non seguono il link simbolico in modo ldd mostrerà

libsomething.so => /usr/lib/libsomething.so.1 

su A ma

libsomething.so => /usr/lib/libsomething.so.2 

su B. E poi il caricatore seguirà il link simbolico a qualunque versione ci sia.

Inoltre, non desidero un caricamento ritardato con dlopen o altro. Voglio che si colleghi all'oggetto condiviso al momento della compilazione.

È possibile?

risposta

8

Rendere eseguibile che utilizza qualsiasi versione disponibile della libreria condivisa è, ovviamente, possibile.

Il problema è che si è collegato il vostro eseguibile per specifiche della versione soname (libsomething.so.1 e libsomething.so.2). Avresti dovuto farlo con soname nonverso libsomething.so invece.

Per ottenere ciò, sulla macchina di compilazione è necessario compilare e installare la libreria con soname (ELF SONAME) uguale a libsomething.so (senza versione) in modo che il linker possa scegliere questo soname mentre viene creato l'eseguibile.

Secondo il Shared Libraries HOWTO, è possibile passare richiesto senza versione soname, mentre la costruzione della biblioteca:

gcc -shared -Wl,-soname,libsomething.so -o libsomething.so.X objectsomething.o 

Poi, non appena si installa la libreria ed eseguire ldconfig, si dispone:

  • symlink /lib/libsomething.so che punta a /lib/libsomething.so.1 sulla macchina A;
  • symlink /lib/libsomething.so puntamento per /lib/libsomething.so.2 sulla macchina B.

Il caricatore (run ldd) sceglierà simbolici unversioned indipendentemente da dove si indica:

  • libsomething.so => /lib/libsomething.so (0xNNNNNNNN) sulla macchina A;
  • libsomething.so => /lib/libsomething.so (0xNNNNNNNN) sulla macchina B.

dynamic loader di Linux (ld.so) risolve librerie in base al loro valore di soname scritto nel file eseguibile (ELF NEEDED). Il valore viene copiato dal file di libreria (ELF SONAME) durante la creazione dell'eseguibile. Finché c'è un collegamento simbolico sul sistema di destinazione che corrisponde al soname registrato nell'eseguibile, verrà caricata la libreria puntata da questo collegamento simbolico.


Corriamo attraverso la configurazione e spettacolo comandi per verificando ipotesi.

Ho usato Fedora 18 X86_64 per il test e la potenza regolata su i686 per chiarezza.

  • Compilare sia libsomething.so.1 e libsomething.so.2. Assicurarsi SONAME è impostato senza versione libsomething.so:

    readelf -a libsomething.so.1 | grep SONAME 
    0xNNNNNNNN (SONAME)    Library soname: [libsomething.so] 
    
    readelf -a libsomething.so.2 | grep SONAME 
    0xNNNNNNNN (SONAME)    Library soname: [libsomething.so] 
    
  • installare le librerie nelle rispettive macchine sotto /lib/ directory. Eseguire ldconfig -v su entrambe le macchine e verificare l'output.

    ldconfig -v 2>&1 | grep something 
    libsomething.so -> libsomething.so.1 (changed) 
    
    ldconfig -v 2>&1 | grep something 
    libsomething.so -> libsomething.so.2 (changed) 
    
  • Compile eseguibile e fare in modo che si riferisce allo stesso soname, senza la versione in NEEDED.

    readelf -a executable | grep NEEDED 
    0xNNNNNNNN (NEEDED)    Shared library: [libsomething.so] 
    
  • È eseguibile dipende senza versione libsomething.so ora. Copia eseguibile su entrambe le macchine ed esegui ldd contro entrambe le copie.

    ldd executable 
    libsomething.so => /lib/libsomething.so (0xNNNNNNNN) 
    

    L'ultimo output è lo stesso su entrambe le macchine poiché l'eseguibile è stato creato con soname senza versione. Questo fa sì che il caricatore prenda link simbolici non verificati sulle macchine target. E a seconda della macchina, il collegamento simbolico può puntare a diverse implementazioni della libreria libsomething.so.1 o libsomething.so.2.

+0

Non stavo costruendo la biblioteca in questione, penso che la vera risposta è solo non fare quello che ho suggerito, e se vuoi veramente imbrogliare, usa solo i link simbolici. Ciò ha fornito alcune buone informazioni anche se così sto accettando. –

2

Ciò significa che non sarà in grado di trovare la libreria sulla macchina B.

E non dovrebbe in ogni caso.

Con la definizione stessa di soversions, libsomething.so.2 indica che l'API/ABI non è compatibile con libsomething.so.1. Pertanto, l'aggiunta di libsomething.so nella tabella delle librerie del programma da caricare sarebbe in realtà sbagliata. Il link simbolico libsomething.so funge solo da suggerimento per ld su quale soversion selezionare per impostazione predefinita.

Di qualunque file ld abbia effettivamente finito per aprirsi, richiederà il campo DTNAME/SONAME per la codifica nel programma. Se non lo vuoi, non equipaggiare libsomething con un soname. Ma può facilmente diventare dolore ... iniziando con l'esecuzione di simboli non disponibili durante il tentativo di eseguire il programma.

Problemi correlati