Quali sono i diversi metodi per eseguire un eseguibile non nixos su NixOs? Mi piacerebbe vedere anche i metodi manuali.
Quali sono i diversi metodi per eseguire un eseguibile non nixos su NixOs? Mi piacerebbe vedere anche i metodi manuali.
Risposte:
Qui ci sono diversi metodi (quelli manuali sono principalmente a scopo educativo poiché la maggior parte delle volte è meglio scrivere una derivazione corretta). Non sono affatto un esperto, e ho fatto questo elenco anche per imparare nix, quindi se hai metodi migliori, fammelo sapere!
Quindi il problema principale è che l'eseguibile chiama prima un caricatore, quindi ha bisogno di alcune librerie per funzionare, e nixos inserisce sia il caricatore che le librerie /nix/store/
.
Questo elenco fornisce tutti i metodi che ho trovato finora. Esistono sostanzialmente tre "gruppi":
Consiglierei il metodo 4 autoPatchelfHook
per una configurazione reale e corretta e se non hai tempo e vuoi solo eseguire un binario su una riga, potresti essere interessato dalla soluzione quick-and-dirty basata su steam-run
(metodo 7 ).
Devi prima trovare il caricatore con ad esempio 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
Qui è il caricatore /lib64/ld-linux-x86-64.so.2
. Per trovare il caricatore di nixos, puoi fare:
$ ls /nix/store/*glibc*/lib/ld-linux-x86-64.so.2
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2
È inoltre necessario trovare le librerie richieste dal programma, ad esempio con 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)
Qui vedi che la maggior parte delle librerie si trova tranne libstdc++.so.6
. Quindi troviamolo:
$ find /nix/store -name libstdc++.so.6
/nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/libstdc++.so.6
Buona. Ora, abbiamo solo bisogno di eseguire il programma con il LD_LIBRARY_PATH
configurato per puntare a questo file e chiamare il caricatore che abbiamo determinato al primo passaggio su questo file:
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
(assicurati di utilizzare ./
prima del nome dello script e di mantenere solo la directory delle librerie. Se hai diverse librerie, usa semplicemente concat il percorso con due punti)
Dopo l'installazione (con nixenv -i
o nel tuo configuration.nix
) patchelf
, puoi anche modificare direttamente l'eseguibile per imballare il buon caricatore e le librerie. Per cambiare il caricatore basta eseguire:
patchelf --set-interpreter /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 wolframscript
e controllare:
$ patchelf --print-interpreter wolframscript
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.
e per cambiare il percorso delle librerie hardcoded nell'eseguibile, prima controlla qual è l'attuale rpath (vuoto per me):
$ patchelf --print-rpath wolframscript
e aggiungili al percorso della libreria che hai determinato prima, eventualmente separato con due punti:
$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript
Possiamo riprodurre più o meno la stessa cosa in una derivazione nix ispirata a skypeforlinux
Questo esempio presenta anche un'alternativa, oppure puoi usare:
patchelf --set-interpreter ${glibc}/lib/ld-linux-x86-64.so.2 "$out/bin/wolframscript" || true
(che dovrebbe essere abbastanza chiaro una volta compreso il metodo "manuale"), oppure
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/bin/wolframscript" || true
Questo secondo metodo è un po 'più sottile, ma se si esegue:
$ 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
vedrai che il file $NIX_CC/nix-support/dynamic-linker
contiene un percorso per il caricatore ld-linux-x86-64.so.2
.
Metti dentro derivation.nix
, questo è
{ 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" ];
};
}
e in default.nix
put:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
Compila ed esegui con
nix-build
result/bin/wolframscript
Tutti i metodi precedenti richiedono un po 'di lavoro (è necessario trovare gli eseguibili, correggerli ...). NixOs ha fatto per noi uno speciale "gancio" autoPatchelfHook
che corregge automaticamente tutto per te! Devi solo specificarlo in (native)BuildInputs
, e nix fa la magia.
{ 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" ];
};
}
Alcuni software potrebbero essere difficili da impacchettare in quel modo perché potrebbero fare molto affidamento sulla struttura ad albero dei file FHS o verificare che il file binario sia invariato. È inoltre possibile utilizzare buildFHSUserEnv per fornire una struttura di file FHS (leggera, utilizzando spazi dei nomi) per l'applicazione. Si noti che questo metodo è più pesante dei metodi basati su patch e aggiunge un tempo di avvio significativo, quindi evitarlo quando possibile
Puoi semplicemente generare una shell e quindi estrarre manualmente l'archivio ed eseguire il file o impacchettare direttamente il tuo programma per l'FHS. Vediamo prima come ottenere una shell. Inserisci un file (ad esempio fhs-env.nix
) quanto segue:
let nixpkgs = import <nixpkgs> {};
in nixpkgs.buildFHSUserEnv {
name = "fhs";
targetPkgs = pkgs: [];
multiPkgs = pkgs: [ pkgs.dpkg ];
runScript = "bash";
}
e corri:
nix-build fhs-env.nix
result/bin/fhs
Otterrai quindi una bash in un Linux dall'aspetto più standard e potrai eseguire comandi per eseguire il tuo eseguibile, come:
mkdir wolf_fhs/
dpkg -x WolframScript_12.0.0_LINUX64_amd64.deb wolf_fhs/
cd wolf_fhs/opt/Wolfram/WolframScript/bin/
./wolfram
Se hai bisogno di più librerie / programmi come dipendenze, aggiungile a multiPkgs
(per tutti gli archi supportati) o targetPkgs
(solo per gli archi correnti).
Bonus: puoi anche lanciare una shell fhs con un comando a una riga, senza creare un file specifico:
nix-build -E '(import <nixpkgs> {}).buildFHSUserEnv {name = "fhs";}' && ./result/bin/fhs
fonte: https://reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html
Con buildFHSUserEnv
te puoi eseguire molti software, ma dovrai specificare manualmente tutte le librerie richieste. Se vuoi una soluzione rapida e non hai il tempo di verificare con precisione quali sono le librerie richieste, potresti provare steam-run
(nonostante il nome, non è collegato direttamente a Steam e racchiude solo molte librerie), che è come buildFHSUserEnv
con molte librerie comuni preinstallate (alcune potrebbero non essere libere come quelle steamrt
che contengono un po 'di codice nvidia, grazie simpson!). Per usarlo, basta installare steam-run
e quindi:
steam-run ./wolframscript
o se vuoi una shell completa:
steam-run bash
Nota che potrebbe essere necessario aggiungere nixpkgs.config.allowUnfree = true;
(o whitelist questo pacchetto specifico ), se si desidera installarlo con nixos-rebuild
, e se si desidera eseguire / installarlo con nix-shell
/ nix-env
è necessario mettere { allowUnfree = true; }
in ~/.config/nixpkgs/config.nix
.
Non è facile "sovrascrivere" pacchetti o librerie su nix-shell, ma se si desidera creare un wrapper attorno allo script, è possibile creare manualmente uno script wrapper:
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p steam-run
exec steam-run ./wolframscript "$@"
o scriverlo direttamente in una derivazione nixos:
{ stdenv, steam-run, writeScriptBin }:
let
src = ./opt/Wolfram/WolframScript/bin/wolframscript;
in writeScriptBin "wolf_wrapped_steam" ''
exec ${steam-run}/bin/steam-run ${src} "$@"
''
o se inizi dal .deb (qui makeWrapper
invece ho usato ):
{ 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
'';
}
(se sei troppo stanco per scrivere il solito default.nix
, puoi correre direttamente nix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}"
)
FARE
https://nixos.org/nixos/manual/index.html#module-services-flatpak
appimage-run: per testare, ad esempio, con musescore