ルートではないシステムで「シングルユーザーモード」でnix
を使用しています(nixの設定については、以下を参照してください)。
システムに存在しないライブラリに動的にリンクされているバイナリの1つをすばやく実行したいと思っていました。
だから、私は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/
を要求する方が簡単でした。
私がやったもう1つのことは、~/.bash_profile
に追加することです。
export NIX_CONF_DIR=/nix/etc/nix
nix.conf
を編集できるようにします。 (それ以外の場合はルート制御された/etc/
にあるはずでした。build-max-jobs
とbuild-cores
の設定をしたかったので、これを行いました。)
実際の解決策はpatchelf
を使用しています(一致しないglibcバージョンに対処する必要がある場合:ホストシステムと1つのnixライブラリがリンクされている場合)、私の話の後半を参照してください。
まあ、私はこのための環境変数を~/.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)
$
ここで最も驚くべきエラーは次のとおりです。
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:invalid mode for dlopen() について読む:LD_LIBRARY_PATH
がld-linux-x86-64.so.2
と一致しないため、libc.so.6
に別のglibc
があるとクラッシュすることが予想されます。この回答で説明されているように、単一のシステムが可能ですが、少しトリッキーです。)
そのため、ダイナミックリンカーへのパスはバイナリにハードコードされています。また、使用されている動的リンカーは、システムから(ホスト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
でそれらをインストールしていないため)、あなたは toは、LD_LIBRARY_PATH
でnixライブラリへのパスとホストシステムライブラリへのパスの両方を指定します(デフォルトの検索パスを完全に上書きします)。
(patchelf
ページから)
同様に、RPATH
、実行可能ファイルと動的ライブラリに埋め込まれたリンカー検索パスを変更できます。
patchelf --set-rpath /opt/my-libs/lib:/foo/lib program
これにより、動的リンカーは、プログラムが必要とする共有ライブラリーを/opt/my-libs/lib
および/foo/lib
で検索します。もちろん、環境変数LD_LIBRARY_PATH
を設定することもできますが、環境を設定するためにラッパースクリプトが必要になるため、多くの場合不便です。
Nixの「シングルユーザーモード」に加えて、私は NixOS ユーザーに回答を提供します。通常、NixOSでは バイナリファイルを実行できません です。
nix-env -i
を使用してパッケージをローカルにインストールする場合、すべての.so
ファイルは~/.nix-profile/lib/
に格納されます。
/etc/nixos/configuration.nix
でパッケージを指定してパッケージ globally をインストールする場合、対応する.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
をグローバルにインストールする必要があります。パッケージをグローバルとユーザーごとの両方にインストールしている場合は、2番目のコマンドを変更することもできます。
$ 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
を使用して実行可能ファイルをもう一度実行してみてください。