Berbagai metode untuk menjalankan non-nixos yang dapat dieksekusi di Nixos

12

Apa metode yang berbeda untuk menjalankan non-nixos yang dapat dieksekusi di NixO? Saya juga ingin melihat metode manualnya.

tobiasBora
sumber

Jawaban:

22

Berikut adalah beberapa metode (yang manual kebanyakan untuk tujuan pendidikan karena sebagian besar waktu menulis derivasi yang tepat lebih baik). Saya bukan ahli sama sekali, dan saya melakukan daftar ini juga untuk mempelajari nix, jadi jika Anda memiliki metode yang lebih baik, beri tahu saya!

Jadi masalah utamanya adalah bahwa panggilan yang dapat dieksekusi terlebih dahulu loader, dan kemudian membutuhkan beberapa perpustakaan untuk bekerja, dan nixos memasukkan kedua loader dan perpustakaan /nix/store/.

Daftar ini memberikan semua metode yang saya temukan sejauh ini. Pada dasarnya ada tiga "grup":

  • manual lengkap: menarik untuk tujuan pendidikan, dan untuk memahami apa yang terjadi, tetapi hanya itu (jangan menggunakannya dalam praktik karena tidak ada yang akan mencegah derivasi yang digunakan untuk mengumpulkan sampah nanti)
  • versi yang ditambal: metode ini mencoba memodifikasi yang dapat dieksekusi (secara otomatis saat menggunakan metode 4 yang disarankan dengan autoPatchelfHook) untuk mengarahkan langsung ke pustaka yang bagus
  • metode berdasarkan FHS, yang pada dasarnya memalsukan "linux normal" (lebih berat untuk dijalankan daripada versi yang ditambal, jadi ini harus dihindari jika mungkin).

Saya akan merekomendasikan metode 4 dengan autoPatchelfHookpengaturan yang nyata dan tepat, dan jika Anda tidak punya waktu dan hanya ingin menjalankan biner dalam satu baris, Anda mungkin tertarik dengan solusi cepat dan kotor berdasarkan pada steam-run(metode 7) ).

Metode 1) Metode manual kotor, tanpa patch

Anda harus terlebih dahulu menemukan loader dengan misalnya 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

Di sini loadernya /lib64/ld-linux-x86-64.so.2. Untuk menemukan pemuat nixos, Anda dapat melakukan:

$ ls /nix/store/*glibc*/lib/ld-linux-x86-64.so.2
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2

Anda juga perlu menemukan untuk menemukan perpustakaan yang diperlukan oleh program Anda, misalnya dengan 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)

Di sini, Anda melihat bahwa sebagian besar perpustakaan ditemukan kecuali libstdc++.so.6. Jadi mari kita temukan:

$ find /nix/store -name libstdc++.so.6
/nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/libstdc++.so.6

Baik. Sekarang, kita hanya perlu menjalankan program dengan LD_LIBRARY_PATHkonfigurasi untuk menunjuk ke file ini, dan memanggil loader yang kita tentukan pada langkah pertama pada file ini:

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

(pastikan untuk menggunakan ./sebelum nama skrip, dan hanya menyimpan direktori perpustakaan. Jika Anda memiliki beberapa perpustakaan, cukup gunakan concat path dengan titik dua)

Metode 2) Metode manual kotor, dengan tambalan

Setelah menginstal (dengan nixenv -iatau di Anda configuration.nix) patchelf, Anda juga dapat secara langsung memodifikasi executable untuk mengemas loader dan library yang baik. Untuk mengubah loader, jalankan:

patchelf --set-interpreter /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 wolframscript

dan untuk memeriksa:

$ patchelf --print-interpreter wolframscript
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.

dan untuk mengubah jalur ke pustaka yang di-hardcode dalam executable, periksa terlebih dahulu apa rpath saat ini (kosong untuk saya):

$ patchelf --print-rpath wolframscript

dan menambahkannya ke jalur perpustakaan yang Anda tentukan sebelumnya, akhirnya dipisahkan dengan titik dua:

$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript

Metode 3) Menambal dalam derivasi nix

Kita dapat mereproduksi hal yang kurang lebih sama dalam derivasi nix yang terinspirasi oleh skypeforlinux

Contoh ini juga menyajikan alternatif, bisa Anda gunakan:

patchelf --set-interpreter ${glibc}/lib/ld-linux-x86-64.so.2 "$out/bin/wolframscript" || true

(yang seharusnya cukup jelas setelah Anda memahami metode "manual"), atau

patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/bin/wolframscript" || true

Metode kedua ini sedikit lebih halus, tetapi jika Anda menjalankan:

$ 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

Anda akan melihat bahwa file tersebut $NIX_CC/nix-support/dynamic-linkerberisi path ke loader ld-linux-x86-64.so.2.

Dimasukkan ke dalam derivation.nix, ini

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

dan di tempat default.nix:

{ pkgs ? import <nixpkgs> {} }:

pkgs.callPackage ./derivation.nix {}

Kompilasi dan jalankan bersama

nix-build
result/bin/wolframscript

Metode 4) Gunakan autoPatchElf: simpler

Semua metode sebelumnya membutuhkan sedikit pekerjaan (Anda perlu menemukan executable, tambalan mereka ...). NixOs memberi kami "kait" khusus autoPatchelfHookyang secara otomatis menambal segalanya untuk Anda! Anda hanya perlu menentukannya (native)BuildInputs, dan nix melakukan keajaiban.

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

Metode 5) Gunakan FHS untuk mensimulasikan shell linux klasik, dan jalankan file secara manual

Beberapa sofware mungkin sulit untuk dikemas dengan cara itu karena mereka mungkin sangat bergantung pada struktur pohon file FHS , atau mungkin memeriksa bahwa biner tidak berubah. Anda kemudian dapat juga menggunakan buildFHSUserEnv untuk menyediakan struktur file FHS (ringan, menggunakan namespaces) untuk aplikasi Anda. Perhatikan bahwa metode ini lebih berat daripada metode berbasis tambalan, dan tambahkan waktu startup yang signifikan, jadi hindari jika memungkinkan

Anda bisa menelurkan shell dan kemudian secara manual mengekstrak arsip dan menjalankan file, atau langsung mengemas program Anda untuk FHS. Pertama mari kita lihat bagaimana cara mendapatkan shell. Masukkan file (katakan fhs-env.nix) berikut ini:

let nixpkgs = import <nixpkgs> {};
in nixpkgs.buildFHSUserEnv {
   name = "fhs";
   targetPkgs = pkgs: [];
   multiPkgs = pkgs: [ pkgs.dpkg ];
   runScript = "bash";
}

dan lari:

nix-build fhs-env.nix
result/bin/fhs

Anda kemudian akan mendapatkan bash di linux yang tampak lebih standar, dan Anda dapat menjalankan perintah untuk menjalankan executable Anda, seperti:

mkdir wolf_fhs/
dpkg -x WolframScript_12.0.0_LINUX64_amd64.deb wolf_fhs/
cd wolf_fhs/opt/Wolfram/WolframScript/bin/
./wolfram

Jika Anda membutuhkan lebih banyak pustaka / program sebagai dependensi, cukup tambahkan ke multiPkgs(untuk semua targetPkgslengkungan yang didukung) atau (hanya untuk lengkungan saat ini).

Bonus: Anda juga dapat meluncurkan shell fhs dengan perintah satu baris, tanpa membuat file tertentu:

nix-build -E '(import <nixpkgs> {}).buildFHSUserEnv {name = "fhs";}' && ./result/bin/fhs

Metode 6) Gunakan FHS untuk mensimulasikan shell linux klasik, dan kemas file-file di dalamnya

sumber: https://reflexivereflection.com/posts/2015-02-02-deb-installation-nixos.html

Metode 7) menjalankan uap

Dengan buildFHSUserEnvAnda dapat menjalankan banyak softwares, tetapi Anda harus menentukan secara manual semua perpustakaan yang diperlukan. Jika Anda menginginkan solusi cepat dan Anda tidak punya waktu untuk memeriksa dengan tepat perpustakaan apa yang diperlukan, Anda mungkin ingin mencoba steam-run(terlepas dari namanya, itu tidak terhubung langsung dengan uap, dan hanya mengemas banyak perpustakaan), yang merupakan seperti buildFHSUserEnvdengan banyak perpustakaan umum yang sudah diinstal sebelumnya (beberapa di antaranya mungkin tidak bebas seperti steamrtitu mengemas beberapa kode nvidia, terima kasih simpson!). Untuk menggunakannya, cukup instal steam-run, lalu:

steam-run ./wolframscript

atau jika Anda ingin shell penuh:

steam-run bash

Perhatikan bahwa Anda mungkin perlu menambahkan nixpkgs.config.allowUnfree = true;(atau whitelist paket khusus ini ) jika Anda ingin menginstalnya dengan nixos-rebuild, dan jika Anda ingin menjalankan / install dengan nix-shell/ nix-envAnda harus menempatkan { allowUnfree = true; }di ~/.config/nixpkgs/config.nix.

Tidaklah mudah untuk "menimpa" paket atau pustaka ke nix-shell, tetapi jika Anda ingin membuat wrapper di sekitar skrip Anda, Anda dapat membuat skrip wrapper secara manual:

#!/usr/bin/env nix-shell
#!nix-shell -i bash -p steam-run
exec steam-run ./wolframscript "$@"

atau langsung menuliskannya di derivasi nixos:

{ stdenv, steam-run, writeScriptBin }:
let
  src = ./opt/Wolfram/WolframScript/bin/wolframscript;
in writeScriptBin "wolf_wrapped_steam" ''
    exec ${steam-run}/bin/steam-run ${src} "$@"
  ''

atau jika Anda mulai dari .deb (di sini saya menggunakan makeWrappersebaliknya):

{ 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
  '';
}

(jika Anda terlalu lelah untuk menulis yang biasa default.nix, Anda dapat berlari langsung nix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}")

Metode 8) Menggunakan wadah / Docker (jauh lebih berat)

MELAKUKAN

Metode 9) Mengandalkan flatpack / appimage

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

appimage-run: Untuk menguji dengan, ex, musescore

Sumber atau contoh

tobiasBora
sumber