Quais são os diferentes métodos para executar um executável não-nixos no NixOs? Eu gostaria de ver também os métodos manuais.
Quais são os diferentes métodos para executar um executável não-nixos no NixOs? Eu gostaria de ver também os métodos manuais.
Respostas:
Aqui estão vários métodos (os manuais são principalmente para fins educacionais, pois na maioria das vezes é melhor escrever uma derivação adequada). Eu não sou um especialista, e fiz essa lista também para aprender o nix; portanto, se você tiver métodos melhores, informe-me!
Portanto, a questão principal é que o executável chama primeiro um carregador e, em seguida, precisa de algumas bibliotecas para funcionar, e o nixos coloca o carregador e as bibliotecas /nix/store/
.
Esta lista fornece todos os métodos que encontrei até agora. Existem basicamente três "grupos":
Eu recomendaria o método 4 autoPatchelfHook
para uma configuração real e adequada e, se você não tiver tempo e apenas desejar executar um binário em uma linha, poderá se interessar pela solução rápida e suja baseada em steam-run
(método 7 )
Você precisa primeiro encontrar o carregador com, por exemplo 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
Aqui está o carregador /lib64/ld-linux-x86-64.so.2
. Para encontrar o carregador de nixos, você pode:
$ ls /nix/store/*glibc*/lib/ld-linux-x86-64.so.2
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2
Você também precisa encontrar as bibliotecas necessárias para o seu programa, por exemplo 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)
Aqui, você vê que a maioria das bibliotecas é encontrada, exceto libstdc++.so.6
. Então, vamos encontrá-lo:
$ find /nix/store -name libstdc++.so.6
/nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/libstdc++.so.6
Boa. Agora, precisamos apenas executar o programa com o LD_LIBRARY_PATH
configurado para apontar para esse arquivo e chamar o carregador que determinamos na primeira etapa deste arquivo:
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
(certifique-se de usar ./
antes do nome do script e manter apenas o diretório das bibliotecas. Se você tiver várias bibliotecas, use concat o caminho com dois pontos)
Após a instalação (com nixenv -i
ou no seu configuration.nix
) patchelf
, você também pode modificar diretamente o executável para compactar o bom carregador e as bibliotecas. Para mudar o carregador, basta executar:
patchelf --set-interpreter /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 wolframscript
e verificar:
$ patchelf --print-interpreter wolframscript
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.
e para alterar o caminho para as bibliotecas codificadas no executável, verifique primeiro qual é o rpath atual (vazio para mim):
$ patchelf --print-rpath wolframscript
e anexá-los ao caminho da biblioteca que você determinou antes, eventualmente separados por dois pontos:
$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript
Podemos reproduzir mais ou menos a mesma coisa em uma derivação nix inspirada no skypeforlinux
Este exemplo também apresenta uma alternativa, você pode usar:
patchelf --set-interpreter ${glibc}/lib/ld-linux-x86-64.so.2 "$out/bin/wolframscript" || true
(que deve ficar bem claro depois que você entender o método "manual") ou
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/bin/wolframscript" || true
Este segundo método é um pouco mais sutil, mas se você executar:
$ 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
você verá que o arquivo $NIX_CC/nix-support/dynamic-linker
contém um caminho para o carregador ld-linux-x86-64.so.2
.
Coloque derivation.nix
, isso é
{ 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 em default.nix
colocar:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
Compile e execute com
nix-build
result/bin/wolframscript
Todos os métodos anteriores precisam de um pouco de trabalho (você precisa encontrar os executáveis, corrigi-los ...). O NixOs fez para nós um "gancho" especial que corrige autoPatchelfHook
tudo automaticamente para você! Você só precisa especificá-lo (native)BuildInputs
, e o nix faz a mágica.
{ 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" ];
};
}
Alguns softwares podem ser difíceis de compactar dessa maneira, porque podem depender fortemente da estrutura da árvore de arquivos do FHS ou podem verificar se os binários não foram alterados. Você também pode usar o buildFHSUserEnv para fornecer uma estrutura de arquivo FHS (leve, usando espaços para nome) para seu aplicativo. Observe que esse método é mais pesado que os métodos baseados em patches e adiciona um tempo de inicialização significativo, portanto evite-o quando possível
Você pode gerar um shell e extrair manualmente o arquivo morto e executá-lo, ou empacotar diretamente seu programa para o FHS. Vamos primeiro ver como obter um shell. Coloque em um arquivo (digamos fhs-env.nix
) o seguinte:
let nixpkgs = import <nixpkgs> {};
in nixpkgs.buildFHSUserEnv {
name = "fhs";
targetPkgs = pkgs: [];
multiPkgs = pkgs: [ pkgs.dpkg ];
runScript = "bash";
}
e corra:
nix-build fhs-env.nix
result/bin/fhs
Você receberá um bash em um linux de aparência mais padrão e poderá executar comandos para executar seu executável, como:
mkdir wolf_fhs/
dpkg -x WolframScript_12.0.0_LINUX64_amd64.deb wolf_fhs/
cd wolf_fhs/opt/Wolfram/WolframScript/bin/
./wolfram
Se você precisar de mais bibliotecas / programas como dependências, adicione-os a multiPkgs
(para todos os arcos suportados) ou targetPkgs
(apenas para o arco atual).
Bônus: você também pode iniciar um shell fhs com um comando de uma linha, sem criar um arquivo específico:
nix-build -E '(import <nixpkgs> {}).buildFHSUserEnv {name = "fhs";}' && ./result/bin/fhs
fonte: https://reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html
Com buildFHSUserEnv
você pode executar muitos softwares, mas você precisará especificar manualmente todas as bibliotecas necessárias. Se você deseja uma solução rápida e não tem tempo para verificar com precisão quais são as bibliotecas necessárias, tente steam-run
(apesar do nome, ele não está diretamente vinculado ao steam e apenas comporta muitas bibliotecas), o que é como buildFHSUserEnv
com muitas bibliotecas comuns pré-instaladas (algumas delas podem não ser livres como steamrt
essa que contém algum código da nvidia, obrigado simpson!). Para usá-lo, basta instalar steam-run
e, em seguida:
steam-run ./wolframscript
ou se você quiser um shell completo:
steam-run bash
Note que você pode precisar adicionar nixpkgs.config.allowUnfree = true;
(ou whitelist este pacote específico ), se você quiser instalá-lo com nixos-rebuild
, e se você deseja executar / instalá-lo com nix-shell
/ nix-env
você precisa colocar { allowUnfree = true; }
em ~/.config/nixpkgs/config.nix
.
Não é fácil "sobrescrever" pacotes ou bibliotecas para o nix-shell, mas se você deseja criar um wrapper em torno de seu script, é possível criar manualmente um script de wrapper:
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p steam-run
exec steam-run ./wolframscript "$@"
ou escreva-o diretamente em uma derivação 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 se você começar do .deb (aqui eu usei makeWrapper
):
{ 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 você está cansado demais para escrever o habitual default.nix
, pode correr diretamente nix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}"
)
FAÇAM
https://nixos.org/nixos/manual/index.html#module-services-flatpak
appimage-run: para testar com, ex, musescore