2014-12-09 17 views
6

Desidero utilizzare gcc 4.8.1 per la mia applicazione (richiede libstdC++. So.6.0.18), tuttavia i clienti hanno solo libstdC++. So.6.0.13. Sto usando da un po 'il -static-libgcc -static-stdlibc++, ma la mia applicazione è composta da diverse librerie collegate dinamicamente e da un'applicazione principale. Ciò significa che durante la compilazione di ciascuna libreria dinamica, devono compilare staticamente la libreria standard, che è ridondante e dispendiosa. Voglio solo spedire la libreria standard di mia scelta con il mio prodotto, tuttavia ogni volta che eseguo la mia applicazione in un ambiente come il loro, carica sempre la libreria standard sbagliata. Preferisce la versione /usr/lib64/ indipendentemente da ciò che sembra fare (sembra avere la precedenza su LD_LIBRARY_PATH).Spedizione libstdC++. So.6 con l'applicazione

Vincoli:

  1. io non sono autorizzato a costringerli a effettuare l'aggiornamento a una nuova libreria standard.

  2. Non voglio rendere statiche le librerie dinamiche. (Sarei in grado di compilare staticamente tutto nell'app principale una volta, ma ci sono alcune barriere logistiche che mi impediscono di ricompilare alcune librerie in quelle statiche).

-Wl,-rpath=$(path_to_directory) è un po 'pericoloso, ma è legale perché i clienti fanno fonte alcune impostazioni che mi permettono di impostare variabili di percorso. Tuttavia, l'impostazione del percorso del mio nuovo stdlibC++ non sembra sovrascrivere la versione predefinita /usr/lib64. Ottengo ancora errori GLIBCXX perché non utilizzerà la libreria corretta.

Sicuramente c'è una soluzione elegante per questo?

Forse c'è solo un errore nella mia procedura. Ecco un esempio (dispiace per il censore, ma è solo roba nome utente):

~/example$ pwd 
/home/username/example 
~/example$ echo $LD_LIBRARY_PATH 

~/example$ ls 
Makefile libstdc++.so.6.0.18 test.cpp 
~/example$ make 
g++ -std=c++11 -Wall -Werror test.cpp -o test 
~/example$ ldd test 
./test: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by ./test) 
    linux-vdso.so.1 => (0x00007fffe5919000) 
    libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x000000390b800000) 
    libm.so.6 => /lib64/libm.so.6 (0x0000003904800000) 
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000390b400000) 
    libc.so.6 => /lib64/libc.so.6 (0x0000003904400000) 
    /lib64/ld-linux-x86-64.so.2 (0x0000003904000000) 
~/example$ setenv LD_LIBRARY_PATH /home/username/example 
~/example$ echo $LD_LIBRARY_PATH 
/home/username/example 
~/example$ ldd test 
./test: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.14' not found (required by ./test) 
    linux-vdso.so.1 => (0x00007fff2d3ff000) 
    libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x000000390b800000) 
    libm.so.6 => /lib64/libm.so.6 (0x0000003904800000) 
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x000000390b400000) 
    libc.so.6 => /lib64/libc.so.6 (0x0000003904400000) 
    /lib64/ld-linux-x86-64.so.2 (0x0000003904000000) 

Scusate ragazzi, ho fatto un errore piuttosto stupida ...

~/example$ file libstdc++.so.6.0.18 
libstdc++.so.6.0.18: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, not stripped 

Alcuni dweeb costruito la versione errata del libreria, e un altro dweeb (ovvero me stesso) ha provato ad usarlo su una macchina a 64-bit. L'utilizzo di LD_LIBRARY_PATH funzionava da sempre ...

+0

Mi sarei aspettato che funzionasse LD_LIBRARY_PATH: hai provato a 'ldd'ing il tuo binario con e senza set LD_LIBRARY_PATH? Ricorda inoltre che LD_LIBRARY_PATH non continuerà mai a superare le elevazioni. –

+0

Mostra come si imposta LD_LIBRARY_PATH e anche l'output di 'ldd $ x | fgrep ++ 'dove' $ x' si estende su tutti i binari inviati, con LD_LIBRARY_PATH impostato e/o '-Wl, -rpath =' in effetti. –

+0

Okay, si suppone che 'LD_LIBRARY_PATH' abbia la precedenza? La mia applicazione funziona in modalità utente, quindi non ci sono privilegi elevati. Ecco cosa ho fatto in pratica: compila con gcc 4.8.1 (la sua configurazione risolve i collegamenti con la libreria corretta), imposta 'setenv LD_LIBRARY_PATH/home/myusername /: $ {LD_LIBRARY_PATH}', e poi prova a eseguire/'ldd' il programma . Lo stdlib che voglio in questo esempio è nella mia home directory. Questo dovrebbe avere la precedenza sui percorsi di sistema? – Suedocode

risposta

4

Il tuo problema è che l'eseguibile è collegato al soname libstdc++.so.6 non al nome file completo della libreria libstdc++.so.6.0.16. Il linker dinamico cercherà libstdc++.so.6 nei soliti posti (ad esempio LD_LIBRARY_PATH, DT_RPATH, ldconfig dirs ecc.) In modo da garantire che la versione 6.0.18 sia stata trovata e che sia necessario un collegamento simbolico denominato libstdc++.so.6 che punta ad esso.

Invece di utilizzare LD_LIBRARY_PATH (che è fragile su macchine che non controlli, in quanto gli utenti possono modificare il loro ambiente) Io preferisco Collegamento con '-Wl,-rpath,$ORIGIN' (NB sono necessarie le virgolette per fermare il guscio in espansione $ORIGIN)

An RPATH di $ORIGIN dice al linker dinamico di iniziare a cercare le librerie condivise nella stessa directory dell'eseguibile, quindi se invii libstdC++, così sarà trovato accanto al tuo eseguibile. Se si desidera spedire l'eseguibile in una directory bin e avere la libreria in una directory lib, è possibile utilizzare '-Wl,-rpath,$ORIGIN/../lib' o altri percorsi relativi alla posizione dell'eseguibile.

+0

Ah, ho già visto quella cosa ORIGIN, ma non avevo capito che si trattava di una parola chiave per il linker; Ho pensato che fosse solo una variabile shell comunemente usata (che sarebbe del tutto controproducente). – Suedocode