如何在執行時使用 nix 安裝的庫?
我
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
設置。)
TL; 博士
工作解決方案正在使用
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: invalid mode for dlopen():有另一個
glibc
inLD_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
,但這通常很不方便,因為它需要一個包裝腳本來設置環境。