Как использовать библиотеки, установленные nix во время выполнения?

8

Я использую nixв «однопользовательском режиме» в системе, где я не root (см. Ниже описание моей настройки nix).

Я хотел быстро запустить один из моих двоичных файлов, который динамически связан с библиотекой, которая отсутствует в системе.

Итак, я установил библиотеку с nix:

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

Но библиотека все еще не найдена компоновщиком:

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

Смотри, он присутствует в файловой системе:

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

Что мне делать, чтобы установленные библиотеки nixбыли "видны"?

Возможно, стандартный пользовательский скрипт установки nixмодифицирует, .bash_profileчтобы добавить его bin/в PATH, но не делает что-то аналогичное для библиотек.

Моя установка NIX:

Единственное, что я попросил, чтобы root сделал для меня, было: mkdir -m 0755 /nix && chown ivan /nixиначе я следовал стандартной простой процедуре установки nix. Так что теперь я могу использовать пользовательские программы из пакетов nix. Я не смог бы сделать это красиво без какой-либо помощи со стороны рута, т. Е. Без /nix/, потому что /nix/был недоступен для меня; Я мог бы, конечно, использовать другой каталог, но тогда предварительно собранные двоичные пакеты не будут действительными, и все пакеты должны быть перестроены, согласно документации nix. В моем случае было проще попросить /nix/меня.

Еще одна вещь, которую я сделал, добавляет ~/.bash_profile:

export NIX_CONF_DIR=/nix/etc/nix

так что я могу редактировать nix.conf. (В /etc/противном случае он должен был находиться в рут-контроле . Я сделал это, потому что хотел build-max-jobsи build-coresнастройки в нем.)

imz - Иван Захарящев
источник
1
Я никогда не слышал nix-env, не говоря уже о nix.conf. Что это за ОС? Кроме того, что вы повторяли ссылки, чтобы nixиметь в виду? Я только когда-либо слышал, чтобы это использовалось как аббревиатура Unix, но кажется, что вы используете это в более конкретном контексте.
Фахим Митха,
3
@FaheemMitha Я думал, что у тега есть некоторое описание, поэтому мне не нужно объяснять это в посте. Но, видимо, тег не имеет описания. О, ну, так что я должен добавить несколько ссылок. nixэто современный менеджер пакетов , и nixOS является дистрибутивом, а Hydra система для постоянно восстановления NIX пакетов, и nixOps является инструментом для управления инфраструктурой (сеть из нескольких хостов) декларативно и disNix для управления набором услуг декларативно (поверх инфраструктуры). guixявляется потомком GNU nixс дистрибутивом (продвигается как 100% libre IIC
imz - Иван Захарящев
1
Понимаю. Спасибо за информацию. Я не слышал ни об одном из них, кроме guix.
Фахим Митха

Ответы:

7

TL; DR

Рабочее решение использует patchelf(если вам приходится иметь дело с несовпадающими версиями glibc: в хост-системе и с одной библиотекой nix были связаны), смотрите вторую половину моей истории.

Пробуя обычный подход

Попытка использовать LD_LIBRARY_PATH

Ну, я установил переменную окружения для этого в ~/.bash_profile:

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

но это не все!

В настоящее время существуют проблемы со связыванием с различными версиями 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 версии glibc

Самая удивительная ошибка здесь:

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)

потому что nixдолжен был установить версию, glibcкоторая используется его libgmp!

И действительно, glibcот nixтам есть:

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

Возможно, glibcон не был доступен пользователю, поэтому, когда я запустил свой двоичный файл, система glibcбыла загружена первой. Доказательство:

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

Хорошо, мы можем попытаться сделать glibcвидимым для пользователя тоже:

$ nix-env -i glibc

Тогда все плохо

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

Так что, если вы хотите загружать библиотеки nixпри запуске ваших собственных двоичных файлов , это кажется не простой задачей ...

Сейчас я комментирую

export LD_LIBRARY_PATH="$NIX_LINK"/lib

и делать в сеансе оболочки:

$ unset LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

Нужно больше думать. (Читайте о __vdso_time: неверный режим для dlopen () : имея другой glibcин , LD_LIBRARY_PATHкак ожидается , к краху, потому что ваш ld-linux-x86-64.so.2не будет соответствовать вашим libc.so.6Наличие нескольких версий Glibc на одной системе можно, но немного хитрым, как описано в этом ответе.) .

Нужное решение: patchelf

Таким образом, путь к динамическому компоновщику жестко запрограммирован в двоичном файле. И динамический компоновщик используется из системы (с хоста glibc), а не из nix. А поскольку динамический компоновщик не соответствует glibc, который мы хотим и должны использовать, он не работает.

Простое и рабочее решение - патчелф .

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

После этого все работает. Вы все еще должны возиться с LD_LIBRARY_PATHхотя.

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

Если - как в моем несовершенном случае - некоторые библиотеки взяты из nix, но некоторые взяты из хост-системы (потому что я их не установил nix-env -i), вы должны указать оба пути к библиотекам nix, и к вашей системе хоста LD_LIBRARY_PATH(он полностью переопределяет путь поиска по умолчанию).

дополнительный шаг: patchelf для пути поиска библиотеки

(со patchelfстраницы)

Кроме того, вы можете изменить RPATHпуть поиска компоновщика, встроенный в исполняемые файлы и динамические библиотеки:

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

Это заставляет динамический компоновщик искать /opt/my-libs/libи /foo/libсовместно использовать библиотеки, необходимые программе. Конечно, вы также можете установить переменную среды LD_LIBRARY_PATH, но это часто неудобно, так как для настройки среды требуется скрипт-обертка.

imz - Иван Захарящев
источник
3

В дополнение к «однопользовательскому режиму» Nix, я даю ответ пользователям NixOS . Обычно вы не можете запускать двоичные файлы в NixOS.

Если вы устанавливаете пакеты локально nix-env -i, все ваши .soфайлы хранятся в ~/.nix-profile/lib/.

Если вы устанавливаете пакеты глобально , указав их /etc/nixos/configuration.nix, соответствующие .soфайлы можно найти в /nix/var/nix/profiles/system/sw/lib/. Вернее, /nix/store/в этом каталоге находятся только символические ссылки на соответствующие файлы .

Таким образом, если вы устанавливаете пакеты глобально, решение Ивана Захарящева становится:

$ 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

Чтобы первая команда работала, вам нужно установить glibcглобально. Вы также можете изменить вторую команду, если у вас установлены пакеты как глобально, так и для каждого пользователя:

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

Может случиться так, что нужный .soфайл просто не установлен в системе, поэтому у вас будет такая ошибка:

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

Я не уверен, как найти соответствующий пакет для отсутствующего файла в целом, но вы можете погуглить имя .soфайла и установить соответствующий пакет и попробовать снова запустить свой исполняемый файл с кастомом LD_LIBRARY_PATH.

Миржан Иркегулов
источник