Metodi diversi per eseguire un eseguibile non nixos su Nixos


12

Quali sono i diversi metodi per eseguire un eseguibile non nixos su NixOs? Mi piacerebbe vedere anche i metodi manuali.

Risposte:


22

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":

  • il manuale completo: interessante per scopi educativi e per capire cosa sta succedendo, ma questo è tutto (non usarli in pratica perché nulla impedirà che le derivazioni fossero in passato raccolte in seguito a rifiuti)
  • le versioni patchate: questi metodi tentano di modificare l'eseguibile (automaticamente quando si utilizza il metodo consigliato 4 con autoPatchelfHook) per indicare direttamente la buona libreria
  • i metodi basati su FHS, che fondamentalmente falsificano un "normale linux" (più pesante da eseguire rispetto alla versione con patch, quindi questo dovrebbe essere evitato se possibile).

Consiglierei il metodo 4 autoPatchelfHookper 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 ).

Metodo 1) Metodo manuale sporco, nessuna patch

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_PATHconfigurato 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)

Metodo 2) Metodo manuale sporco, con patch

Dopo l'installazione (con nixenv -io 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

Metodo 3) Patch in una derivazione nix

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-linkercontiene 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.nixput:

{ pkgs ? import <nixpkgs> {} }:

pkgs.callPackage ./derivation.nix {}

Compila ed esegui con

nix-build
result/bin/wolframscript

Metodo 4) Usa autoPatchElf: più semplice

Tutti i metodi precedenti richiedono un po 'di lavoro (è necessario trovare gli eseguibili, correggerli ...). NixOs ha fatto per noi uno speciale "gancio" autoPatchelfHookche 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" ];
  };
}

Metodo 5) Utilizzare FHS per simulare una shell Linux classica ed eseguire manualmente i file

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

Metodo 6) Utilizzare FHS per simulare una shell Linux classica e comprimere i file all'interno

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

Metodo 7) corsa a vapore

Con buildFHSUserEnvte 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 buildFHSUserEnvcon molte librerie comuni preinstallate (alcune potrebbero non essere libere come quelle steamrtche contengono un po 'di codice nvidia, grazie simpson!). Per usarlo, basta installare steam-rune 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 makeWrapperinvece 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 {}")

Metodo 8) Utilizzo di container / Docker (molto più pesante)

FARE

Metodo 9) Affidati a flatpack / appimage

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

appimage-run: per testare, ad esempio, con musescore

Fonti o esempi

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.