Come utilizzare le librerie installate da nix in fase di esecuzione?


8

Sto usando nixin "modalità utente singolo" in un sistema in cui non sono il root (vedi sotto per una descrizione della mia configurazione di nix).

Volevo eseguire rapidamente uno dei miei binari che è dinamicamente collegato a una libreria che è assente nel sistema.

Quindi, ho installato la libreria con nix:

$ nix-env -qa 'gmp'
gmp-4.3.2
gmp-5.1.3
$ nix-env -i gmp-5.1.3

Ma la libreria non è ancora stata trovata dal linker:

$ ldd -r ../valencies 
../valencies: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ../valencies)
../valencies: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ../valencies)
    linux-vdso.so.1 =>  (0x00007fffbbf28000)
    /usr/local/lib/libsnoopy.so (0x00007f4dcfbdc000)
    libgmp.so.10 => not found
    libffi.so.5 => /usr/lib64/libffi.so.5 (0x00007f4dcf9cc000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f4dcf748000)
    librt.so.1 => /lib64/librt.so.1 (0x00007f4dcf540000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f4dcf33c000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f4dcf11f000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f4dced8b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f4dcfde7000)
undefined symbol: __gmpz_gcd    (../valencies)
undefined symbol: __gmpn_cmp    (../valencies)
undefined symbol: __gmpz_mul    (../valencies)
undefined symbol: __gmpz_fdiv_r (../valencies)
undefined symbol: __gmpz_fdiv_q_2exp    (../valencies)
undefined symbol: __gmpz_com    (../valencies)
undefined symbol: __gmpn_gcd_1  (../valencies)
undefined symbol: __gmpz_sub    (../valencies)
symbol memcpy, version GLIBC_2.14 not defined in file libc.so.6 with link time reference    (../valencies)
undefined symbol: __gmpz_fdiv_q (../valencies)
undefined symbol: __gmpz_fdiv_qr    (../valencies)
undefined symbol: __gmpz_add    (../valencies)
undefined symbol: __gmpz_init   (../valencies)
undefined symbol: __gmpz_ior    (../valencies)
undefined symbol: __gmpz_mul_2exp   (../valencies)
undefined symbol: __gmpz_xor    (../valencies)
undefined symbol: __gmpz_and    (../valencies)
symbol __fdelt_chk, version GLIBC_2.15 not defined in file libc.so.6 with link time reference   (../valencies)
undefined symbol: __gmpz_tdiv_qr    (../valencies)
undefined symbol: __gmp_set_memory_functions    (../valencies)
undefined symbol: __gmpz_tdiv_q (../valencies)
undefined symbol: __gmpz_divexact   (../valencies)
undefined symbol: __gmpz_tdiv_r (../valencies)
$ 

Guarda, è presente nel filesystem:

$ find / -name 'libgmp.so.10' 2>/dev/null 
/nix/store/mnmzq0qbrvw6dv1k2vj3cwz9ffdh05zr-user-environment/lib/libgmp.so.10
/nix/store/fnww2w81hv5v3dl9gsb7p4llb7z7krzd-gmp-5.1.3/lib/libgmp.so.10
$ 

Cosa devo fare affinché le librerie installate da nixsiano "visibili"?

Probabilmente, lo script di user-installazione standard di nixmodifica .bash_profileper aggiungere la sua bin/in PATH, ma non fare qualcosa di analogo per le biblioteche.

La mia configurazione nix:

L'unica cosa che ho chiesto al root di fare per me è stata: mkdir -m 0755 /nix && chown ivan /nixaltrimenti ho seguito la semplice procedura di installazione standard di nix. Quindi ora posso usare programmi personalizzati dai pacchetti nix. Non potrei farlo bene senza alcun aiuto dalla radice, cioè senza /nix/, perché /nix/non era disponibile per me; Potrei ovviamente usare un'altra directory, ma poi i pacchetti binari pre-compilati non sarebbero validi e tutti i pacchetti dovrebbero essere ricostruiti, secondo la documentazione di nix. Nel mio caso, è stato più semplice chiedere /nix/di me.

Un'altra cosa che ho fatto è aggiungere a ~/.bash_profile:

export NIX_CONF_DIR=/nix/etc/nix

in modo che io possa modificare nix.conf. (Doveva essere nel root-controllato /etc/altrimenti. L'ho fatto perché volevo build-max-jobse build-coresimpostazioni in esso.)


1
Non ne ho mai sentito parlare nix-env, per non parlare nix.conf. Che sistema operativo è questo? Inoltre, cosa vuoi nixdire con riferimenti ripetuti ? L'ho mai sentito solo usato come abbreviazione di Unix, ma sembra che tu lo stia usando in un contesto più specifico.
Faheem Mitha,

3
@FaheemMitha Ho pensato che il tag avesse una descrizione, quindi non ho bisogno di spiegarlo nel post. Ma a quanto pare il tag non ha descrizione. Oh, bene, quindi devo inserire alcuni link. nixè un moderno gestore di pacchetti e nixOS è una distro e Hydra è un sistema per la ricostruzione costante di pacchetti nix e nixOps è uno strumento per gestire una infrastruttura (una rete di più host) in modo dichiarativo e disNix per gestire un insieme di servizi in modo dichiarativo (sopra un'infrastruttura). guixè un figlio di GNU nix, con una distro (promossa da 100% libre IIC
IMZ - Ivan Zakharyaschev

1
Vedo. Grazie per l'informazione. Non ho sentito parlare di nessuno di questi tranne guix.
Faheem Mitha,

Risposte:


7

TL; DR

La soluzione funzionante sta usando patchelf(se hai a che fare con versioni glibc non corrispondenti: nel sistema host e le librerie one nix sono state collegate), vedi la seconda metà della mia storia.

Provando il solito approccio

Tentativo di utilizzare LD_LIBRARY_PATH

Bene, ho impostato una variabile d'ambiente per questo in ~/.bash_profile:

NIX_LINK=/home/ivan/.nix-profile
export LD_LIBRARY_PATH="$NIX_LINK"/lib

ma non è tutto!

Ora ci sono problemi con il collegamento con diverse versioni di libc:

$ ldd -r ../valencies 
../valencies: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ../valencies)
../valencies: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ../valencies)
../valencies: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /home/ivan/.nix-profile/lib/libgmp.so.10)
    linux-vdso.so.1 =>  (0x00007fff365ff000)
    /usr/local/lib/libsnoopy.so (0x00007f56c72e6000)
    libgmp.so.10 => /home/ivan/.nix-profile/lib/libgmp.so.10 (0x00007f56c7063000)
    libffi.so.5 => /usr/lib64/libffi.so.5 (0x00007f56c6e54000)
    libm.so.6 => /lib64/libm.so.6 (0x00007f56c6bd0000)
    librt.so.1 => /lib64/librt.so.1 (0x00007f56c69c7000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f56c67c3000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f56c65a6000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f56c6211000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f56c74f1000)
symbol memcpy, version GLIBC_2.14 not defined in file libc.so.6 with link time reference    (/home/ivan/.nix-profile/lib/libgmp.so.10)
symbol memcpy, version GLIBC_2.14 not defined in file libc.so.6 with link time reference    (../valencies)
symbol __fdelt_chk, version GLIBC_2.15 not defined in file libc.so.6 with link time reference   (../valencies)
$ 

Ordinamento di 2 versioni di glibc

L'errore più sorprendente qui è:

symbol memcpy, version GLIBC_2.14 not defined in file libc.so.6 with link time reference    (/home/ivan/.nix-profile/lib/libgmp.so.10)

perché nixdeve aver installato la versione di glibccui è utilizzato dal suo libgmp!

E infatti, il glibcda nixè lì:

$ ldd -r /home/ivan/.nix-profile/lib/libgmp.so.10
    linux-vdso.so.1 =>  (0x00007fff0f1ff000)
    /usr/local/lib/libsnoopy.so (0x00007f06e9919000)
    libc.so.6 => /nix/store/93zfs0zzndi7pkjkjxawlafdj8m90kg5-glibc-2.20/lib/libc.so.6 (0x00007f06e957c000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f06e9371000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f06e9da7000)
symbol _dl_find_dso_for_object, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference (/nix/store/93zfs0zzndi7pkjkjxawlafdj8m90kg5-glibc-2.20/lib/libc.so.6)
/home/ivan/.nix-profile/lib/libgmp.so.10: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
$ 

Probabilmente, glibcnon era disponibile per l'utente, quindi quando ho eseguito il mio binario, il sistema è glibcstato caricato per primo. Prova:

$ ls ~/.nix-profile/lib/*libc*
ls: cannot access /home/ivan/.nix-profile/lib/*libc*: No such file or directory
$ 

Ok, possiamo provare a rendere glibcvisibile anche all'utente:

$ nix-env -i glibc

Quindi tutto va male:

$ ldd -r ../valencies 
/bin/bash: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
$ /bin/echo ok
/bin/echo: error while loading shared libraries: __vdso_time: invalid mode for dlopen(): Invalid argument
$ 

Quindi, non sembra essere un lavoro facile se vuoi caricare librerie da nixquando esegui i tuoi binari ...

Per ora, sto commentando

export LD_LIBRARY_PATH="$NIX_LINK"/lib

e facendo nella sessione di shell:

$ unset LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

Ho bisogno di pensare di più. (Leggi __vdso_time: modalità non valida per dlopen () : se ne prevede un altro glibcin LD_LIBRARY_PATHcrash, perché il tuo ld-linux-x86-64.so.2non corrisponderà al tuo libc.so.6. Avere più versioni di glibc su un singolo sistema è possibile, ma leggermente complicato, come spiegato in questa risposta.)

La soluzione necessaria: patchelf

Pertanto, il percorso del linker dinamico è codificato nel file binario. E il linker dinamico utilizzato viene dal sistema (dall'host glibc), non da nix. E poiché il linker dinamico non corrisponde al glibc che vogliamo e che dobbiamo usare, non funziona.

Una soluzione semplice e funzionante è patchelf .

patchelf --set-interpreter /home/ivan/.nix-profile/lib/ld-linux-x86-64.so.2 ../valencies

Dopodiché, funziona. Devi comunque giocherellare con LD_LIBRARY_PATH.

$ LD_LIBRARY_PATH=/home/ivan/.nix-profile/lib:/lib64/:/usr/lib64/ ../valencies

Se - come nel mio caso imperfetta - alcune delle librerie sono presi da nix, ma alcuni sono presi dal sistema host (perché non li ho installato con nix-env -i), è necessario specificare sia il percorso per le librerie nix, e nelle librerie del sistema host in LD_LIBRARY_PATH(sostituisce completamente il percorso di ricerca predefinito).

passaggio aggiuntivo: patchelf per il percorso di ricerca della libreria

(dalla patchelfpagina)

Allo stesso modo, è possibile modificare il RPATHpercorso di ricerca del linker incorporato in eseguibili e librerie dinamiche:

patchelf --set-rpath /opt/my-libs/lib:/foo/lib program

Questo fa sì che il linker dinamico esegua la ricerca /opt/my-libs/libe la /foo/libricerca delle librerie condivise necessarie al programma. Naturalmente, puoi anche impostare la variabile d'ambiente LD_LIBRARY_PATH, ma questo è spesso scomodo in quanto richiede uno script wrapper per impostare l'ambiente.


3

Oltre alla "modalità utente singolo" di Nix, offro una risposta per gli utenti NixOS . Di solito non è possibile eseguire file binari su NixOS.

Se installi i pacchetti localmente usando nix-env -i, tutti i tuoi .sofile vengono archiviati ~/.nix-profile/lib/.

Se si installano i pacchetti a livello globale specificandoli in /etc/nixos/configuration.nix, è .sopossibile trovare i file corrispondenti in /nix/var/nix/profiles/system/sw/lib/. Più correttamente, /nix/store/in quella directory sono presenti solo collegamenti simbolici ai file corrispondenti da qualche parte .

Quindi, se installi pacchetti a livello globale, la soluzione di Ivan Zakharyaschev diventa:

$ patchelf --set-interpreter /nix/var/nix/profiles/system/sw/lib/ld-linux-x86-64.so.2 ./YOUREXECUTABLE
$ LD_LIBRARY_PATH=/nix/var/nix/profiles/system/sw/lib ./YOUREXECUTABLE

Perché il primo comando funzioni devi installarlo a glibclivello globale. Puoi anche modificare il secondo comando se hai pacchetti installati sia globalmente che per utente:

$ LD_LIBRARY_PATH=/home/YOURUSERNAME/.nix-profile/lib:/nix/var/nix/profiles/system/sw/lib ./YOUREXECUTABLE

È possibile che il .sofile necessario semplicemente non sia installato nel sistema, quindi si verificherà un errore del tipo:

./YOUREXECUTABLE: error while loading shared libraries: libX11.so.6: cannot open shared object file: No such file or directory

Non sono sicuro di come trovare un pacchetto corrispondente per un file mancante in generale, ma puoi google il nome del .sofile e installare il pacchetto corrispondente e provare a eseguire LD_LIBRARY_PATHnuovamente il tuo eseguibile con un file personalizzato .

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.