Più librerie glibc su un singolo host


171

Più librerie glibc su un singolo host

Il mio server Linux (SLES-8) attualmente ha glibc-2.2.5-235, ma ho un programma che non funzionerà su questa versione e richiede glibc-2.3.3.

È possibile avere più glibcs ​​installati sullo stesso host?

Questo è l'errore che visualizzo quando eseguo il mio programma sul vecchio glibc:

./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./myapp)
./myapp: /lib/i686/libpthread.so.0: version `GLIBC_2.3.2' not found (required by ./myapp)
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libxerces-c.so.27)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)

Così ho creato una nuova directory chiamata newglibc e ho copiato i seguenti file in:

libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so

e

export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH

Ma ricevo un errore:

./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libpthread.so.0)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by libstdc++.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libm.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./newglibc/libc.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libc.so.6)

Quindi sembra che stiano ancora collegando a / lib e non riprendano da dove li ho messi?

Grazie


1
stesso problema con il server SLES-11. Non riesco ad aggiornare e ho bisogno di cose recenti. oh mio ...
UmNyobe,

FWIW, export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH ho risolto il problema per me! Certamente non funzionerà per tutti, ma è una soluzione semplice se funziona! Grazie! :)
Rinogo,

Risposte:


229

È molto possibile avere più versioni di glibc sullo stesso sistema (lo facciamo ogni giorno).

Tuttavia, devi sapere che glibc è composto da molti pezzi (oltre 200 librerie condivise) che devono corrispondere tutti. Uno dei pezzi è ld-linux.so.2, e deve corrispondere a libc.so.6, altrimenti vedrai gli errori che stai vedendo.

Il percorso assoluto di ld-linux.so.2 è hardcoded nell'eseguibile al momento del collegamento e non può essere facilmente modificato al termine del collegamento.

Per creare un eseguibile che funzionerà con il nuovo glibc, procedere come segue:

g++ main.o -o myapp ... \
   -Wl,--rpath=/path/to/newglibc \
   -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

L' -rpathopzione linker farà in modo che il caricatore di runtime cerchi le librerie /path/to/newglibc(quindi non dovresti impostare LD_LIBRARY_PATHprima di eseguirlo) e l' -dynamic-linkeropzione "cuocerà" il percorso per correggere ld-linux.so.2nell'applicazione.

Se non riesci a ricollegare l' myappapplicazione (ad esempio perché è un file binario di terze parti), non tutto è perduto, ma diventa più complicato. Una soluzione è quella di creare un chrootambiente adeguato per questo. Un'altra possibilità è usare rtldi e un editor binario .


3
Si noti che -Wl,--dynamic-linker=file(richiede due '-') funziona solo durante la compilazione per gli eseguibili ELF. Verifica/sbin/ldconfig -p | grep ld
Tom,

49
Ora puoi usare una comoda utility patchelf( nixos.org/patchelf.html ), che ti consente di modificare rpath e interprete di ELF già compilato.
Michael Pankov,

10
Vale la pena ricordare che specificare il percorso per il nuovo utilizzo di glibc -Wl,--rpathpiuttosto che LD_LIBRARY_PATHpuò essere importante per ragioni diverse dalla convenienza: se il programma avvia processi figlio, il valore di LD_LIBRARY_PATHsarà di solito ereditato da loro, ma se non sono anche compilati per l'uso il nuovo glibc (per esempio, se sono binari di scorta come bash), non si avviano.
HighCommander4,

13
Un'altra opzione è eseguire direttamente il nuovo ld.so, passandogli il tuo programma binario come parametro; questo sostituirà efficacemente ld.so utilizzato senza la necessità di ricompilare il programma:/path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
Maximk


67

Questa domanda è vecchia, le altre risposte sono vecchie. La risposta di "Russian Employed" è molto buona e istruttiva, ma funziona solo se hai il codice sorgente. In caso contrario, le alternative allora erano molto complicate. Fortunatamente al giorno d'oggi abbiamo una soluzione semplice a questo problema (come commentato in una delle sue risposte), usando patchelf . Tutto quello che devi fare è:

$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp

E dopo, puoi semplicemente eseguire il tuo file:

$ ./myapp

Per chrootfortuna non è necessario o modificare manualmente i file binari. Ma ricorda di eseguire il backup del tuo file binario prima di correggerlo, se non sei sicuro di cosa stai facendo, perché modifica il tuo file binario. Dopo averlo corretto, non è possibile ripristinare il vecchio percorso di interprete / rpath. Se non funziona, dovrai continuare a patcharlo finché non trovi il percorso che funzionerà effettivamente ... Beh, non deve essere un processo di prova ed errore. Ad esempio, nell'esempio di OP, aveva bisogno GLIBC_2.3, quindi puoi facilmente trovare quale lib fornisce quella versione usando strings:

$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3

In teoria, il primo grep si svuoterebbe perché il sistema libc non ha la versione che vuole, e il secondo dovrebbe produrre GLIBC_2.3 perché ha la versione che myappsta usando, quindi sappiamo che possiamo patchelfusare il nostro binario usando quel percorso.

Quando si tenta di eseguire un binario in Linux, il binario tenta di caricare il linker, quindi le librerie, e dovrebbero essere tutti nel percorso e / o nel posto giusto. Se il tuo problema è con il linker e vuoi scoprire quale percorso sta cercando il tuo binario, puoi scoprirlo con questo comando:

$ readelf -l myapp | grep interpreter
  [Requesting program interpreter: /lib/ld-linux.so.2]                                                                                                                                                                                   

Se il tuo problema è con le librerie, i comandi che ti daranno le librerie utilizzate sono:

$ readelf -d myapp | grep Shared
$ ldd myapp 

Questo elencherà le librerie di cui il tuo binario ha bisogno, ma probabilmente conosci già quelle problematiche, poiché stanno già producendo errori come nel caso di OP.

"patchelf" funziona per molti problemi diversi che potresti incontrare durante il tentativo di eseguire un programma, relativi a questi 2 problemi. Ad esempio, se ottieni ELF file OS ABI invalid:, può essere risolto impostando un nuovo caricatore (la --set-interpreterparte del comando) come spiego qui . Un altro esempio è il problema di ottenere No such file or directoryquando si esegue un file che è lì ed eseguibile, come esemplificato qui . In quel caso particolare, in OP mancava un collegamento al caricatore, ma forse nel tuo caso non hai accesso root e non puoi creare il collegamento. L'impostazione di un nuovo interprete risolverebbe il tuo problema.

Grazie impiegato russo e Michael Pankov per l'intuizione e la soluzione!


1
Questo è stato il più utile! Ho patchato il binario in pitone per usare il nuovo glibc per tensorflow
faizan,

Questa è una soluzione chiara (di cui non avevo mai saputo nulla patchelf), ma la frase "Non c'è bisogno di ... modificare i binari" può essere un po 'fuorviante (dal momento che in realtà stai modificando i tuoi binari).
Larks

Lì, riparato. ;)
msb

Utilità davvero utile! Grazie! Anche se sono riuscito a ottenere un errore di segmentazione solo dopo ore di risoluzione manuale delle dipendenze, patching tutto per installare localmente Chrome senza privilegi di amministratore ...
G. Bergeron,

@fgiraldeau grazie per il complimento. :) ma alla domanda è stata posta, risposto e accettata nel 2009, non mi aspetto che qualcuno aspetti 8 anni prima di accettare una risposta. heheh; D
msb,

20

Usa LD_PRELOAD: metti la tua libreria da qualche parte fuori dalle directory lib man ed esegui:

LD_PRELOAD='mylibc.so anotherlib.so' program

Vedi: l'articolo di Wikipedia


1
pensavo che sarebbe stata una bella soluzione per un Makefile complesso, ma non ha funzionato per me
galactica

che è utile in particolare quelli non binary.thanks sorgente
coder

2
um ... mi sbagliavo, mi sembra di aver bisogno di rpath the ld-linux.so su / path / to / new / lib / frist mentre compilazione e collegamento dei sorgenti
codificatore

1
Questo non funziona se ld - #. ##. So (dal tuo sistema glibc lib) non è la stessa versione di glibc di libc.so. # (dal tuo glibc lib alternativo)
Andy

12

Prima di tutto, la dipendenza più importante di ciascun programma collegato dinamicamente è il linker. Tutte le librerie quindi devono corrispondere alla versione del linker.

Facciamo un semplice esempio: ho il nuovo sistema Ubuntu in cui eseguo un programma (nel mio caso è il compilatore D - ldc2). Vorrei eseguirlo sul vecchio CentOS, ma a causa della vecchia libreria glibc è impossibile. ho ottenuto

ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)

Devo copiare tutte le dipendenze da Ubuntu a Centos. Il metodo corretto è il seguente:

Innanzitutto, controlliamo tutte le dipendenze:

ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 
    linux-vdso.so.1 =>  (0x00007ffebad3f000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)

linux-vdso.so.1 non è una vera libreria e non dobbiamo preoccuparcene.

/lib64/ld-linux-x86-64.so.2 è il linker, che viene usato da Linux per collegare l'eseguibile con tutte le librerie dinamiche.

Il resto dei file è una vera libreria e tutti insieme al linker devono essere copiati da qualche parte nel centos.

Supponiamo che tutte le librerie e il linker siano nella directory "/ mylibs".

ld-linux-x86-64.so.2 - come ho già detto - è il linker. Non è una libreria dinamica ma eseguibile statico. Puoi eseguirlo e vedere che ha anche alcuni parametri, ad esempio --library-path (tornerò su di esso).

Su Linux, il programma collegato dinamicamente può essere pranzato solo dal suo nome, ad es

/bin/ldc2

Linux carica tale programma nella RAM e controlla quale linker è impostato per esso. Di solito, sul sistema a 64 bit, è /lib64/ld-linux-x86-64.so.2 (nel tuo filesystem è un collegamento simbolico al vero eseguibile). Quindi Linux esegue il linker e carica le librerie dinamiche.

Puoi anche cambiarlo un po 'e fare un simile trucco:

/mylibs/ld-linux-x86-64.so.2 /bin/ldc2

È il metodo per forzare Linux a utilizzare un linker specifico.

E ora possiamo tornare al parametro precedente menzionato --library-path

/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2

Eseguirà ldc2 e caricherà le librerie dinamiche da / mylibs.

Questo è il metodo per chiamare l'eseguibile con librerie scelte (non predefinite dal sistema).


Ho compilato un programma su RH7 e ne ho bisogno per funzionare su RH6. Non volevo creare un nuovo eseguibile o usare patchelf, quindi questa è un'ottima alternativa.
Mark Rajcok,

9

Setup 1: compila il tuo glibc senza GCC dedicato e usalo

Questa configurazione potrebbe funzionare ed è rapida in quanto non ricompila l'intera toolchain GCC, ma solo glibc.

Ma non è affidabile in quanto utilizza oggetti host di runtime C come crt1.o, crti.oe crtn.ofornito da glibc. Questo è menzionato in: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Quegli oggetti fanno una configurazione iniziale su cui glibc si affida, quindi non sarei sorpreso se le cose andassero meravigliosamente e modi incredibilmente sottili.

Per una configurazione più affidabile, vedere la Configurazione 2 di seguito.

Compilare glibc e installarlo localmente:

export glibc_install="$(pwd)/glibc/build/install"

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
mkdir build
cd build
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`

Installazione 1: verifica la build

test_glibc.c

#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>

atomic_int acnt;
int cnt;

int f(void* thr_data) {
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
    }
    return 0;
}

int main(int argc, char **argv) {
    /* Basic library version check. */
    printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());

    /* Exercise thrd_create from -pthread,
     * which is not present in glibc 2.27 in Ubuntu 18.04.
     * /programming/56810/how-do-i-start-threads-in-plain-c/52453291#52453291 */
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

Compila ed esegui con test_glibc.sh:

#!/usr/bin/env bash
set -eux
gcc \
  -L "${glibc_install}/lib" \
  -I "${glibc_install}/include" \
  -Wl,--rpath="${glibc_install}/lib" \
  -Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
  -std=c11 \
  -o test_glibc.out \
  -v \
  test_glibc.c \
  -pthread \
;
ldd ./test_glibc.out
./test_glibc.out

Il programma genera l'atteso:

gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674

Comando adattato da https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location ma --sysrootnon riuscito con:

cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install

così l'ho rimosso.

lddoutput conferma che le lddlibrerie e che abbiamo appena creato vengono effettivamente utilizzate come previsto:

+ ldd test_glibc.out
        linux-vdso.so.1 (0x00007ffe4bfd3000)
        libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
        libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
        /home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)

L' gccoutput di debug della compilazione mostra che sono stati utilizzati gli oggetti di runtime dell'host, il che è un male come menzionato in precedenza, ma non so come aggirarlo, ad esempio contiene:

COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o

Setup 1: modifica glibc

Ora modifichiamo glibc con:

diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */

+#include <stdio.h>
+
 #include "thrd_priv.h"

 int
 thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
 {
+  puts("hacked");
   _Static_assert (sizeof (thr) == sizeof (pthread_t),
                   "sizeof (thr) != sizeof (pthread_t)");

Quindi ricompilare e reinstallare glibc, quindi ricompilare ed eseguire nuovamente il nostro programma:

cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh

e vediamo hackedstampato alcune volte come previsto.

Ciò conferma ulteriormente che abbiamo effettivamente utilizzato glibc che abbiamo compilato e non quello host.

Testato su Ubuntu 18.04.

Setup 2: configurazione incontaminata di crosstool-NG

Questa è un'alternativa alla messa a punto 1, ed è la configurazione più corretta che ho raggiunto fino ad ora: tutto è corretto, per quanto posso osservare, compresi gli oggetti il runtime C, come crt1.o, crti.oe crtn.o.

In questa configurazione, compileremo una toolchain GCC completamente dedicata che utilizza glibc che desideriamo.

L'unico aspetto negativo di questo metodo è che la compilazione richiederà più tempo. Ma non rischierei una configurazione di produzione con niente di meno.

crosstool-NG è un insieme di script che scarica e compila tutto dalla fonte per noi, inclusi GCC, glibc e binutils.

Sì, il sistema di compilazione GCC è così male che abbiamo bisogno di un progetto separato per quello.

Questa configurazione non è perfetta solo perché crosstool-NG non supporta la creazione di file eseguibili senza -Wlflag aggiuntivi , il che è strano da quando abbiamo creato GCC stesso. Ma tutto sembra funzionare, quindi questo è solo un inconveniente.

Ottieni crosstool-NG, configuralo e crealo:

git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

La creazione richiede circa trenta minuti o due ore.

L'unica opzione di configurazione obbligatoria che posso vedere è quella di far corrispondere la versione del kernel host per utilizzare le intestazioni del kernel corrette. Trova la versione del kernel host con:

uname -a

che mi mostra:

4.15.0-34-generic

quindi menuconfigfaccio:

  • Operating System
    • Version of linux

quindi seleziono:

4.14.71

che è la prima versione uguale o precedente. Deve essere più vecchio poiché il kernel è retrocompatibile.

Setup 2: configurazioni opzionali

Quello .configche abbiamo generato con ./ct-ng x86_64-unknown-linux-gnuha:

CT_GLIBC_V_2_27=y

Per cambiarlo, menuconfigfai:

  • C-library
  • Version of glibc

salva il .config, e continua con la build.

Oppure, se si desidera utilizzare la propria sorgente glibc, ad esempio per utilizzare glibc dall'ultima versione di git, procedere in questo modo :

  • Paths and misc options
    • Try features marked as EXPERIMENTAL: impostato su vero
  • C-library
    • Source of glibc
      • Custom location: dì di si
      • Custom location
        • Custom source location: punta a una directory contenente la tua sorgente glibc

dove glibc è stato clonato come:

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28

Installazione 2: provalo

Una volta creato il toolchain desiderato, provalo con:

#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
PATH="${PATH}:${install_dir}/bin" \
  x86_64-unknown-linux-gnu-gcc \
  -Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
  -Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
  -v \
  -o test_glibc.out \
  test_glibc.c \
  -pthread \
;
ldd test_glibc.out
./test_glibc.out

Tutto sembra funzionare come nell'installazione 1, tranne per il fatto che ora sono stati utilizzati gli oggetti runtime corretti:

COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o

Installazione 2: tentativo di ricompilazione glibc efficiente non riuscito

Non sembra possibile con crosstool-NG, come spiegato di seguito.

Se hai appena ricostruito;

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

quindi vengono prese in considerazione le modifiche alla posizione dell'origine glibc personalizzata, ma costruisce tutto da zero, rendendolo inutilizzabile per lo sviluppo iterativo.

Se lo facciamo:

./ct-ng list-steps

offre una bella panoramica dei passaggi di costruzione:

Available build steps, in order:
  - companion_tools_for_build
  - companion_libs_for_build
  - binutils_for_build
  - companion_tools_for_host
  - companion_libs_for_host
  - binutils_for_host
  - cc_core_pass_1
  - kernel_headers
  - libc_start_files
  - cc_core_pass_2
  - libc
  - cc_for_build
  - cc_for_host
  - libc_post_cc
  - companion_libs_for_target
  - binutils_for_target
  - debug
  - test_suite
  - finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.

pertanto, vediamo che ci sono passaggi glibc intrecciati con diversi passaggi GCC, in particolare libc_start_filesviene prima cc_core_pass_2, che è probabilmente il passaggio più costoso insieme cc_core_pass_1.

Per compilare un solo passaggio, devi prima impostare l' .configopzione "Salva passaggi intermedi" per la build iniziale:

  • Paths and misc options
    • Debug crosstool-NG
      • Save intermediate steps

e quindi puoi provare:

env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`

ma sfortunatamente, il + necessario come menzionato in: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

Si noti tuttavia che il riavvio in una fase intermedia reimposta la directory di installazione allo stato che aveva durante quella fase. Vale a dire, avrai una libc ricostruita, ma nessun compilatore finale creato con questa libc (e quindi nessuna libreria di compilatori come libstdc ++).

e sostanzialmente rende ancora la ricostruzione troppo lenta per essere fattibile per lo sviluppo, e non vedo come superarla senza patchare crosstool-NG.

Inoltre, a partire dal libcpassaggio non sembra copiare nuovamente l'origine daCustom source location , rendendo ulteriormente inutilizzabile questo metodo.

Bonus: stdlibc ++

Un vantaggio se sei interessato anche alla libreria standard C ++: Come modificare e ricostruire l'origine della libreria standard C ++ di GCC libstdc ++?


6

Puoi prendere in considerazione l'utilizzo di Nix http://nixos.org/nix/ ?

Nix supporta la gestione di pacchetti multiutente: più utenti possono condividere un archivio Nix comune in modo sicuro, non è necessario disporre dei privilegi di root per installare il software e possono installare e utilizzare diverse versioni di un pacchetto.


4

@msb offre una soluzione sicura.

Ho incontrato questo problema quando l'ho fatto import tensorflow as tfin un ambiente conda in CentOS 6.5cui ha solo glibc-2.12.

ImportError: /lib64/libc.so.6: version `GLIBC_2.16' not found (required by /home/

Voglio fornire alcuni dettagli:

Prima installa glibcnella tua home directory:

mkdir ~/glibc-install; cd ~/glibc-install
wget http://ftp.gnu.org/gnu/glibc/glibc-2.17.tar.gz
tar -zxvf glibc-2.17.tar.gz
cd glibc-2.17
mkdir build
cd build
../configure --prefix=/home/myself/opt/glibc-2.17  # <-- where you install new glibc
make -j<number of CPU Cores>  # You can find your <number of CPU Cores> by using **nproc** command
make install

Secondo, segui lo stesso modo per installare patchelf ;

In terzo luogo, patch il tuo Python:

[myself@nfkd ~]$ patchelf --set-interpreter /home/myself/opt/glibc-2.17/lib/ld-linux-x86-64.so.2 --set-rpath /home/myself/opt/glibc-2.17/lib/ /home/myself/miniconda3/envs/tensorflow/bin/python

come menzionato da @msb

Ora posso usare tensorflow-2.0 alphainCentOS 6.5 .

rif: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/


2

Non sono sicuro che la domanda sia ancora pertinente, ma esiste un altro modo per risolvere il problema: Docker. È possibile installare un contenitore quasi vuoto della distribuzione di origine (la distribuzione utilizzata per lo sviluppo) e copiare i file nel contenitore. In questo modo Non è necessario creare il filesystem necessario per chroot.


1

Se osservi attentamente il secondo output, puoi vedere che viene utilizzata la nuova posizione per le librerie. Forse ci sono ancora librerie mancanti che fanno parte del glibc.

Penso anche che tutte le librerie utilizzate dal tuo programma dovrebbero essere compilate con quella versione di glibc. Se hai accesso al codice sorgente del programma, una nuova compilation sembra essere la soluzione migliore.


1

"Impiegato russo" è tra le migliori risposte e penso che tutte le altre risposte suggerite potrebbero non funzionare. Il motivo è semplicemente perché quando un'applicazione viene creata per la prima volta, tutte le sue API necessarie vengono risolte al momento della compilazione. Usando "ldd" puoi vedere tutte le dipendenze staticamente collegate:

ldd /usr/lib/firefox/firefox
    linux-vdso.so.1 =>  (0x00007ffd5c5f0000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f727e708000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f727e500000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f727e1f8000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f727def0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f727db28000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f727eb78000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f727d910000)

Ma in fase di esecuzione, Firefox caricherà anche molte altre librerie dinamiche, ad esempio (per Firefox) ci sono molte librerie con etichetta "glib" caricate (anche se staticamente collegate non ce ne sono):

 /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.2.2
 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0
 /usr/lib/x86_64-linux-gnu/libavahi-glib.so.1.0.2

Molte volte, puoi vedere i nomi di una versione essere soft-link in un'altra versione. Per esempio:

lrwxrwxrwx 1 root root     23 Dec 21  2014 libdbus-glib-1.so.2 -> libdbus-glib-1.so.2.2.2
-rw-r--r-- 1 root root 160832 Mar  1  2013 libdbus-glib-1.so.2.2.2

Ciò significa quindi che esistono diverse versioni di "librerie" in un sistema, il che non è un problema in quanto è lo stesso file e fornirà compatibilità quando le applicazioni hanno dipendenze di più versioni.

Pertanto, a livello di sistema, tutte le librerie sono quasi interdipendenti le une dalle altre e semplicemente cambiare la priorità di caricamento delle librerie manipolando LD_PRELOAD o LD_LIBRARY_PATH non sarà di aiuto - anche se può caricare, il runtime potrebbe comunque arrestarsi in modo anomalo.

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

La migliore alternativa è chroot (menzionata brevemente da ER): ma per questo dovrai ricreare l'intero ambiente in cui è eseguita l'esecuzione binaria originale - di solito a partire da / lib, / usr / lib /, / usr / lib / x86 ecc. Puoi usare "Buildroot" o YoctoProject o semplicemente tar da un ambiente Distro esistente. (come Fedora / Suse ecc.).


0

Quando volevo eseguire un browser al cromo su Ubuntu preciso (glibc-2.15), ho ricevuto il (tipico) messaggio "... libc.so.6: versione` GLIBC_2.19 'non trovata ... ". Ho considerato il fatto che i file non sono necessari in modo permanente, ma solo per iniziare. Quindi ho raccolto i file necessari per il browser e sudo e ho creato un ambiente mini-glibc-2.19, ho avviato il browser e copiato nuovamente i file originali. I file necessari sono nella RAM e l'originale glibc è lo stesso.

as root
the files (*-2.15.so) already exist 

mkdir -p /glibc-2.19/i386-linux-gnu

/glibc-2.19/ld-linux.so.2 -> /glibc-2.19/i386-linux-gnu/ld-2.19.so
/glibc-2.19/i386-linux-gnu/libc.so.6 -> libc-2.19.so
/glibc-2.19/i386-linux-gnu/libdl.so.2 -> libdl-2.19.so
/glibc-2.19/i386-linux-gnu/libpthread.so.0 -> libpthread-2.19.so

mkdir -p /glibc-2.15/i386-linux-gnu

/glibc-2.15/ld-linux.so.2 -> (/glibc-2.15/i386-linux-gnu/ld-2.15.so)
/glibc-2.15/i386-linux-gnu/libc.so.6 -> (libc-2.15.so)
/glibc-2.15/i386-linux-gnu/libdl.so.2 -> (libdl-2.15.so)
/glibc-2.15/i386-linux-gnu/libpthread.so.0 -> (libpthread-2.15.so)

lo script per eseguire il browser:

#!/bin/sh
sudo cp -r /glibc-2.19/* /lib
/path/to/the/browser &
sleep 1
sudo cp -r /glibc-2.15/* /lib
sudo rm -r /lib/i386-linux-gnu/*-2.19.so
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.