Các phương pháp khác nhau để chạy một tệp thực thi không phải là nixos trên NixO là gì? Tôi cũng muốn xem các phương pháp thủ công.
Các phương pháp khác nhau để chạy một tệp thực thi không phải là nixos trên NixO là gì? Tôi cũng muốn xem các phương pháp thủ công.
Câu trả lời:
Dưới đây là một số phương pháp (những phương pháp thủ công chủ yếu dành cho mục đích giáo dục vì hầu hết thời gian viết một dẫn xuất thích hợp là tốt hơn). Tôi hoàn toàn không phải là một chuyên gia và tôi cũng đã làm danh sách này để học nix, vì vậy nếu bạn có phương pháp tốt hơn, hãy cho tôi biết!
Vì vậy, vấn đề chính là cuộc gọi thực thi đầu tiên là trình tải, sau đó cần một số thư viện để làm việc và nixos đặt cả trình tải và thư viện vào /nix/store/
.
Danh sách này cung cấp cho tất cả các phương pháp tôi tìm thấy cho đến nay. Về cơ bản có ba "nhóm":
Tôi muốn giới thiệu phương pháp 4 với autoPatchelfHook
một thiết lập thực, phù hợp và nếu bạn không có thời gian và chỉ muốn chạy nhị phân trong một dòng, bạn có thể quan tâm đến giải pháp nhanh và bẩn dựa trên steam-run
(phương pháp 7 ).
Trước tiên, bạn cần tìm trình tải với ví dụ file
:
$ file wolframscript
wolframscript: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.18, BuildID[sha1]=079684175aa38e3633b60544681b338c0e8831e0, stripped
Đây là bộ nạp /lib64/ld-linux-x86-64.so.2
. Để tìm trình tải của nixos, bạn có thể làm:
$ ls /nix/store/*glibc*/lib/ld-linux-x86-64.so.2
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2
Bạn cũng cần tìm để tìm các thư viện mà chương trình của bạn yêu cầu, ví dụ như ldd
:
$ ldd wolframscript
linux-vdso.so.1 (0x00007ffe8fff9000)
libpthread.so.0 => /nix/store/sw54ph775lw7b9g4hlfvpx6fmlvdy8qi-glibc-2.27/lib/libpthread.so.0 (0x00007f86aa321000)
librt.so.1 => /nix/store/sw54ph775lw7b9g4hlfvpx6fmlvdy8qi-glibc-2.27/lib/librt.so.1 (0x00007f86aa317000)
libdl.so.2 => /nix/store/sw54ph775lw7b9g4hlfvpx6fmlvdy8qi-glibc-2.27/lib/libdl.so.2 (0x00007f86aa312000)
libstdc++.so.6 => not found
libm.so.6 => /nix/store/sw54ph775lw7b9g4hlfvpx6fmlvdy8qi-glibc-2.27/lib/libm.so.6 (0x00007f86aa17c000)
libgcc_s.so.1 => /nix/store/sw54ph775lw7b9g4hlfvpx6fmlvdy8qi-glibc-2.27/lib/libgcc_s.so.1 (0x00007f86a9f66000)
libc.so.6 => /nix/store/sw54ph775lw7b9g4hlfvpx6fmlvdy8qi-glibc-2.27/lib/libc.so.6 (0x00007f86a9dae000)
/lib64/ld-linux-x86-64.so.2 => /nix/store/sw54ph775lw7b9g4hlfvpx6fmlvdy8qi-glibc-2.27/lib64/ld-linux-x86-64.so.2 (0x00007f86aa344000)
Ở đây, bạn thấy rằng hầu hết các thư viện được tìm thấy ngoại trừ libstdc++.so.6
. Vì vậy, hãy tìm nó:
$ find /nix/store -name libstdc++.so.6
/nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/libstdc++.so.6
Tốt Bây giờ, chúng ta chỉ cần chạy chương trình với LD_LIBRARY_PATH
cấu hình để trỏ đến tệp này và gọi trình nạp mà chúng ta đã xác định ở bước đầu tiên trên tệp này:
LD_LIBRARY_PATH=/nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/:$LD_LIBRARY_PATH /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 ./wolframscript
(đảm bảo sử dụng ./
trước tên tập lệnh và chỉ giữ thư mục của các thư viện. Nếu bạn có một số thư viện, chỉ cần sử dụng concat đường dẫn với dấu hai chấm)
Sau khi cài đặt (có nixenv -i
hoặc trong của bạn configuration.nix
) patchelf
, bạn cũng có thể trực tiếp sửa đổi tệp thực thi để đóng gói trình tải và thư viện tốt. Để thay đổi trình tải, chỉ cần chạy:
patchelf --set-interpreter /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 wolframscript
và để kiểm tra:
$ patchelf --print-interpreter wolframscript
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.
và để thay đổi đường dẫn đến các thư viện được mã hóa cứng trong tệp thực thi, trước tiên hãy kiểm tra xem đường dẫn hiện tại là gì (trống đối với tôi):
$ patchelf --print-rpath wolframscript
và nối chúng vào đường dẫn thư viện mà bạn đã xác định trước đó, cuối cùng được phân tách bằng dấu hai chấm:
$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript
Chúng ta có thể tái tạo ít nhiều điều tương tự trong một dẫn xuất nix lấy cảm hứng từ skypeforlinux
Ví dụ này cũng là một lựa chọn thay thế, bạn có thể sử dụng:
patchelf --set-interpreter ${glibc}/lib/ld-linux-x86-64.so.2 "$out/bin/wolframscript" || true
(sẽ khá rõ ràng khi bạn hiểu phương pháp "thủ công") hoặc
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/bin/wolframscript" || true
Phương pháp thứ hai này tinh tế hơn một chút, nhưng nếu bạn chạy:
$ nix-shell '<nixpkgs>' -A hello --run 'echo $NIX_CC/nix-support/dynamic-linker "->" $(cat $NIX_CC/nix-support/dynamic-linker)'
/nix/store/8zfm4i1aw4c3l5n6ay311ds6l8vd9983-gcc-wrapper-7.4.0/nix-support/dynamic-linker -> /nix/store/sw54ph775lw7b9g4hlfvpx6fmlvdy8qi-glibc-2.27/lib/ld-linux-x86-64.so.2
bạn sẽ thấy rằng tập tin $NIX_CC/nix-support/dynamic-linker
chứa một đường dẫn đến trình tải ld-linux-x86-64.so.2
.
Đặt vào derivation.nix
, đây là
{ stdenv, dpkg,glibc, gcc-unwrapped }:
let
# Please keep the version x.y.0.z and do not update to x.y.76.z because the
# source of the latter disappears much faster.
version = "12.0.0";
rpath = stdenv.lib.makeLibraryPath [
gcc-unwrapped
glibc
];
# What is it for?
# + ":${stdenv.cc.cc.lib}/lib64";
src = ./WolframScript_12.0.0_LINUX64_amd64.deb;
in stdenv.mkDerivation {
name = "wolframscript-${version}";
system = "x86_64-linux";
inherit src;
nativeBuildInputs = [
];
buildInputs = [ dpkg ];
unpackPhase = "true";
# Extract and copy executable in $out/bin
installPhase = ''
mkdir -p $out
dpkg -x $src $out
cp -av $out/opt/Wolfram/WolframScript/* $out
rm -rf $out/opt
'';
postFixup = ''
# Why does the following works?
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/bin/wolframscript" || true
# or
# patchelf --set-interpreter ${glibc}/lib/ld-linux-x86-64.so.2 "$out/bin/wolframscript" || true
patchelf --set-rpath ${rpath} "$out/bin/wolframscript" || true
'';
meta = with stdenv.lib; {
description = "Wolframscript";
homepage = https://www.wolfram.com/wolframscript/;
license = licenses.unfree;
maintainers = with stdenv.lib.maintainers; [ ];
platforms = [ "x86_64-linux" ];
};
}
và default.nix
đưa vào:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
Biên dịch và chạy với
nix-build
result/bin/wolframscript
Tất cả các phương thức trước đó cần một chút công việc (bạn cần tìm các tệp thực thi, vá chúng ...). NixO đã làm cho chúng tôi một "cái móc" đặc biệt autoPatchelfHook
tự động vá mọi thứ cho bạn! Bạn chỉ cần xác định nó trong (native)BuildInputs
, và nix thực hiện phép thuật.
{ stdenv, dpkg, glibc, gcc-unwrapped, autoPatchelfHook }:
let
# Please keep the version x.y.0.z and do not update to x.y.76.z because the
# source of the latter disappears much faster.
version = "12.0.0";
src = ./WolframScript_12.0.0_LINUX64_amd64.deb;
in stdenv.mkDerivation {
name = "wolframscript-${version}";
system = "x86_64-linux";
inherit src;
# Required for compilation
nativeBuildInputs = [
autoPatchelfHook # Automatically setup the loader, and do the magic
dpkg
];
# Required at running time
buildInputs = [
glibc
gcc-unwrapped
];
unpackPhase = "true";
# Extract and copy executable in $out/bin
installPhase = ''
mkdir -p $out
dpkg -x $src $out
cp -av $out/opt/Wolfram/WolframScript/* $out
rm -rf $out/opt
'';
meta = with stdenv.lib; {
description = "Wolframscript";
homepage = https://www.wolfram.com/wolframscript/;
license = licenses.mit;
maintainers = with stdenv.lib.maintainers; [ ];
platforms = [ "x86_64-linux" ];
};
}
Một số phần mềm có thể khó đóng gói theo cách đó vì chúng có thể phụ thuộc nhiều vào cấu trúc cây tệp FHS hoặc có thể kiểm tra xem tệp nhị phân không thay đổi. Sau đó, bạn cũng có thể sử dụng buildFHSUserEnv để cung cấp cấu trúc tệp FHS (nhẹ, sử dụng không gian tên) cho ứng dụng của bạn. Lưu ý rằng phương pháp này nặng hơn các phương thức dựa trên bản vá và thêm thời gian khởi động đáng kể, vì vậy hãy tránh nó khi có thể
Bạn có thể chỉ cần sinh ra một trình bao và sau đó trích xuất thủ công tệp lưu trữ và thực thi tệp hoặc trực tiếp đóng gói chương trình của bạn cho FHS. Trước tiên chúng ta hãy xem làm thế nào để có được một cái vỏ. Đặt trong một tập tin (nói fhs-env.nix
) như sau:
let nixpkgs = import <nixpkgs> {};
in nixpkgs.buildFHSUserEnv {
name = "fhs";
targetPkgs = pkgs: [];
multiPkgs = pkgs: [ pkgs.dpkg ];
runScript = "bash";
}
và chạy:
nix-build fhs-env.nix
result/bin/fhs
Sau đó, bạn sẽ nhận được một bash trong một linux trông chuẩn hơn và bạn có thể chạy các lệnh để chạy tệp thực thi của mình, như:
mkdir wolf_fhs/
dpkg -x WolframScript_12.0.0_LINUX64_amd64.deb wolf_fhs/
cd wolf_fhs/opt/Wolfram/WolframScript/bin/
./wolfram
Nếu bạn cần thêm thư viện / chương trình làm phụ thuộc, chỉ cần thêm chúng vào multiPkgs
(cho tất cả các targetPkgs
vòm được hỗ trợ) hoặc (chỉ dành cho vòm hiện tại).
Phần thưởng: bạn cũng có thể khởi chạy shell fhs bằng lệnh một dòng, mà không cần tạo tệp specifc:
nix-build -E '(import <nixpkgs> {}).buildFHSUserEnv {name = "fhs";}' && ./result/bin/fhs
nguồn: https://reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html
Với buildFHSUserEnv
bạn có thể chạy rất nhiều phần mềm, nhưng bạn sẽ cần chỉ định thủ công tất cả các thư viện cần thiết. Nếu bạn muốn có một giải pháp nhanh chóng và bạn không có thời gian để kiểm tra chính xác các thư viện cần thiết là gì, bạn có thể muốn thử steam-run
(mặc dù tên, nó không được liên kết trực tiếp với steam và chỉ chứa rất nhiều thư viện), đó là giống như buildFHSUserEnv
rất nhiều thư viện phổ biến được cài đặt sẵn (một số trong số chúng có thể không miễn phí như steamrt
gói đó chứa một số mã nvidia, cảm ơn simpson!). Để sử dụng nó, chỉ cần cài đặt steam-run
, và sau đó:
steam-run ./wolframscript
hoặc nếu bạn muốn có một vỏ đầy đủ:
steam-run bash
Lưu ý rằng bạn có thể cần thêm nixpkgs.config.allowUnfree = true;
(hoặc danh sách trắng gói cụ thể này ) nếu bạn muốn cài đặt nó nixos-rebuild
và nếu bạn muốn chạy / cài đặt nó với nix-shell
/ nix-env
bạn cần phải đặt { allowUnfree = true; }
vào ~/.config/nixpkgs/config.nix
.
Không dễ để "ghi đè" các gói hoặc thư viện vào nix-shell, nhưng nếu bạn muốn tạo một trình bao bọc xung quanh tập lệnh của mình, bạn có thể tự tạo một tập lệnh bao bọc:
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p steam-run
exec steam-run ./wolframscript "$@"
hoặc trực tiếp viết nó trong một dẫn xuất nixos:
{ stdenv, steam-run, writeScriptBin }:
let
src = ./opt/Wolfram/WolframScript/bin/wolframscript;
in writeScriptBin "wolf_wrapped_steam" ''
exec ${steam-run}/bin/steam-run ${src} "$@"
''
hoặc nếu bạn bắt đầu từ .deb (ở đây tôi đã sử dụng makeWrapper
thay thế):
{ stdenv, steam-run, dpkg, writeScriptBin, makeWrapper }:
stdenv.mkDerivation {
name = "wolframscript";
src = ./WolframScript_12.0.0_LINUX64_amd64.deb;
nativeBuildInputs = [
dpkg makeWrapper
];
unpackPhase = "true";
installPhase = ''
mkdir -p $out/bin
dpkg -x $src $out
cp -av $out/opt/Wolfram/WolframScript/bin/wolframscript $out/bin/.wolframscript-unwrapped
makeWrapper ${steam-run}/bin/steam-run $out/bin/wolframscript --add-flags $out/bin/.wolframscript-unwrapped
rm -rf $out/opt
'';
}
(nếu bạn quá mệt mỏi để viết thông thường default.nix
, bạn có thể chạy trực tiếp nix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}"
)
LÀM
https://nixos.org/nixos/manual/index.html#module-service-flatpak
appimage-run: Để kiểm tra với, ex, musescore