Bagaimana cara menggunakan pustaka yang diinstal oleh nix saat run-time?

8

Saya menggunakan nixdalam "mode single-user" dalam sistem di mana saya bukan root (lihat di bawah untuk deskripsi pengaturan nix saya).

Saya ingin cepat menjalankan salah satu binari saya yang secara dinamis terkait dengan perpustakaan yang tidak ada dalam sistem.

Jadi, saya telah menginstal perpustakaan dengan nix:

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

Namun perpustakaan masih belum ditemukan oleh tautan:

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

Lihat, ini ada di sistem file:

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

Apa yang harus saya lakukan agar perpustakaan yang diinstal nix"terlihat"?

Mungkin, script user-instalasi standar nixmemodifikasi .bash_profileuntuk menambahkan nya bin/ke dalam PATH, tapi tidak melakukan sesuatu yang analog untuk perpustakaan.

Pengaturan nix saya:

Satu-satunya hal yang saya minta dilakukan root untuk saya adalah mkdir -m 0755 /nix && chown ivan /nix:, jika tidak, saya telah mengikuti prosedur instalasi nix sederhana standar. Jadi sekarang saya bisa menggunakan program khusus dari paket nix. Saya tidak dapat melakukan ini dengan baik tanpa bantuan dari root sama sekali, yaitu, tanpa /nix/, karena /nix/tidak tersedia untuk saya; Saya tentu saja dapat menggunakan direktori lain, tetapi kemudian paket-paket biner pra-dibangun tidak akan valid dan semua paket harus dibangun kembali, menurut dokumentasi nix. Dalam kasus saya, lebih mudah untuk meminta /nix/saya.

Hal lain yang saya lakukan adalah menambahkan ~/.bash_profile:

export NIX_CONF_DIR=/nix/etc/nix

sehingga saya bisa mengedit nix.conf. (Seharusnya di root-dikendalikan /etc/sebaliknya. Saya melakukannya karena saya ingin build-max-jobsdan build-corespengaturan di dalamnya.)

imz - Ivan Zakharyaschev
sumber
1
Belum pernah saya dengar nix-env, belum lagi nix.conf. OS apa ini? Juga, apa yang Anda nixmaksud dengan referensi berulang ? Saya hanya pernah mendengarnya digunakan sebagai singkatan Unix, tetapi sepertinya Anda menggunakannya dalam konteks yang lebih spesifik.
Faheem Mitha
3
@FaheemMitha Saya pikir tag memiliki deskripsi jadi saya tidak perlu menjelaskan ini dalam posting. Namun ternyata tag tersebut tidak memiliki deskripsi. Oh, well, jadi saya harus memasukkan beberapa tautan. nixadalah manajer paket modern , dan nixOS adalah distro, dan Hydra adalah sistem untuk terus-menerus membangun kembali paket nix, dan nixOps adalah alat untuk mengelola infrastruktur (jaringan beberapa host) secara deklaratif, dan menonaktifkan untuk mengelola serangkaian layanan secara deklaratif (di atas infrastruktur). guixadalah keturunan GNU dari nix, dengan distro (dipromosikan sebagai 100% gratis IIC
imz - Ivan Zakharyaschev
1
Saya melihat. Terima kasih untuk informasi. Saya belum pernah mendengar hal itu kecuali guix.
Faheem Mitha

Jawaban:

7

TL; DR

Solusi yang digunakan adalah menggunakan patchelf(jika Anda harus berurusan dengan versi glibc yang tidak cocok: di sistem host dan satu lib lix telah dikaitkan dengan), lihat bagian kedua dari cerita saya.

Mencoba pendekatan yang biasa

Mencoba menggunakan LD_LIBRARY_PATH

Yah, saya telah menyiapkan variabel lingkungan untuk ini di ~/.bash_profile:

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

tapi itu belum semuanya!

Sekarang ada masalah dengan menautkan dengan berbagai versi 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)
$ 

Menyortir 2 versi glibc

Kesalahan paling mengejutkan di sini adalah:

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)

karena nixpasti sudah menginstal versi glibcyang digunakan oleh nya libgmp!

Dan memang, glibcdari nixsana:

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

Mungkin, glibctidak tersedia untuk pengguna, jadi ketika saya menjalankan biner saya, sistem glibcdimuat terlebih dahulu. Bukti:

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

Oke, kita juga bisa mencoba membuatnya glibcterlihat oleh pengguna:

$ nix-env -i glibc

Maka semuanya buruk:

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

Jadi, sepertinya bukan pekerjaan yang mudah jika Anda ingin memuat pustaka dari nixsaat menjalankan binari Anda sendiri ...

Untuk saat ini, saya berkomentar

export LD_LIBRARY_PATH="$NIX_LINK"/lib

dan lakukan di sesi shell:

$ unset LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

Perlu berpikir lebih jauh. (Baca tentang __vdso_time: modus valid untuk dlopen () : memiliki lain glibcdi LD_LIBRARY_PATHdiharapkan kecelakaan, karena Anda ld-linux-x86-64.so.2tidak akan cocok Anda libc.so.6Memiliki beberapa versi glibc pada sistem tunggal adalah mungkin, tapi sedikit rumit, seperti yang dijelaskan dalam jawaban ini..)

Solusi yang dibutuhkan: patchelf

Jadi, path ke dynamic linker adalah hard-coded dalam biner. Dan linker dinamis yang digunakan adalah dari sistem (dari host glibc), bukan dari nix. Dan karena penghubung dinamis tidak cocok dengan glibc yang kita inginkan dan perlu kita gunakan, itu tidak berfungsi.

Solusi sederhana dan berhasil adalah patchelf .

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

Setelah itu berhasil. Anda masih perlu mengutak-atik LD_LIBRARY_PATH.

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

Jika - seperti dalam kasus tidak sempurna saya - beberapa perpustakaan diambil dari nix, tetapi beberapa diambil dari sistem host (karena saya belum menginstalnya dengan nix-env -i), Anda harus menentukan kedua path ke nix libs, dan ke sistem host Anda, libs in LD_LIBRARY_PATH(itu sepenuhnya mengesampingkan jalur pencarian default).

langkah tambahan: patchelf untuk jalur pencarian perpustakaan

(dari patchelfhalaman)

Demikian juga, Anda dapat mengubah RPATH, jalur pencarian tautan yang tertanam ke executable dan perpustakaan dinamis:

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

Ini menyebabkan tautan dinamis untuk mencari /opt/my-libs/libdan /foo/libuntuk perpustakaan bersama yang dibutuhkan oleh program. Tentu saja, Anda juga dapat mengatur variabel lingkungan LD_LIBRARY_PATH, tetapi itu seringkali tidak nyaman karena memerlukan skrip wrapper untuk mengatur lingkungan.

imz - Ivan Zakharyaschev
sumber
3

Selain "mode pengguna tunggal" Nix, saya memberikan jawaban untuk pengguna NixOS . Anda biasanya tidak dapat menjalankan file biner di NixOS.

Jika Anda menginstal paket menggunakan lokal nix-env -i, semua .sofile Anda disimpan ~/.nix-profile/lib/.

Jika Anda menginstal paket secara global dengan menetapkannya /etc/nixos/configuration.nix, .sofile yang sesuai dapat ditemukan di /nix/var/nix/profiles/system/sw/lib/. Lebih tepatnya, hanya symlinks ke file yang sesuai di suatu tempat di /nix/store/dalam direktori itu.

Jadi jika Anda menginstal paket secara global, solusi Ivan Zakharyaschev menjadi:

$ 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

Agar perintah pertama berfungsi, Anda harus menginstal glibcsecara global. Anda juga dapat memodifikasi perintah kedua jika Anda memiliki paket yang diinstal secara global dan per-pengguna:

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

Mungkin saja .sofile yang dibutuhkan tidak diinstal di sistem, jadi Anda akan memiliki kesalahan seperti:

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

Saya tidak yakin bagaimana menemukan paket yang sesuai untuk file yang hilang secara umum, tetapi Anda dapat google nama .sofile dan menginstal paket yang sesuai dan mencoba untuk menjalankan executable Anda dengan kustom LD_LIBRARY_PATHlagi.

Mirzhan Irkegulov
sumber