Какие существуют методы для запуска исполняемого файла не nixos в NixO? Я хотел бы видеть также ручные методы.
Какие существуют методы для запуска исполняемого файла не nixos в NixO? Я хотел бы видеть также ручные методы.
Ответы:
Вот несколько методов (ручные в основном для образовательных целей, так как в большинстве случаев лучше написать правильный вывод). Я вообще не эксперт, и я сделал этот список также для изучения nix, так что если у вас есть лучшие методы, дайте мне знать!
Таким образом, основная проблема заключается в том, что исполняемый файл сначала вызывает загрузчик, а затем ему нужны некоторые библиотеки для работы, и nixos помещает как загрузчик, так и библиотеки /nix/store/
.
В этом списке приведены все методы, которые я нашел до сих пор. Есть в основном три "группы":
Я бы порекомендовал метод 4 с autoPatchelfHook
для реальной, правильной настройки, и если у вас нет времени и вы просто хотите запустить двоичный файл в одну строку, вас может заинтересовать быстрое и грязное решение, основанное на steam-run
(метод 7 ).
Сначала вам нужно найти загрузчик, например 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
Здесь загрузчик есть /lib64/ld-linux-x86-64.so.2
. Чтобы найти загрузчик nixos, вы можете сделать:
$ ls /nix/store/*glibc*/lib/ld-linux-x86-64.so.2
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2
Вам также нужно найти библиотеки, которые требуются вашей программе, например 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)
Здесь вы видите, что большинство библиотек найдено кроме libstdc++.so.6
. Итак, давайте найдем это:
$ find /nix/store -name libstdc++.so.6
/nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/libstdc++.so.6
Хорошо. Теперь нам просто нужно запустить программу с LD_LIBRARY_PATH
настроенным указателем на этот файл и вызвать загрузчик, который мы определили на первом шаге для этого файла:
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
(Обязательно используйте ./
перед именем сценария и сохраняйте только каталог библиотек. Если у вас несколько библиотек, просто используйте путь concat с двоеточиями)
После установки (с nixenv -i
или в ваш configuration.nix
) patchelf
вы также можете напрямую изменить исполняемый файл, чтобы упаковать хороший загрузчик и библиотеки. Чтобы изменить загрузчик, просто запустите:
patchelf --set-interpreter /nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.2 wolframscript
и проверить:
$ patchelf --print-interpreter wolframscript
/nix/store/681354n3k44r8z90m35hm8945vsp95h1-glibc-2.27/lib/ld-linux-x86-64.so.
и чтобы изменить путь к библиотекам, жестко закодированным в исполняемом файле, сначала проверьте текущий rpath (пустой для меня):
$ patchelf --print-rpath wolframscript
и добавьте их к указанному ранее пути к библиотеке, в конце концов разделив двоеточиями:
$ patchelf --set-rpath /nix/store/12zhmzzhrwszdc8q3fwgifpwjkwi3mzc-gcc-7.3.0-lib/lib/ wolframscript
$ ./wolframscript
Мы можем воспроизвести более или менее одно и то же в выводе nix, вдохновленном skypeforlinux
Этот пример представляет также альтернативу, которую вы можете использовать:
patchelf --set-interpreter ${glibc}/lib/ld-linux-x86-64.so.2 "$out/bin/wolframscript" || true
(что должно быть достаточно ясно, как только вы поймете «ручной» метод), или
patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$out/bin/wolframscript" || true
Этот второй метод немного более тонкий, но если вы запустите:
$ 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
вы увидите, что файл $NIX_CC/nix-support/dynamic-linker
содержит путь к загрузчику ld-linux-x86-64.so.2
.
Положить derivation.nix
, это
{ 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" ];
};
}
и на default.nix
месте:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
Скомпилируйте и запустите
nix-build
result/bin/wolframscript
Всем предыдущим методам нужно немного поработать (нужно найти исполняемые файлы, исправить их ...). NixOs сделал для нас специальный «крючок», autoPatchelfHook
который автоматически исправляет все для вас! Вам просто нужно указать это (native)BuildInputs
, и nix делает волшебство.
{ 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" ];
};
}
Некоторое программное обеспечение может быть сложно упаковать таким образом, поскольку оно может сильно зависеть от структуры файлового дерева FHS или может проверить, что двоичный файл не изменился. Затем вы также можете использовать buildFHSUserEnv для предоставления файловой структуры FHS (облегченной, с использованием пространств имен) для вашего приложения. Обратите внимание, что этот метод тяжелее, чем методы на основе исправлений, и добавляет значительное время запуска, поэтому избегайте его, когда это возможно
Вы можете либо просто создать оболочку, а затем вручную извлечь архив и выполнить файл, либо напрямую упаковать свою программу для FHS. Давайте сначала посмотрим, как получить оболочку. Поместите в файл (скажем fhs-env.nix
) следующее:
let nixpkgs = import <nixpkgs> {};
in nixpkgs.buildFHSUserEnv {
name = "fhs";
targetPkgs = pkgs: [];
multiPkgs = pkgs: [ pkgs.dpkg ];
runScript = "bash";
}
и запустить:
nix-build fhs-env.nix
result/bin/fhs
Затем вы получите bash в более стандартно выглядящем linux и можете запускать команды для запуска вашего исполняемого файла, например:
mkdir wolf_fhs/
dpkg -x WolframScript_12.0.0_LINUX64_amd64.deb wolf_fhs/
cd wolf_fhs/opt/Wolfram/WolframScript/bin/
./wolfram
Если вам нужно больше библиотек / программ в качестве зависимостей, просто добавьте их в multiPkgs
(для всех поддерживаемых арок) или targetPkgs
(только для текущей арки).
Бонус: вы также можете запустить оболочку fhs с помощью однострочной команды, не создавая специальный файл:
nix-build -E '(import <nixpkgs> {}).buildFHSUserEnv {name = "fhs";}' && ./result/bin/fhs
источник: https://reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html
С buildFHSUserEnv
его помощью можно запускать множество программ, но вам нужно будет вручную указать все необходимые библиотеки. Если вам нужно быстрое решение, и у вас нет времени, чтобы точно проверить, какие библиотеки вам нужны, вы можете попробовать steam-run
(несмотря на название, оно не связано напрямую с Steam, а просто упаковывает много библиотек), что как buildFHSUserEnv
и во многих предустановленных общих библиотеках (некоторые из них могут быть несвободными, например steamrt
, упаковывает некоторый код nvidia, спасибо Симпсон!). Чтобы использовать его, просто установите steam-run
, а затем:
steam-run ./wolframscript
или если вы хотите полную оболочку:
steam-run bash
Обратите внимание , что вам может понадобиться , чтобы добавить nixpkgs.config.allowUnfree = true;
(или белый список этот конкретный пакет ) , если вы хотите установить его nixos-rebuild
, и если вы хотите запустить / установить его с nix-shell
/ nix-env
нужно положить { allowUnfree = true; }
в ~/.config/nixpkgs/config.nix
.
Нелегко «перезаписать» пакеты или библиотеки в nix-shell, но если вы хотите создать оболочку для вашего сценария, вы можете вручную создать сценарий оболочки:
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p steam-run
exec steam-run ./wolframscript "$@"
или прямо напишите это в выводе nixos:
{ stdenv, steam-run, writeScriptBin }:
let
src = ./opt/Wolfram/WolframScript/bin/wolframscript;
in writeScriptBin "wolf_wrapped_steam" ''
exec ${steam-run}/bin/steam-run ${src} "$@"
''
или если вы начинаете с .deb (здесь я использовал 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
'';
}
(если вы слишком устали, чтобы писать обычные default.nix
, вы можете запустить напрямую nix-build -E "with import <nixpkgs> {}; callPackage ./derivation.nix {}"
)
ДЕЛАТЬ
https://nixos.org/nixos/manual/index.html#module-services-flatpak
appimage-run: для тестирования, например, musescore