Quelles sont les différentes méthodes pour exécuter un exécutable non nixos sur NixOs? J'aimerais voir aussi les méthodes manuelles.
Quelles sont les différentes méthodes pour exécuter un exécutable non nixos sur NixOs? J'aimerais voir aussi les méthodes manuelles.
Réponses:
Voici plusieurs méthodes (les méthodes manuelles sont principalement à des fins éducatives car la plupart du temps, il est préférable d'écrire une dérivation appropriée). Je ne suis pas du tout un expert, et j'ai également fait cette liste pour apprendre Nix, donc si vous avez de meilleures méthodes, faites le moi savoir!
Donc, le problème principal est que l'exécutable appelle d'abord un chargeur, puis a besoin de certaines bibliothèques pour fonctionner, et nixos place à la fois le chargeur et les bibliothèques /nix/store/
.
Cette liste donne toutes les méthodes que j'ai trouvées jusqu'à présent. Il existe essentiellement trois "groupes":
Je recommanderais la méthode 4 avec autoPatchelfHook
pour une configuration réelle et correcte, et si vous n'avez pas le temps et que vous souhaitez simplement exécuter un binaire en une seule ligne, vous pouvez être intéressé par la solution rapide et sale basée sur steam-run
(méthode 7 ).
Vous devez d'abord trouver le chargeur avec par exemple 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
Voici le chargeur /lib64/ld-linux-x86-64.so.2
. Pour trouver le chargeur de nixos, vous pouvez faire:
$ ls /nix/store/*glibc*/lib/ld-linux-x86-64.so.2
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2
Vous devez également rechercher pour trouver les bibliothèques dont votre programme a besoin, par exemple avec 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)
Ici, vous voyez que la plupart des bibliothèques se trouvent sauf libstdc++.so.6
. Alors trouvons-le:
$ find /nix/store -name libstdc++.so.6
/nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/libstdc++.so.6
Bien. Maintenant, nous devons simplement exécuter le programme avec le LD_LIBRARY_PATH
configuré pour pointer vers ce fichier et appeler le chargeur que nous avons déterminé à la première étape de ce fichier:
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
(assurez-vous d'utiliser ./
avant le nom du script et de ne conserver que le répertoire des bibliothèques. Si vous avez plusieurs bibliothèques, utilisez simplement concat le chemin avec deux points)
Après l'installation (avec nixenv -i
ou dans votre configuration.nix
) patchelf
, vous pouvez également modifier directement l'exécutable pour emballer le bon chargeur et les bonnes bibliothèques. Pour changer le chargeur, lancez simplement:
patchelf --set-interpreter /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 wolframscript
et pour vérifier:
$ patchelf --print-interpreter wolframscript
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.
et pour changer le chemin vers les bibliothèques codées en dur dans l'exécutable, vérifiez d'abord quel est le chemin actuel (vide pour moi):
$ patchelf --print-rpath wolframscript
et ajoutez-les au chemin de bibliothèque que vous avez déterminé auparavant, éventuellement séparés par des deux-points:
$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript
On peut reproduire plus ou moins la même chose dans une dérivation nix inspirée de skypeforlinux
Cet exemple présente également une alternative, soit vous pouvez utiliser:
patchelf --set-interpreter ${glibc}/lib/ld-linux-x86-64.so.2 "$out/bin/wolframscript" || true
(qui devrait être assez clair une fois que vous aurez compris la méthode "manuelle"), ou
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/bin/wolframscript" || true
Cette deuxième méthode est un peu plus subtile, mais si vous exécutez:
$ 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
vous verrez que le fichier $NIX_CC/nix-support/dynamic-linker
contient un chemin vers le chargeur ld-linux-x86-64.so.2
.
Mettez derivation.nix
, c'est
{ 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" ];
};
}
et en default.nix
gros:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
Compiler et exécuter avec
nix-build
result/bin/wolframscript
Toutes les méthodes précédentes nécessitent un peu de travail (il faut trouver les exécutables, les patcher ...). NixOs a fait pour nous un "crochet" spécial qui corrige autoPatchelfHook
automatiquement tout pour vous! Il vous suffit de le spécifier (native)BuildInputs
et nix fait la 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" ];
};
}
Certains logiciels peuvent être difficiles à empaqueter de cette façon car ils peuvent dépendre fortement de la structure de l'arborescence des fichiers FHS ou peuvent vérifier que le binaire est inchangé. Vous pouvez ensuite également utiliser buildFHSUserEnv pour fournir une structure de fichiers FHS (légère, en utilisant des espaces de noms) pour votre application. Notez que cette méthode est plus lourde que les méthodes basées sur les correctifs et ajoute un temps de démarrage important, donc évitez-la si possible
Vous pouvez soit simplement générer un shell, puis extraire manuellement l'archive et exécuter le fichier, soit empaqueter directement votre programme pour le FHS. Voyons d'abord comment obtenir un shell. Mettez dans un fichier (disons fhs-env.nix
) ce qui suit:
let nixpkgs = import <nixpkgs> {};
in nixpkgs.buildFHSUserEnv {
name = "fhs";
targetPkgs = pkgs: [];
multiPkgs = pkgs: [ pkgs.dpkg ];
runScript = "bash";
}
et courir:
nix-build fhs-env.nix
result/bin/fhs
Vous obtiendrez alors un bash dans un linux plus standard, et vous pouvez exécuter des commandes pour exécuter votre exécutable, comme:
mkdir wolf_fhs/
dpkg -x WolframScript_12.0.0_LINUX64_amd64.deb wolf_fhs/
cd wolf_fhs/opt/Wolfram/WolframScript/bin/
./wolfram
Si vous avez besoin de plus de bibliothèques / programmes en tant que dépendances, ajoutez-les simplement multiPkgs
(pour toutes targetPkgs
les arches prises en charge) ou (pour l'arc actuel uniquement).
Bonus: vous pouvez également lancer un shell fhs avec une commande en ligne, sans créer de fichier spécifique:
nix-build -E '(import <nixpkgs> {}).buildFHSUserEnv {name = "fhs";}' && ./result/bin/fhs
source: https://reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html
Avec, buildFHSUserEnv
vous pouvez exécuter de nombreux logiciels, mais vous devrez spécifier manuellement toutes les bibliothèques requises. Si vous voulez une solution rapide et que vous n'avez pas le temps de vérifier précisément quelles sont les bibliothèques requises, vous voudrez peut-être essayer steam-run
(malgré son nom, il n'est pas directement lié à Steam et ne contient que beaucoup de bibliothèques), ce qui est comme buildFHSUserEnv
avec beaucoup de bibliothèques communes préinstallées (certaines d'entre elles peuvent être non libres comme steamrt
cela contient du code nvidia, merci simpson!). Pour l'utiliser, il suffit d'installer steam-run
, puis:
steam-run ./wolframscript
ou si vous voulez un shell complet:
steam-run bash
Notez que vous devrez peut - être ajouter nixpkgs.config.allowUnfree = true;
(ou whitelist ce paquet spécifique ) si vous voulez l' installer avec nixos-rebuild
, et si vous voulez exécuter / installer avec nix-shell
/ nix-env
vous avez besoin de mettre { allowUnfree = true; }
en ~/.config/nixpkgs/config.nix
.
Il n'est pas facile de "remplacer" des packages ou des bibliothèques dans nix-shell, mais si vous souhaitez créer un wrapper autour de votre script, vous pouvez soit créer manuellement un script wrapper:
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p steam-run
exec steam-run ./wolframscript "$@"
ou l'écrire directement dans une dérivation nixos:
{ stdenv, steam-run, writeScriptBin }:
let
src = ./opt/Wolfram/WolframScript/bin/wolframscript;
in writeScriptBin "wolf_wrapped_steam" ''
exec ${steam-run}/bin/steam-run ${src} "$@"
''
ou si vous commencez à partir du .deb (ici j'ai utilisé à la makeWrapper
place):
{ 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
'';
}
(si vous êtes trop fatigué pour écrire l'habituel default.nix
, vous pouvez courir directement nix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}"
)
FAIRE
https://nixos.org/nixos/manual/index.html#module-services-flatpak
appimage-run: pour tester avec, ex, musescore