Nixosで非Nixos実行可能ファイルを実行するさまざまな方法


12

NixOでNixos以外の実行可能ファイルを実行するには、どのような方法がありますか?手動の方法も見てみたいです。

回答:


22

ここにいくつかの方法があります(手動による方法は、ほとんどの場合、適切な派生を書く方が良いため、ほとんどが教育目的のためです)。私はまったく専門家ではありません。また、このリストはnixを学ぶためにも行ったので、より良い方法がある場合は、お知らせください!

したがって、主な問題は、実行可能ファイルが最初にローダーを呼び出し、次に機能するためにいくつかのライブラリーを必要とすること、そしてnixosがローダーとライブラリーの両方をに配置すること/nix/store/です。

このリストは、これまでに見つけたすべての方法を示しています。基本的に3つの「グループ」があります。

  • 完全なマニュアル:教育目的で、何が起こっているのかを理解するために興味深いが、それだけです(後でガベージコレクションに使用された派生物を妨げるものがないため、実際には使用しないでください)。
  • パッチが適用されたバージョン:これらのメソッドは、実行可能ファイルを修正して(推奨されるメソッド4のautoPatchelfHookを使用する場合は自動的に)、適切なライブラリを直接指すようにします。
  • FHSに基づくメソッド。基本的には「通常のLinux」を偽造します(パッチを適用したバージョンよりも実行が重いため、可能であればこれを回避する必要があります)。

私はautoPatchelfHook実際の適切な設定のためにメソッド4をお勧めします。時間がない場合にバイナリを1行で実行したい場合は、steam-run(メソッド7 )。

方法1)汚れた手動の方法、パッチなし

たとえば、最初にローダーを見つける必要があります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

./スクリプト名の前に使用し、ライブラリのディレクトリのみを保持するようにしてください。複数のライブラリがある場合は、パスをコロンで連結してください)

方法2)ダーティ手動方法、パッチあり

インストール後(nixenv -iまたはでconfiguration.nixpatchelf、実行可能ファイルを直接変更して適切なローダーとライブラリをパックすることもできます。ローダーを変更するには、次のコマンドを実行します。

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

方法3)nix派生のパッチ

skypeforlinuxに触発されたnix派生で、ほぼ同じものを再現できます。

この例は、次のいずれかを使用できる代替案も示しています。

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

この2番目の方法は少し微妙ですが、実行すると:

$ 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.nixPUT:

{ pkgs ? import <nixpkgs> {} }:

pkgs.callPackage ./derivation.nix {}

コンパイルして実行

nix-build
result/bin/wolframscript

方法4)autoPatchElfを使用する:シンプル

以前のすべてのメソッドには少し作業が必要です(実行可能ファイルを見つけてパッチを適用する必要があります...)。NixOは、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" ];
  };
}

方法5)FHSを使用してクラシック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

次に、より標準的な外観のLinuxでbashを取得し、次のようなコマンドを実行して実行可能ファイルを実行できます。

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

依存関係としてより多くのライブラリ/プログラムが必要な場合は、それらをmultiPkgs(サポートされているすべてのアーチの場合)またはtargetPkgs(現在のアーチのみの場合)に追加します。

おまけ:特定のファイルを作成せずに、1行のコマンドでfhsシェルを起動することもできます。

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

方法6)FHSを使用してクラシックLinuxシェルをシミュレートし、ファイルを内部にパックする

ソース:https : //reflexivereflection.com/posts/2015-02-28-deb-installation-nixos.html

方法7)スチームラン

buildFHSUserEnv多くのソフトウェアを実行できますが、必要なすべてのライブラリを手動で指定する必要があります。迅速な解決策が必要で、必要なライブラリを正確に確認する時間がない場合は、試してみてくださいsteam-run(名前にもかかわらず、steamに直接リンクされておらず、多数のライブラリがパックされているだけです)。buildFHSUserEnv多くの一般的なライブラリがプリインストールされているようなものです(それらのいくつかはsteamrt、いくつかのnvidiaコードをパックするようにnon-freeかもしれません、simpsonに感謝します!)。使用するには、をインストールして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 {}"

方法8)コンテナー/ Dockerを使用する(かなり重い)

TODO

方法9)flatpack / appimageに依存する

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

appimage-run:musescoreでテストするには

ソースまたは例

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.