executable – Diferentes métodos para ejecutar un ejecutable que no sea nixos en Nixos

Pregunta:

¿Cuáles son los diferentes métodos para ejecutar un ejecutable que no sea nixos en NixOs? Me gustaría ver también los métodos manuales.

Respuesta:

Aquí hay varios métodos (los manuales son principalmente con fines educativos, ya que la mayoría de las veces es mejor escribir una derivación adecuada). No soy un experto en absoluto, e hice esta lista también para aprender nix, así que si tiene mejores métodos, ¡hágamelo saber!

Entonces, el problema principal es que el ejecutable llama primero a un cargador, y luego necesita algunas bibliotecas para funcionar, y nixos coloca tanto el cargador como las bibliotecas en /nix/store/ .

Esta lista muestra todos los métodos que encontré hasta ahora. Básicamente, hay tres "grupos":

  • el manual completo: interesante para fines educativos y para comprender lo que está pasando, pero eso es todo (no los use en la práctica porque nada evitará que las derivaciones solían ser recolectadas de basura más adelante)
  • las versiones parcheadas: estos métodos intentan modificar el ejecutable (automáticamente cuando se usa el método recomendado 4 con autoPatchelfHook) para señalar la buena biblioteca directamente
  • los métodos basados ​​en FHS, que básicamente simulan un "linux normal" (más pesado de ejecutar que la versión parcheada, por lo que esto debe evitarse si es posible).

Recomendaría el método 4 con autoPatchelfHook para una configuración real y adecuada, y si no tiene tiempo y solo desea ejecutar un binario en una línea, es posible que le interese la solución rápida y sucia basada en steam-run (método 7).

Método 1) Método manual sucio, sin parche

Primero debe encontrar el cargador con, por ejemplo, el 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

Aquí el cargador es /lib64/ld-linux-x86-64.so.2 . Para encontrar el cargador de nixos, puede hacer:

$ ls /nix/store/*glibc*/lib/ld-linux-x86-64.so.2
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2

También necesita buscar para encontrar las bibliotecas que requiere su programa, por ejemplo 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)

Aquí, verá que se encuentran la mayoría de las bibliotecas excepto libstdc++.so.6 . Así que vamos a encontrarlo:

$ find /nix/store -name libstdc++.so.6
/nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/libstdc++.so.6

Bien. Ahora, solo necesitamos ejecutar el programa con LD_LIBRARY_PATH configurado para apuntar a este archivo, y llamar al cargador que determinamos en el primer paso de este archivo:

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

(asegúrese de usar ./ antes del nombre del script y de mantener solo el directorio de las bibliotecas. Si tiene varias bibliotecas, simplemente use concat la ruta con dos puntos)

Método 2) Método manual sucio, con parche

Después de instalar (con nixenv -i o en su configuration.nix ) patchelf , también puede modificar directamente el ejecutable para empaquetar el buen cargador y las bibliotecas. Para cambiar el cargador, simplemente ejecute:

patchelf --set-interpreter /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 wolframscript

y comprobar:

$ patchelf --print-interpreter wolframscript
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.

y para cambiar la ruta a las bibliotecas codificadas en el ejecutable, primero verifique cuál es el rpath actual (vacío para mí):

$ patchelf --print-rpath wolframscript

y añádalos a la ruta de la biblioteca que determinó antes, eventualmente separados por dos puntos:

$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript

Método 3) Parche en una derivación de nix

Podemos reproducir más o menos lo mismo en una derivación nix inspirada en skypeforlinux

Este ejemplo presenta también una alternativa, puede usar:

patchelf --set-interpreter ${glibc}/lib/ld-linux-x86-64.so.2 "$out/bin/wolframscript" || true

(que debería quedar bastante claro una vez que comprenda el método "manual"), o

patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/bin/wolframscript" || true

Este segundo método es un poco más sutil, pero si ejecuta:

$ 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

verá que el archivo $NIX_CC/nix-support/dynamic-linker contiene una ruta al cargador ld-linux-x86-64.so.2 .

Poner en derivation.nix , esto es

{ 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" ];
  };
}

y en default.nix poner:

{ pkgs ? import <nixpkgs> {} }:

pkgs.callPackage ./derivation.nix {}

Compilar y ejecutar con

nix-build
result/bin/wolframscript

Método 4) Utilice autoPatchElf: más simple

Todos los métodos anteriores necesitan un poco de trabajo (necesitas encontrar los ejecutables, parchearlos …). ¡NixOs hizo para nosotros un "gancho" especial autoPatchelfHook que automáticamente parchea todo por usted! Solo necesita especificarlo en (native)BuildInputs , y nix hace 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" ];
  };
}

Método 5) Utilice FHS para simular un shell de Linux clásico y ejecute manualmente los archivos

Algunos sofware pueden ser difíciles de empaquetar de esa manera porque pueden depender en gran medida de la estructura del árbol de archivos FHS , o pueden verificar que los binarios no hayan cambiado. Luego, también puede usar buildFHSUserEnv para proporcionar una estructura de archivo FHS (liviana, usando espacios de nombres) para su aplicación. Tenga en cuenta que este método es más pesado que los métodos basados ​​en parches y agrega un tiempo de inicio significativo, así que evítelo cuando sea posible

Puede simplemente generar un shell y luego extraer manualmente el archivo y ejecutar el archivo, o empaquetar directamente su programa para el FHS. Primero veamos cómo obtener un caparazón. Ponga en un archivo (digamos fhs-env.nix ) lo siguiente:

let nixpkgs = import <nixpkgs> {};
in nixpkgs.buildFHSUserEnv {
   name = "fhs";
   targetPkgs = pkgs: [];
   multiPkgs = pkgs: [ pkgs.dpkg ];
   runScript = "bash";
}

y correr:

nix-build fhs-env.nix
result/bin/fhs

Luego obtendrá un bash en un linux de aspecto más estándar, y puede ejecutar comandos para ejecutar su ejecutable, como:

mkdir wolf_fhs/
dpkg -x WolframScript_12.0.0_LINUX64_amd64.deb wolf_fhs/
cd wolf_fhs/opt/Wolfram/WolframScript/bin/
./wolfram

Si necesita más bibliotecas / programas como dependencias, simplemente agréguelos a multiPkgs (para todos los multiPkgs compatibles) o targetPkgs (solo para el targetPkgs actual).

Bonificación: también puede iniciar un shell fhs con un comando de una línea, sin crear un archivo específico:

nix-build -E '(import <nixpkgs> {}).buildFHSUserEnv {name = "fhs";}' && ./result/bin/fhs

Método 6) Use FHS para simular un shell de Linux clásico y empaque los archivos dentro

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

Método 7) funcionamiento a vapor

Con buildFHSUserEnv puede ejecutar muchos softwares, pero deberá especificar manualmente todas las bibliotecas necesarias. Si desea una solución rápida y no tiene tiempo para verificar con precisión cuáles son las bibliotecas requeridas, es posible que desee probar steam-run (a pesar del nombre, no está vinculado directamente con steam y solo contiene muchas bibliotecas) , que es como buildFHSUserEnv con muchas bibliotecas comunes preinstaladas (algunas de ellas pueden no ser gratuitas, como steamrt que steamrt código de nvidia, ¡gracias, simpson!). Para usarlo, simplemente instale steam-run y luego:

steam-run ./wolframscript

o si quieres un caparazón completo:

steam-run bash

Tenga en cuenta que es posible que deba agregar nixpkgs.config.allowUnfree = true; (o incluya en la lista blanca este paquete específico ) si desea instalarlo con nixos-rebuild , y si desea ejecutarlo / instalarlo con nix-shell / nix-env , debe poner { allowUnfree = true; } en ~/.config/nixpkgs/config.nix .

No es fácil "sobrescribir" paquetes o bibliotecas en nix-shell, pero si desea crear una envoltura alrededor de su secuencia de comandos, puede crear manualmente una secuencia de comandos de envoltura:

#!/usr/bin/env nix-shell
#!nix-shell -i bash -p steam-run
exec steam-run ./wolframscript "$@"

o escribirlo directamente en una derivación de 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 si comienza desde el .deb (aquí usé makeWrapper en makeWrapper lugar):

{ 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 está demasiado cansado para escribir el default.nix habitual, puede ejecutar directamente nix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}" )

Método 8) Uso de contenedores / Docker (mucho más pesado)

HACER

Método 9) Confíe en flatpack / appimage

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

appimage-run: para probar con, ex, musescore

Fuentes o ejemplos

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top

web tasarım