Wie verwende ich Bibliotheken, die zur Laufzeit von nix installiert wurden?


8

Ich verwende nixim "Einzelbenutzermodus" in einem System, in dem ich nicht der Root bin (siehe unten für eine Beschreibung meines Nix-Setups).

Ich wollte schnell eine meiner Binärdateien ausführen, die dynamisch mit einer Bibliothek verknüpft ist, die im System nicht vorhanden ist.

Also habe ich die Bibliothek installiert mit nix:

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

Aber die Bibliothek wird vom Linker immer noch nicht gefunden:

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

Schauen Sie, es ist im Dateisystem vorhanden:

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

Was mache ich, damit die von installierten Bibliotheken nix"sichtbar" sind?

Wahrscheinlich, das Standard - Benutzerinstallationsskript von nixändert .bash_profileseine hinzufügen bin/in PATH, aber nicht etwas Analoges für Bibliotheken tun.

Mein Nix-Setup:

Das einzige, was ich vom Root verlangt habe, war: mkdir -m 0755 /nix && chown ivan /nixAnsonsten habe ich das einfache Standard-Nix-Installationsverfahren befolgt. Jetzt kann ich benutzerdefinierte Programme aus nix-Paketen verwenden. Ich konnte dies ohne die Hilfe der Wurzel überhaupt nicht gut machen, dh ohne /nix/, weil /nix/es für mich nicht verfügbar war; Ich könnte natürlich ein anderes Verzeichnis verwenden, aber dann wären die vorgefertigten Binärpakete nicht gültig und alle Pakete müssten gemäß der Nix-Dokumentation neu erstellt werden. In meinem Fall war es einfacher, /nix/nach mir zu fragen .

Eine andere Sache, die ich getan habe, ist das Hinzufügen zu ~/.bash_profile:

export NIX_CONF_DIR=/nix/etc/nix

damit ich bearbeiten kann nix.conf. (Es sollte sonst in der Root-Steuerung sein /etc/. Ich habe es getan, weil ich wollte build-max-jobsund build-coresEinstellungen darin.)


1
Ich habe noch nie davon gehört nix-env, ganz zu schweigen davon nix.conf. Welches Betriebssystem ist das? Was bedeuten wiederholte Referenzen nix? Ich habe nur gehört, dass es als Abkürzung für verwendet wird Unix, aber es scheint, dass Sie es in einem spezifischeren Kontext verwenden.
Faheem Mitha

3
@FaheemMitha Ich dachte, das Tag hätte eine Beschreibung, daher muss ich dies nicht im Beitrag erklären. Aber anscheinend hat das Tag keine Beschreibung. Na ja, also muss ich ein paar Links einfügen. nixist ein moderner Paketmanager , und nixOS ist eine Distribution, und Hydra ist ein System zum ständigen Neuerstellen von nix-Paketen. nixOps ist ein Tool zum deklarativen Verwalten einer Infrastruktur (eines Netzwerks aus mehreren Hosts) und disNix zum deklarativen Verwalten einer Reihe von Diensten (auf einer Infrastruktur). guixist ein GNU-Nachkomme von nix, mit einer Distribution (gefördert als 100% libre IIC
imz - Ivan Zakharyaschev

1
Aha. Danke für die Auskunft. Ich habe von keinem außer denen gehört guix.
Faheem Mitha

Antworten:


7

TL; DR

Die funktionierende Lösung verwendet patchelf(wenn Sie sich mit nicht übereinstimmenden glibc-Versionen befassen müssen: im Host-System und mit dem, mit dem nix libs verknüpft wurden), siehe die zweite Hälfte meiner Geschichte.

Den üblichen Ansatz versuchen

Versuch, LD_LIBRARY_PATH zu verwenden

Nun, ich habe eine Umgebungsvariable dafür eingerichtet in ~/.bash_profile:

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

aber das ist nicht alles!

Jetzt gibt es Probleme beim Verknüpfen mit verschiedenen Versionen von 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)
$ 

2 Versionen von glibc aussortieren

Der überraschendste Fehler hier ist:

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)

denn nixmuss installiert haben, welche version glibcvon seiner verwendet wird libgmp!

Und tatsächlich ist das glibcvon nixda:

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

Wahrscheinlich glibcwar es für den Benutzer nicht verfügbar. Als ich meine Binärdatei ausführte, wurde das System glibczuerst geladen. Beweis:

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

Ok, wir können versuchen, dies glibcauch für den Benutzer sichtbar zu machen :

$ nix-env -i glibc

Dann ist alles schlecht:

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

Es scheint also keine leichte Aufgabe zu sein, wenn Sie Bibliotheken laden möchten, wenn Sie nixIhre eigenen Binärdateien ausführen ...

Im Moment kommentiere ich aus

export LD_LIBRARY_PATH="$NIX_LINK"/lib

und in der Shell-Sitzung tun:

$ unset LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

Ich muss mehr nachdenken. (Lesen Sie mehr über __vdso_time: Ungültiger Modus für dlopen () : Es wird erwartet, dass ein anderer glibcin LD_LIBRARY_PATHabstürzt, da Ihr ld-linux-x86-64.so.2nicht mit Ihrem übereinstimmt libc.so.6. Es ist möglich, mehrere Versionen von glibc auf einem einzigen System zu haben, aber etwas schwierig, wie in dieser Antwort erläutert.)

Die benötigte Lösung: Patchelf

Der Pfad zum dynamischen Linker ist also in der Binärdatei fest codiert. Der verwendete dynamische Linker stammt vom System (vom Host glibc) und nicht von nix. Und weil der dynamische Linker nicht mit dem Glibc übereinstimmt, den wir verwenden möchten und müssen, funktioniert er nicht.

Eine einfache und funktionierende Lösung ist Patchelf .

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

Danach funktioniert es. Sie müssen jedoch immer noch damit herumspielen LD_LIBRARY_PATH.

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

Wenn - wie in meinem Fall unvollkommen - einige der Bibliotheken von nichts genommen werden, aber einige werden von dem Host - System entnommen (weil ich nicht installiert habe sie mit nix-env -i), Sie müssen sowohl den Pfad zu dem nichts Libs angeben, und zu Ihrem Hostsystem libs in LD_LIBRARY_PATH(es überschreibt den Standardsuchpfad vollständig).

zusätzlicher Schritt: Patchelf für den Bibliothekssuchpfad

(von der patchelfSeite)

Ebenso können Sie RPATHden Linker-Suchpfad ändern , der in ausführbare Dateien und dynamische Bibliotheken eingebettet ist:

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

Dadurch sucht der dynamische Linker in /opt/my-libs/libund /foo/libnach den vom Programm benötigten gemeinsam genutzten Bibliotheken. Natürlich können Sie auch die Umgebungsvariable festlegen LD_LIBRARY_PATH, dies ist jedoch häufig unpraktisch, da zum Einrichten der Umgebung ein Wrapper-Skript erforderlich ist.


3

Zusätzlich zum „Einzelbenutzermodus“ von Nix gebe ich eine Antwort für NixOS- Benutzer. Normalerweise können Sie unter NixOS keine Binärdateien ausführen.

Wenn Sie Pakete lokal mit installieren nix-env -i, werden alle Ihre .soDateien in gespeichert ~/.nix-profile/lib/.

Wenn Sie Pakete global installieren, indem Sie sie in angeben /etc/nixos/configuration.nix, finden Sie die entsprechenden .soDateien in /nix/var/nix/profiles/system/sw/lib/. Richtiger ist, /nix/store/dass sich in diesem Verzeichnis nur Symlinks zu entsprechenden Dateien befinden.

Wenn Sie also Pakete global installieren, lautet die Lösung von Ivan Zakharyaschev :

$ 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

Damit der erste Befehl funktioniert, müssen Sie ihn glibcglobal installieren . Sie können den zweiten Befehl auch ändern, wenn Sie Pakete sowohl global als auch pro Benutzer installiert haben:

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

Es kann sein, dass die benötigte .soDatei einfach nicht im System installiert ist, sodass folgende Fehler auftreten:

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

Ich bin nicht sicher, wie ich ein entsprechendes Paket für eine fehlende Datei im Allgemeinen finden kann, aber Sie können den Namen der .soDatei googeln, das entsprechende Paket installieren und versuchen, Ihre ausführbare Datei erneut mit einer benutzerdefinierten Datei auszuführen LD_LIBRARY_PATH.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.