Verschiedene Methoden zum Ausführen einer ausführbaren Nicht-Nixos-Datei auf Nixos

12

Welche verschiedenen Methoden gibt es, um eine ausführbare Nicht-Nixos-Datei auf NixOs auszuführen? Ich würde auch gerne die manuellen Methoden sehen.

tobiasBora
quelle

Antworten:

22

Hier sind verschiedene Methoden (die manuellen dienen hauptsächlich zu Bildungszwecken, da das Schreiben einer richtigen Ableitung meistens besser ist). Ich bin überhaupt kein Experte, und ich habe diese Liste auch gemacht, um nix zu lernen. Wenn Sie also bessere Methoden haben, lassen Sie es mich wissen!

Das Hauptproblem ist also, dass die ausführbare Datei zuerst einen Loader aufruft und dann einige Bibliotheken benötigt, um zu funktionieren, und nixos sowohl den Loader als auch die Bibliotheken einfügt /nix/store/.

Diese Liste enthält alle Methoden, die ich bisher gefunden habe. Grundsätzlich gibt es drei "Gruppen":

  • das vollständige Handbuch: interessant für Bildungszwecke und um zu verstehen, was los ist, aber das ist alles (verwenden Sie sie nicht in der Praxis, da nichts die Ableitungen daran hindert, später Müll zu sammeln)
  • Die gepatchten Versionen: Diese Methoden versuchen, die ausführbare Datei zu ändern (automatisch, wenn die empfohlene Methode 4 mit autoPatchelfHook verwendet wird), um direkt auf die gute Bibliothek zu verweisen
  • die auf FHS basierenden Methoden, die im Grunde genommen ein "normales Linux" vortäuschen (schwerer auszuführen als die gepatchte Version, daher sollte dies nach Möglichkeit vermieden werden).

Ich würde Methode 4 mit autoPatchelfHookfür ein echtes, korrektes Setup empfehlen. Wenn Sie keine Zeit haben und nur eine Binärdatei in einer Zeile ausführen möchten, könnte Sie die schnelle und schmutzige Lösung auf Basis von steam-run(Methode 7) interessieren ).

Methode 1) Schmutzige manuelle Methode, kein Patch

Sie müssen zuerst den Lader finden mit zum Beispiel 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

Hier ist der Lader /lib64/ld-linux-x86-64.so.2. Um den Lader von Nixos zu finden, haben Sie folgende Möglichkeiten:

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

Sie müssen auch suchen, um die Bibliotheken zu finden, die Ihr Programm benötigt, zum Beispiel mit 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)

Hier sehen Sie, dass die meisten Bibliotheken außer gefunden werden libstdc++.so.6. Also lasst es uns finden:

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

Gut. Jetzt müssen wir nur noch das Programm ausführen, das so LD_LIBRARY_PATHkonfiguriert ist, dass es auf diese Datei verweist, und den Loader aufrufen, den wir im ersten Schritt dieser Datei ermittelt haben:

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

(Stellen Sie sicher, dass Sie ./vor dem Skriptnamen verwenden und nur das Verzeichnis der Bibliotheken behalten. Wenn Sie mehrere Bibliotheken haben, verwenden Sie einfach concat den Pfad mit Doppelpunkten.)

Methode 2) Schmutzige manuelle Methode mit Patch

Nach der Installation (mit nixenv -ioder in Ihrem configuration.nix) patchelfkönnen Sie die ausführbare Datei auch direkt ändern, um den guten Loader und die Bibliotheken zu packen. Um den Lader zu wechseln, führen Sie einfach Folgendes aus:

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

und zu überprüfen:

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

Um den Pfad zu den in der ausführbaren Datei fest codierten Bibliotheken zu ändern, überprüfen Sie zunächst den aktuellen Pfad (für mich leer):

$ patchelf --print-rpath wolframscript

und hängen Sie sie an den zuvor festgelegten Bibliothekspfad an, der schließlich durch Doppelpunkte getrennt ist:

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

Methode 3) Patch in einer Nix-Ableitung

Wir können mehr oder weniger dasselbe in einer von skypeforlinux inspirierten Nix- Ableitung reproduzieren

Dieses Beispiel bietet auch eine Alternative, die Sie entweder verwenden können:

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

(was ziemlich klar sein sollte, wenn Sie die "manuelle" Methode verstanden haben) oder

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

Diese zweite Methode ist etwas subtiler, aber wenn Sie ausführen:

$ 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

Sie werden sehen, dass die Datei $NIX_CC/nix-support/dynamic-linkereinen Pfad zum Loader enthält ld-linux-x86-64.so.2.

Setzen Sie ein derivation.nix, das ist

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

und in default.nixput:

{ pkgs ? import <nixpkgs> {} }:

pkgs.callPackage ./derivation.nix {}

Kompilieren und ausführen mit

nix-build
result/bin/wolframscript

Methode 4) Verwenden Sie autoPatchElf: einfacher

Alle vorherigen Methoden erfordern ein wenig Arbeit (Sie müssen die ausführbaren Dateien finden, patchen ...). NixOs hat für uns einen speziellen "Hook" gemacht autoPatchelfHook, der automatisch alles für Sie patcht ! Sie müssen es nur angeben (native)BuildInputs, und nix macht die Magie.

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

Methode 5) Verwenden Sie FHS, um eine klassische Linux-Shell zu simulieren und die Dateien manuell auszuführen

Einige Softwareprogramme sind möglicherweise schwer auf diese Weise zu verpacken, da sie sich stark auf die FHS- Dateibaumstruktur stützen oder überprüfen, ob die Binärdateien unverändert sind. Sie können dann auch buildFHSUserEnv verwenden , um eine FHS-Dateistruktur (leichtgewichtig, unter Verwendung von Namespaces) für Ihre Anwendung bereitzustellen. Beachten Sie, dass diese Methode schwerer ist als die Patch-basierten Methoden, und fügen Sie eine erhebliche Startzeit hinzu. Vermeiden Sie sie daher, wenn dies möglich ist

Sie können entweder einfach eine Shell erzeugen und dann das Archiv manuell extrahieren und die Datei ausführen oder Ihr Programm direkt für die FHS verpacken. Mal sehen, wie man eine Shell bekommt. Geben Sie fhs-env.nixFolgendes in eine Datei ein (sagen wir ):

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

und Renn:

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

Sie erhalten dann eine Bash in einem Standard-Linux, und Sie können Befehle ausführen, um Ihre ausführbare Datei auszuführen, wie:

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

Wenn Sie mehr Bibliotheken / Programme als Abhängigkeiten benötigen, fügen Sie diese einfach zu multiPkgs(für alle unterstützten Bögen) oder targetPkgs(nur für den aktuellen Bogen) hinzu.

Bonus: Sie können eine fhs-Shell auch mit einem einzeiligen Befehl starten, ohne eine bestimmte Datei zu erstellen:

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

Methode 6) Verwenden Sie FHS, um eine klassische Linux-Shell zu simulieren und die Dateien darin zu packen

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

Methode 7) Dampflauf

Mit können buildFHSUserEnvSie viele Softwareprogramme ausführen, müssen jedoch alle erforderlichen Bibliotheken manuell angeben. Wenn Sie eine schnelle Lösung wünschen und keine Zeit haben, um genau zu überprüfen, welche Bibliotheken erforderlich sind, sollten Sie es versuchen steam-run(trotz des Namens ist es nicht direkt mit Steam verknüpft und packt nur viele Bibliotheken) wie buildFHSUserEnvbei vielen vorinstallierten gängigen Bibliotheken (einige von ihnen sind möglicherweise nicht frei, so steamrtdass sie nvidia-Code enthalten, danke simpson!). Um es zu verwenden, installieren Sie es einfach steam-runund dann:

steam-run ./wolframscript

oder wenn Sie eine vollständige Shell wollen:

steam-run bash

Beachten Sie, dass Sie hinzufügen müssen möglicherweise nixpkgs.config.allowUnfree = true;(oder weiße Liste dieses spezielle Paket ) , wenn Sie es installieren möchten mit nixos-rebuild, und wenn Sie ausführen möchten / installieren Sie es mit nix-shell/ nix-envSie müssen setzen { allowUnfree = true; }in~/.config/nixpkgs/config.nix .

Es ist nicht einfach, Pakete oder Bibliotheken in nix-shell zu "überschreiben". Wenn Sie jedoch einen Wrapper um Ihr Skript erstellen möchten, können Sie entweder manuell ein Wrapper-Skript erstellen:

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

oder schreibe es direkt in eine Nixos-Ableitung:

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

oder wenn Sie von der .deb ausgehen (hier habe ich makeWrapperstattdessen verwendet):

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

(Wenn Sie zu müde sind, um das Übliche zu schreiben default.nix, können Sie direkt laufennix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}" )

Methode 8) Verwenden von Containern / Docker (viel schwerer)

MACHEN

Methode 9) Verlassen Sie sich auf Flatpack / Appimage

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

appimage-run: Zum Testen mit, ex, musescore

Quellen oder Beispiele

tobiasBora
quelle