Comment utiliser les bibliothèques installées par nix au moment de l'exécution?


8

J'utilise nixen "mode mono-utilisateur" dans un système où je ne suis pas root (voir ci-dessous pour une description de ma configuration nix).

Je voulais exécuter rapidement l'un de mes fichiers binaires qui est lié dynamiquement à une bibliothèque absente du système.

J'ai donc installé la bibliothèque avec nix:

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

Mais la bibliothèque n'est toujours pas trouvée par l'éditeur de liens:

$ 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)
$ 

Regardez, il est présent dans le système de fichiers:

$ 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
$ 

Que dois-je faire pour que les bibliothèques installées par nixsoient "visibles"?

Probablement, le script d'installation utilisateur standard de nixmodifie .bash_profilepour l'ajouter bin/à PATH, mais ne fait pas quelque chose d'analogue pour les bibliothèques.

Ma configuration nix:

La seule chose que j'ai demandé à la racine de faire pour moi était mkdir -m 0755 /nix && chown ivan /nix:, sinon j'ai suivi la procédure d'installation standard de nix simple. Alors maintenant, je peux utiliser des programmes personnalisés à partir de packages nix. Je ne pouvais pas le faire correctement sans aucune aide de la racine, c'est-à-dire sans /nix/, car il /nix/n'était pas disponible pour moi; Je pourrais bien sûr utiliser un autre répertoire, mais les packages binaires pré-construits ne seraient pas valides et tous les packages devraient être reconstruits, selon la documentation de nix. Dans mon cas, c'était plus simple de /nix/me demander .

J'ai également ajouté ~/.bash_profile:

export NIX_CONF_DIR=/nix/etc/nix

afin que je puisse éditer nix.conf. (Il était censé être contrôlé /etc/par la racine sinon. Je l'ai fait parce que je le voulais build-max-jobset les build-coresparamètres.)


1
Je n'en ai jamais entendu parler nix-env, sans parler nix.conf. De quel OS s'agit-il? Aussi, que voulez-vous répéter les références nix? Je ne l'ai jamais entendu que utilisé comme abréviation Unix, mais il semble que vous l'utilisiez dans un contexte plus spécifique.
Faheem Mitha

3
@FaheemMitha Je pensais que la balise avait une description, donc je n'ai pas besoin d'expliquer cela dans le post. Mais apparemment, le tag n'a pas de description. Oh, eh bien, je dois donc mettre quelques liens. nixest un gestionnaire de packages moderne , et nixOS est une distribution, et Hydra est un système pour reconstruire constamment des packages nix, et nixOps est un outil pour gérer une infrastructure (un réseau de plusieurs hôtes) de manière déclarative, et disNix pour gérer un ensemble de services de manière déclarative (au-dessus d'une infrastructure). guixest une progéniture GNU de nix, avec une distribution (promu comme 100% libre IIC
imz - Ivan Zakharyaschev

1
Je vois. Merci pour l'information. Je n'ai entendu parler de rien de tout cela sauf guix.
Faheem Mitha

Réponses:


7

TL; DR

La solution de travail utilise patchelf(si vous devez faire face à des versions de glibc non correspondantes: dans le système hôte et les bibliothèques nix ont été liées), voir la deuxième moitié de mon histoire.

Essayer l'approche habituelle

Essayer d'utiliser LD_LIBRARY_PATH

Eh bien, j'ai mis en place une variable d'environnement pour cela dans ~/.bash_profile:

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

Mais ce n'est pas tout!

Il existe maintenant des problèmes de liaison avec différentes versions de 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)
$ 

Tri de 2 versions de glibc

L'erreur la plus surprenante ici est:

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)

car nixdoit avoir installé la version glibcqui est utilisée par son libgmp!

Et en effet, le glibcfrom nixest 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
$ 

Probablement, glibcn'était pas disponible pour l'utilisateur, donc quand j'ai exécuté mon binaire, le système a glibcété chargé en premier. Preuve:

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

Ok, nous pouvons aussi essayer de rendre glibcvisible à l'utilisateur:

$ nix-env -i glibc

Alors tout va mal:

$ 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
$ 

Donc, cela ne semble pas être une tâche facile si vous souhaitez charger des bibliothèques nixlors de l'exécution de vos propres binaires ...

Pour l'instant, je commente

export LD_LIBRARY_PATH="$NIX_LINK"/lib

et faire dans la session shell:

$ unset LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

Besoin de réfléchir davantage. (Lisez à propos __vdso_time: mode invalide pour la dlopen () : ayant une autre glibcen LD_LIBRARY_PATHdevrait accident, parce que votre ld-linux-x86-64.so.2ne correspondra pas à votre libc.so.6présence de plusieurs versions de glibc sur un seul système est possible, mais un peu délicat, comme expliqué dans cette réponse.).

La solution recherchée: patchelf

Ainsi, le chemin vers l'éditeur de liens dynamique est codé en dur dans le binaire. Et l'éditeur de liens dynamique utilisé provient du système (de la glibc hôte), pas de nix. Et parce que l'éditeur de liens dynamique ne correspond pas à la glibc que nous voulons et devons utiliser, cela ne fonctionne pas.

Une solution simple et fonctionnelle est le patchelf .

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

Après ça, ça marche. Vous devez toujours jouer avec LD_LIBRARY_PATH.

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

Si - comme dans mon cas imparfait - certaines des bibliothèques sont prises à partir de nix, mais d'autres à partir du système hôte (parce que je ne les ai pas installées avec nix-env -i), vous devez spécifier à la fois le chemin vers les bibliothèques nix, et vers les bibliothèques de votre système hôte LD_LIBRARY_PATH(il remplace complètement le chemin de recherche par défaut).

étape supplémentaire: patchelf pour le chemin de recherche de la bibliothèque

(à partir de la patchelfpage)

De même, vous pouvez modifier le RPATH, le chemin de recherche de l'éditeur de liens intégré dans les exécutables et les bibliothèques dynamiques:

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

Cela oblige l'éditeur de liens dynamique à rechercher dans /opt/my-libs/libet /foo/libpour les bibliothèques partagées nécessaires au programme. Bien sûr, vous pouvez également définir la variable d'environnement LD_LIBRARY_PATH, mais cela est souvent gênant car il nécessite un script wrapper pour configurer l'environnement.


3

En plus du «mode mono-utilisateur» de Nix, je fournis une réponse aux utilisateurs de NixOS . Vous ne pouvez généralement pas exécuter de fichiers binaires sur NixOS.

Si vous installez des packages localement à l'aide de nix-env -i, tous vos .sofichiers sont stockés dans ~/.nix-profile/lib/.

Si vous installez des packages globalement en les spécifiant dans /etc/nixos/configuration.nix, vos .sofichiers correspondants se trouvent dans /nix/var/nix/profiles/system/sw/lib/. Plus correctement, seuls les liens symboliques vers les fichiers correspondants quelque part se /nix/store/trouvent dans ce répertoire.

Donc, si vous installez des packages à l'échelle mondiale, la solution d'Ivan Zakharyaschev devient:

$ 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

Pour que la première commande fonctionne, vous devez installer glibcglobalement. Vous pouvez également modifier la deuxième commande si des packages sont installés à la fois globalement et par utilisateur:

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

Il se peut que le .sofichier nécessaire ne soit tout simplement pas installé dans le système, vous aurez donc une erreur comme:

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

Je ne sais pas comment trouver un package correspondant pour un fichier manquant en général, mais vous pouvez rechercher le nom du .sofichier sur Google , installer le package correspondant et essayer d'exécuter à nouveau votre exécutable avec un fichier personnalisé LD_LIBRARY_PATH.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.