Các phương thức khác nhau để chạy một tệp thực thi không phải là nixos trên Nixos


12

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:


22

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":

  • hướng dẫn đầy đủ: thú vị cho mục đích giáo dục và để hiểu những gì đang diễn ra, nhưng đó là tất cả (không sử dụng chúng trong thực tế vì không có gì ngăn chặn các dẫn xuất được sử dụng là rác được thu thập sau này)
  • các phiên bản đã vá: các phương thức này cố gắng sửa đổi tệp thực thi (tự động khi sử dụng phương thức 4 được đề xuất với autoPatchelfHook) để trực tiếp chuyển đến thư viện tốt
  • các phương pháp dựa trên FHS, về cơ bản là giả mạo một "linux bình thường" (nặng hơn để chạy hơn phiên bản vá, vì vậy điều này nên tránh nếu có thể).

Tôi muốn giới thiệu phương pháp 4 với autoPatchelfHookmộ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 ).

Phương pháp 1) Phương pháp thủ công bẩn, không có bản vá

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_PATHcấ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)

Phương pháp 2) Phương pháp thủ công bẩn, có bản vá

Sau khi cài đặt (có nixenv -ihoặ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

Phương pháp 3) Patch trong một dẫn xuất nix

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-linkerchứ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" ];
  };
}

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

Phương pháp 4) Sử dụng autoPatchElf: đơn giản hơn

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 autoPatchelfHooktự độ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" ];
  };
}

Phương pháp 5) Sử dụng FHS để mô phỏng hệ vỏ linux cổ điển và thực hiện thủ công các tệp

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 targetPkgsvò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

Phương pháp 6) Sử dụng FHS để mô phỏng hệ vỏ linux cổ điển và đóng gói các tệp bên trong

nguồn: https://reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html

Phương pháp 7) chạy bằng hơi nước

Với buildFHSUserEnvbạ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ư buildFHSUserEnvrấ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ư steamrtgó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-rebuildvà nếu bạn muốn chạy / cài đặt nó với nix-shell/ nix-envbạ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 makeWrapperthay 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 {}")

Phương pháp 8) Sử dụng container / Docker (nặng hơn nhiều)

LÀM

Phương pháp 9) Dựa vào Flatpack / appimage

https://nixos.org/nixos/manual/index.html#module-service-flatpak

appimage-run: Để kiểm tra với, ex, musescore

Nguồn hoặc ví dụ

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.