Quelles sont les différentes méthodes pour exécuter un exécutable non-Nixos sur Nixos? J'aimerais aussi voir les méthodes manuelles.
Voici plusieurs méthodes (les utilisations manuelles sont principalement à des fins éducatives, car la plupart du temps écrit une dérivation appropriée est meilleure). Je ne suis pas un expert du tout, et j'ai aussi fait cette liste pour apprendre Nix, donc si vous avez de meilleures méthodes, faites-moi savoir!
Donc, le problème principal est que l'appel exécutable d'abord un chargeur, puis a besoin de certaines bibliothèques pour travailler et Nixos mettez à la fois le chargeur et les bibliothèques dans /nix/store/
.
Cette liste donne toutes les méthodes que j'ai trouvées jusqu'à présent. Il y a essentiellement trois "groupes":
Je recommanderais la méthode 4 avec autoPatchelfHook
pour une configuration réelle et appropriée, et si vous n'avez pas de temps et que vous souhaitez simplement exécuter un binaire en une ligne, vous pouvez être intéressé par le rapide et sale Solution 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
Ici le chargeur est /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 trouver pour trouver les bibliothèques requises par votre programme, 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 sont trouvées, 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
Bon. Maintenant, nous devons simplement exécuter le programme avec le LD_LIBRARY_PATH
Configuré pour pointer sur ce fichier et appelez 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 ne conservez que le répertoire des bibliothèques. Si vous avez plusieurs bibliothèques, utilisez simplement Concat le chemin avec des points de vue)
Après l'installation (avec nixenv -i
ou dans votre configuration.nix
) patchelf
, vous pouvez également modifier directement l'exécutable pour emballer la bonne chargeur et les bibliothèques. Pour changer le chargeur vient de courir:
patchelf --set-interpreter /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 wolframscript
et de vérifier:
$ patchelf --print-interpreter wolframscript
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.
et pour changer le chemin d'accès aux bibliothèques codées dans l'exécutable, vérifiez d'abord ce qui est le RPATH actuel (vide pour moi):
$ patchelf --print-rpath wolframscript
et appendez-les à la piste de la bibliothèque que vous avez déterminée auparavant, éventuellement séparées de colons:
$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript
Nous pouvons reproduire plus ou moins la même chose dans une dérivation Nix inspirée par Skypeforlinux
Cet exemple présente également une alternative, que vous puissiez 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 comprenez 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
.
Mettre en 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
mettre:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
Compiler et courir avec
nix-build
result/bin/wolframscript
Toutes les méthodes précédentes nécessitent un peu de travail (vous devez trouver les exécutables, les patcher ...). Nixos a fait pour nous un "crochet" spécial autoPatchelfHook
qui corrige automatiquement tout pour vous! Vous avez juste besoin de le spécifier dans (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 à emballer de cette façon, car ils peuvent s'appuyer fortement sur le [~ # ~ # ~ ~ ~] Structure d'arborescence de fichier, ou peut vérifier que les binaires sont inchangées. Vous pouvez alors utiliser également Buildfhsuserenv pour fournir une structure de fichiers FHS (légère, à l'aide d'espaces de noms) pour votre application. Notez que cette méthode est plus lourde que les méthodes basées sur le patch et ajoutent du temps de démarrage significatif, alors évitez-le lorsque cela est possible
Vous pouvez simplement apparaître une coquille, puis extraire manuellement les archives et exécuter le fichier, ou diriger directement votre programme pour la FHS. Voyons d'abord comment obtenir une coquille. Mettre dans un fichier (dire 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 ensuite une 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 comme des dépendances, ajoutez-les simplement à multiPkgs
(pour tous les arcs pris en charge) ou targetPkgs
(pour la voûte actuelle uniquement).
Bonus: Vous pouvez également lancer une coquille FHS avec une commande d'une 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 des logiciels de lot, mais vous devrez spécifier manuellement toutes les bibliothèques requises. Si vous souhaitez une solution rapide et que vous n'avez pas le temps de vérifier avec précision quelles sont les bibliothèques requises, vous voudrez peut-être essayer Steam-run
(Malgré le nom, il n'est pas lié directement avec Steam et emballe juste de nombreux bibliothèques), qui est comme buildFHSUserEnv
avec beaucoup de bibliothèques communes préinstallé (certaines d'entre elles peuvent être non libres comme steamrt
qui contient du code NVIDIA, merci Simpson!). Pour l'utiliser, installez simplement Steam-run
, puis:
Steam-run ./wolframscript
ou si vous voulez une coquille complète:
Steam-run bash
Notez que vous devrez peut-être ajouter nixpkgs.config.allowUnfree = true;
(ou whitelist ce package spécifique ) Si vous souhaitez l'installer avec nixos-rebuild
, et si vous voulez exécuter/l'installer avec nix-Shell
/nix-env
Vous devez mettre { allowUnfree = true; }
dans ~/.config/nixpkgs/config.nix
.
Il n'est pas facile de "écraser" des paquets ou des bibliothèques à Nix-Shell, mais si vous souhaitez créer une enveloppe autour de votre script, vous pouvez créer manuellement un script wrapper:
#!/usr/bin/env nix-Shell
#!nix-Shell -i bash -p Steam-run
exec Steam-run ./wolframscript "$@"
ou écrivez-le 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é makeWrapper
plutôt):
{ 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, musclus