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.
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.
Antworten:
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":
Ich würde Methode 4 mit autoPatchelfHook
fü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 ).
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_PATH
konfiguriert 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.)
Nach der Installation (mit nixenv -i
oder in Ihrem configuration.nix
) patchelf
kö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
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-linker
einen 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.nix
put:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
Kompilieren und ausführen mit
nix-build
result/bin/wolframscript
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" ];
};
}
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.nix
Folgendes 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
Quelle: https://reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html
Mit können buildFHSUserEnv
Sie 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 buildFHSUserEnv
bei vielen vorinstallierten gängigen Bibliotheken (einige von ihnen sind möglicherweise nicht frei, so steamrt
dass sie nvidia-Code enthalten, danke simpson!). Um es zu verwenden, installieren Sie es einfach steam-run
und 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-env
Sie 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 makeWrapper
stattdessen 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 {}"
)
MACHEN
https://nixos.org/nixos/manual/index.html#module-services-flatpak
appimage-run: Zum Testen mit, ex, musescore