Làm thế nào để sử dụng các thư viện được cài đặt bởi nix vào thời gian chạy?


8

Tôi đang sử dụng nixtrong "chế độ một người dùng" trong một hệ thống mà tôi không phải là root (xem bên dưới để biết mô tả về thiết lập nix của tôi).

Tôi muốn nhanh chóng chạy một trong các nhị phân của mình được liên kết động với một thư viện không có trong hệ thống.

Vì vậy, tôi đã cài đặt thư viện với nix:

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

Nhưng thư viện vẫn không được tìm thấy bởi trình liên kết:

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

Hãy nhìn xem, nó có mặt trong hệ thống tập tin:

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

Tôi phải làm gì để các thư viện được cài đặt bởi nix"hiển thị"?

Có lẽ, tập lệnh cài đặt người dùng chuẩn nixsửa đổi .bash_profileđể thêm nó bin/vào PATH, nhưng không làm điều gì đó tương tự cho các thư viện.

Thiết lập nix của tôi:

Điều duy nhất tôi đã yêu cầu root thực hiện cho tôi là: mkdir -m 0755 /nix && chown ivan /nixnếu không, tôi đã làm theo quy trình cài đặt nix đơn giản tiêu chuẩn. Vì vậy, bây giờ tôi có thể sử dụng các chương trình tùy chỉnh từ các gói nix. Tôi không thể làm điều này một cách độc đáo mà không có bất kỳ sự trợ giúp nào từ gốc, tức là không có /nix/, bởi vì /nix/không có sẵn cho tôi; Tất nhiên tôi có thể sử dụng một thư mục khác, nhưng sau đó các gói nhị phân dựng sẵn sẽ không hợp lệ và tất cả các gói sẽ phải được xây dựng lại, theo tài liệu nix. Trong trường hợp của tôi, nó đơn giản hơn để yêu cầu /nix/cho tôi.

Một điều khác tôi đã làm là thêm vào ~/.bash_profile:

export NIX_CONF_DIR=/nix/etc/nix

để tôi có thể chỉnh sửa nix.conf. (Nó được cho là nằm trong quyền kiểm soát gốc /etc/. Tôi đã làm điều đó bởi vì tôi muốn build-max-jobsbuild-corescài đặt trong đó.)


1
Tôi chưa bao giờ nghe nói nix-env, không đề cập đến nix.conf. Hệ điều hành này là gì? Ngoài ra, bạn lặp lại các tài liệu tham khảo nixcó nghĩa là gì? Tôi chỉ nghe thấy nó được sử dụng như một từ viết tắt Unix, nhưng có vẻ như bạn đang sử dụng nó trong một bối cảnh cụ thể hơn.
Faheem Mitha

3
@FaheemMitha Tôi nghĩ rằng thẻ có một số mô tả vì vậy tôi không cần phải giải thích điều này trong bài viết. Nhưng rõ ràng thẻ không có mô tả. Oh, tốt, vì vậy tôi phải đặt trong một số liên kết. nixmột trình quản lý gói hiện đại và nixOS là một bản phân phối và Hydra là một hệ thống để liên tục xây dựng lại các gói nix và nixOps là một công cụ để quản lý một cơ sở hạ tầng (một mạng gồm nhiều máy chủ) và disNix để quản lý một tập hợp các dịch vụ theo cách khai báo (trên cùng của một cơ sở hạ tầng). guixlà con đẻ của GNU nix, với một bản phân phối (được quảng bá là IIC 100% miễn phí
imz - Ivan Zakharyaschev

1
Tôi hiểu rồi. Cảm ơn vì thông tin. Tôi đã nghe nói không ai trong số đó ngoại trừ guix.
Faheem Mitha

Câu trả lời:


7

TL; DR

Giải pháp làm việc đang sử dụng patchelf(nếu bạn phải xử lý các phiên bản glibc không phù hợp: trong hệ thống máy chủ và các nix lib đã được liên kết với), hãy xem nửa sau của câu chuyện của tôi.

Thử cách tiếp cận thông thường

Đang cố gắng sử dụng LD_LIBRARY_PATH

Vâng, tôi đã thiết lập một biến môi trường cho điều này trong ~/.bash_profile:

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

nhưng đó không phải là tất cả!

Bây giờ có vấn đề với việc liên kết với các phiên bản khác nhau của 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)
$ 

Sắp xếp ra 2 phiên bản của glibc

Lỗi đáng kinh ngạc nhất ở đây là:

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)

bởi vì nixphải cài đặt phiên bản glibcđược sử dụng bởi nó libgmp!

Và thực sự, glibctừ nixđó là:

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

Có lẽ, glibckhông có sẵn cho người dùng, vì vậy khi tôi chạy nhị phân của mình, hệ thống glibcđã được tải trước tiên. Bằng chứng:

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

Ok, chúng tôi cũng có thể cố gắng glibchiển thị cho người dùng:

$ nix-env -i glibc

Sau đó, mọi thứ đều tồi tệ:

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

Vì vậy, nó có vẻ không phải là một công việc dễ dàng nếu bạn muốn tải các thư viện từ nixkhi chạy nhị phân của riêng bạn ...

Hiện tại, tôi đang bình luận

export LD_LIBRARY_PATH="$NIX_LINK"/lib

và làm trong phiên shell:

$ unset LD_LIBRARY_PATH
$ export LD_LIBRARY_PATH

Cần suy nghĩ nhiều hơn. (Đọc về __vdso_time: chế độ không hợp lệ cho dlopen () : có khác glibctrong LD_LIBRARY_PATHdự kiến sẽ sụp đổ, bởi vì bạn ld-linux-x86-64.so.2sẽ không phù hợp của bạn libc.so.6Có nhiều phiên bản của glibc trên một hệ thống duy nhất là có thể, nhưng hơi phức tạp, như được giải thích trong câu trả lời này..)

Giải pháp cần thiết: patchelf

Vì vậy, đường dẫn đến trình liên kết động được mã hóa cứng trong tệp nhị phân. Và trình liên kết động đang được sử dụng là từ hệ thống (từ glibc chủ), không phải từ nix. Và bởi vì trình liên kết động không khớp với glibc mà chúng ta muốn và cần sử dụng, nên nó không hoạt động.

Một giải pháp đơn giản và làm việc là patchelf .

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

Sau đó, nó hoạt động. Bạn vẫn cần phải mân mê với LD_LIBRARY_PATHmặc dù.

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

Nếu - như trong trường hợp không hoàn hảo của tôi - một số thư viện được lấy từ nix, nhưng một số được lấy từ hệ thống máy chủ (vì tôi chưa cài đặt chúng nix-env -i), bạn phải chỉ định cả đường dẫn đến nix libs, và hệ thống máy chủ của bạn libs LD_LIBRARY_PATH(nó hoàn toàn ghi đè đường dẫn tìm kiếm mặc định).

bước bổ sung: patchelf cho đường dẫn tìm kiếm thư viện

(từ patchelftrang)

Tương tự, bạn có thể thay đổi RPATH, đường dẫn tìm kiếm liên kết được nhúng vào các tệp thực thi và thư viện động:

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

Điều này khiến trình liên kết động tìm kiếm trong /opt/my-libs/lib/foo/libcho các thư viện chia sẻ cần thiết bởi chương trình. Tất nhiên, bạn cũng có thể đặt biến môi trường LD_LIBRARY_PATH, nhưng điều đó thường bất tiện vì nó yêu cầu tập lệnh bao bọc để thiết lập môi trường.


3

Ngoài chế độ người dùng đơn lẻ Nix của Nix, tôi cung cấp câu trả lời cho người dùng NixOS . Bạn thường không thể chạy các tệp nhị phân trên NixOS.

Nếu bạn cài đặt các gói cục bộ bằng cách sử dụng nix-env -i, tất cả các .sotệp của bạn được lưu trữ trong ~/.nix-profile/lib/.

Nếu bạn cài đặt các gói trên toàn cầu bằng cách chỉ định chúng trong /etc/nixos/configuration.nix, các .sotệp tương ứng của bạn có thể được tìm thấy /nix/var/nix/profiles/system/sw/lib/. Chính xác hơn, chỉ có các liên kết tượng trưng đến các tệp tương ứng ở đâu đó trong /nix/store/thư mục đó.

Vì vậy, nếu bạn cài đặt các gói trên toàn cầu, giải pháp của Ivan Zakharyaschev sẽ trở thành:

$ 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

Để lệnh đầu tiên hoạt động, bạn sẽ phải cài đặt glibctrên toàn cầu. Bạn cũng có thể sửa đổi lệnh thứ hai nếu bạn đã cài đặt các gói trên toàn cầu và cho mỗi người dùng:

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

Có thể là .sotệp cần thiết đơn giản là không được cài đặt trong hệ thống, vì vậy bạn sẽ gặp lỗi như:

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

Tôi không chắc chắn làm thế nào để tìm một gói tương ứng cho một tệp bị thiếu nói chung, nhưng bạn có thể google tên của .sotệp và cài đặt gói tương ứng và thử chạy lại tệp thực thi của bạn với một tùy chỉnh LD_LIBRARY_PATH.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.