¿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.
¿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.
Respuestas:
Aquí hay varios métodos (los manuales son principalmente para 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 tienes mejores métodos, ¡házmelo 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 /nix/store/
.
Esta lista ofrece todos los métodos que encontré hasta ahora. Básicamente hay tres "grupos":
Recomendaría el método 4 autoPatchelfHook
para una configuración real y adecuada, y si no tiene tiempo y solo desea ejecutar un binario en una línea, puede interesarle la solución rápida y sucia basada en steam-run
(método 7 )
Primero debe encontrar el cargador con, por ejemplo 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í está el cargador /lib64/ld-linux-x86-64.so.2
. Para encontrar el cargador de nixos, puedes 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 debe 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 la mayoría de las bibliotecas se encuentran 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
Bueno. Ahora, solo necesitamos ejecutar el programa con el LD_LIBRARY_PATH
configurado para apuntar a este archivo, y llamar al cargador que determinamos en el primer paso en 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)
Después de la instalación (con nixenv -i
o en su configuration.nix
) patchelf
, también puede modificar directamente el ejecutable para empacar 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 para 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 la ruta actual (vacía para mí):
$ patchelf --print-rpath wolframscript
y añádalos a la ruta de la biblioteca que determinó antes, finalmente separados con dos puntos:
$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript
Podemos reproducir más o menos lo mismo en una derivación de nix inspirada en skypeforlinux
Este ejemplo también presenta 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
.
Ponlo 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 el default.nix
puesto:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
Compilar y ejecutar con
nix-build
result/bin/wolframscript
Todos los métodos anteriores necesitan un poco de trabajo (necesita encontrar los ejecutables, parchearlos ...). ¡NixOs hizo por nosotros un "gancho" especial autoPatchelfHook
que automáticamente repara todo por ti! Solo necesita especificarlo (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" ];
};
}
Algunos sofware pueden ser difíciles de empaquetar de esa manera porque pueden depender en gran medida de la estructura de árbol de archivos FHS , o pueden verificar que los binarios no hayan cambiado. Luego, también puede usar buildFHSUserEnv para proporcionar una estructura de archivos FHS (ligera, 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 generar un shell y luego extraer manualmente el archivo y ejecutar el archivo, o directamente empaquetar su programa para el FHS. Veamos primero 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 archivos compatibles) o targetPkgs
(solo para el archivo 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
fuente: https://reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html
Con buildFHSUserEnv
usted 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, puede intentarlo steam-run
(a pesar del nombre, no está vinculado directamente con steam, y solo contiene muchas bibliotecas), que es al igual que buildFHSUserEnv
con muchas bibliotecas comunes preinstaladas (algunas de ellas pueden no ser libres, como steamrt
eso contiene algún 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 puede ser necesario añadir nixpkgs.config.allowUnfree = true;
(o lista blanca de este paquete específico ) si desea instalarlo con nixos-rebuild
, y si se desea ejecutar / instalarlo con nix-shell
/ nix-env
que necesita para poner { allowUnfree = true; }
en ~/.config/nixpkgs/config.nix
.
No es fácil "sobrescribir" paquetes o bibliotecas a nix-shell, pero si desea crear un contenedor alrededor de su script, puede crear manualmente un script de contenedor:
#!/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 comienzas desde el .deb (aquí usé en su 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ás demasiado cansado para escribir lo habitual default.nix
, puedes correr directamente nix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}"
)
QUE HACER
https://nixos.org/nixos/manual/index.html#module-services-flatpak
appimage-run: Para probar con, por ejemplo, musescore