我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
,但不会对库执行类似的操作。
我的尼克斯设置:
我要求 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
答案1
长话短说
可行的解决方案是使用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
fromnix
就在那里:
$ 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() 的模式无效: 另一个glibc
inLD_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
,但这通常很不方便,因为它需要包装脚本来设置环境。
答案2
除了 Nix 的“单用户模式”之外,我还提供了一个答案尼克斯操作系统用户。你通常无法运行二进制文件在 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
再次使用自定义运行可执行文件。