如何在运行时使用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-jobsbuild-cores它的设置。)


1
我从未听说过nix-env,更不用说nix.conf。这是什么操作系统?另外,您重复提及什么nix意思?我只听说过它用作的缩写Unix,但似乎您是在更特定的上下文中使用它。
Faheem Mitha 2015年

3
@FaheemMitha我以为标签有一些描述,所以我不需要在帖子中解释。但显然,该标签没有描述。哦,好,所以我必须添加一些链接。nix现代的软件包管理器,nixOS是发行版,Hydra是用于不断重建nix软件包的系统,nixOps是用于声明式管理基础结构(由多个主机组成的网络)的工具,而disNix是用于声明式管理一组服务的工具。 (在基础架构之上)。guix是的GNU子孙nix,具有发行版(晋升为100%自由IIC
imz – Ivan Zakharyaschev

1
我知道了。谢谢你的信息。除了这些我什么都没有听说guix
Faheem Mitha 2015年

Answers:


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

并在shell会话中执行以下操作:

$ unset LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

需要多考虑。(有关__vdso_time的信息:dlopen()的无效模式:可能会有另一个glibcin LD_LIBRARY_PATH崩溃,因为您ld-linux-x86-64.so.2与之不匹配libc.so.6。如本答案所述,在单个系统上具有多个版本的glibc是可能的,但是有点棘手。)

所需的解决方案:patchelf

因此,动态链接程序的路径被硬编码在二进制文件中。动态链接器来自系统(来自主机glibc),而不来自nix。而且因为动态链接器与我们想要和需要使用的glibc不匹配,所以它不起作用。

一个简单而可行的解决方案是patchelf

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,但这通常很不方便,因为它需要一个包装器脚本来设置环境。


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/是,该目录中只有指向相应文件的符号链接。

因此,如果在全球范围内安装软件包,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

为了使第一个命令起作用,您必须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再次使用自定义程序运行可执行文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.