LoginSignup
2
1

More than 3 years have passed since last update.

NixOS+home-manager環境にJulia+IJuliaをインストールした。

Posted at

自分用メモ。

JuliaのインストールにもIJulia.jlのインストールにもハマりどころがあった。

Juliaのインストール

まず、NixpkgsのJuliaはかなり古いので、 nix-env -iA nixpkgs.julia で済ませられない。
そこで、涙を飲んでJuliaのバイナリを公式のダウンロードサイトからダウンロードして、実行してみようとする。

> curl -fLO "https://julialang-s3.julialang.org/bin/linux/x64/1.5/julia-1.5.3-linux-x86_64.tar.gz"

> tar -xf julia-1.5.3-linux-x86_64.tar.gz

> ./julia-1.5.3/bin/julia
Failed to execute process 'julia-1.5.3/bin/julia'. Reason:
The file 'julia-1.5.3/bin/julia' does not exist or could not be executed.

かなしいことに、うまくいかない。

なぜならjuliaのバイナリは実行環境としてFHSに準拠したファイルシステムを想定しているからであり、NixOSはFHSに準拠していないからである。

とりわけ、/lib64/ld-linux-x86-64.so.2が必要なのだが、NixOSには/lib64ディレクトリがない。楽だけどNixらしくない方法としては、シンボリックを貼ってしまうという手が考えられる。

> sudo mkdir /lib64

> sudo ln -s /nix/store/9df65igwjmf2wbw0gbrrgair6piqjgmi-glibc-2.31/lib64/ld-linux-x86-64.so.2 /lib64/ld-linux-x86-64.so.2

一応はこれですぐに動くけど、正直こんなやり方はNixらしくない。第一、nix-env -u をしたらいつの間にかシンボリックが壊れてしまいそうである。

そこで、overlayを作る。まず、こんな感じのテンプレートファイルを作る。

.config/nixpkgs/overlays/julia/template.nix
{ stdenv
, glibc
, autoPatchelfHook
, version
, sha256
}:

stdenv.mkDerivation rec {
  pname = "julia-bin";
  inherit version;

  src = builtins.fetchTarball {
    url = "https://julialang-s3.julialang.org/bin/linux/x64/1.5/julia-${version}-linux-x86_64.tar.gz";
    inherit sha256;
  };

  buildInputs = [ glibc ];
  nativeBuildInputs = [ autoPatchelfHook ];
  installPhase = ''
    mkdir -p $out
    cp -a $src/* $out
  '';
}

なにが起こっているかわからないが、buildInputsautoPatchElfHookというのを入れておくと、Nixがパッケージのビルドのときによしなにリンクを貼ってバイナリが動くようにしてくれるらしい。

そんでこんな感じのoverlayを作る。

.config/nixpkgs/overlays/julia/default.nix
self: super: {
  julia-bin = super.callPackage ./template.nix {
    version = "1.5.3";
    sha256 = "1yc60dl39sa0rbiaj2v7vf79j0c9zd93h1mwcahq99w44c81k3q6";
  };
}

で、home.nixhome.packagesjulia-binを追加してhome-manager switchすればjuliaのインストールができる。

> home-manager switch

> julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.5.3 (2020-11-09)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> 

IJuliaのインストール

何も考えずにadd IJuliaでインストールできるわけではない。

julia> ]

(@v1.5) pkg> add IJulia

julia> using IJulia

julia> notebook()
install Jupyter via Conda, y/n? [y]: 
[ Info: Downloading miniconda installer ...
[ Info: Installing miniconda ...
PREFIX=/home/hnakano/.julia/conda/3
Unpacking payload ...
/home/hnakano/.julia/conda/3/installer.sh: 行 412: /home/hnakano/.julia/conda/3/conda.exe: No such file or directory
/home/hnakano/.julia/conda/3/installer.sh: 行 414: /home/hnakano/.julia/conda/3/conda.exe: No such file or directory
ERROR: failed process: Process(`/home/hnakano/.julia/conda/3/installer.sh -b -f -p /home/hnakano/.julia/conda/3`, ProcessExited(1)) [1]

どうやらIJulia.jlがminicondaのインストーラを使ってcondaコマンドとjupyterをインストールしようとするのだが、このminicondaインストーラがやはりFHSを前提としているようでNixOSでは動かない。

そこでまずはNixOS上にjupyterをインストールし、juliaにはそのjupyterの場所を教えてあげることでminicondaインストーラを使わずにことを済ませよう。

Jupyter Notebookのインストール

ここにも罠があるのだが、nixpkgs.jupyterをインストールしてもjupyterコマンドが使えるようになるわけではない。

> nix-env -iA nixpkgs.jupyter

> jupyter notebook
The program ‘jupyter’ is currently not installed. It is provided by
several packages. You can install it by typing one of the following:
  nix-env -iA nixos.python27Packages.jupyter_core
  nix-env -iA nixos.python37Packages.jupyter_core
  nix-env -iA nixos.python38Packages.jupyter_core

大変わかりにくいことに、エラーメッセージに従ってnixos.python37Packages.jupyter_coreをインストールしたところで問題は解決しない。

解決策として、依存ライブラリにnotebookというのを入れたpythonごとインストールするとJupyter Notebookが使えるようになる。

まず、以下のshell.nixを書いて、

shell.nix
with import <nixpkgs> { };
python38.withPackages (p: [ p.notebook ])

以下のコマンドを打てば、Jupyter Notebookが使える。

> nix-shell shell.nix --run 'jupyter notebook'

Juliaから使えるようにする

IJulia.jlは、ENV["JUPYTER"]jupyterコマンドのパスを渡してやるとそちらを優先して使ってくれる。そこで、startup.jlENV["JUPYTER"]を設定するスクリプトを書いてしまう。

.julia/config/startup.jl
ENV["JUPYTER"] = "/nix/store/smfflp34ggglyyamw45sazgiv49snh7h-python3-3.8.6-env/bin/jupyter"

この/nix/store/smff...-python3-3.8.6-envというのは、さっきshell.nixを作ったときに作成されたnix storeで、ここのbin以下にjupyterコマンドが入っている。

もちろんこれでjuliaを起動してbuild IJuliaすればIJuliaが使えるようになるのだが、この方法はNixらしくない(2回目)し、うっかりnix-collect-garbage -dとかした日には動かなくなってしまうかもしれない。

そこで、juliaの設定用にhome-managerのモジュールを作成する。

まず、nixを使ってstartup.jlを書くために、テンプレートファイルstartup.jl.inを作成する。

.config/nixpkgs/hm-modules/julia/startup.jl.in
ENV["JUPYTER"] = @pythonWithJupyter@/bin/jupyter

@pythonWithJupyter@の部分がNixで置換される。

このテンプレートファイルから実際のstartup.jlを作成するためのhome-manager moduleを作成する。

.config/nixpkgs/hm-modules/julia/default.nix
{ config, pkgs, lib, ... }:
with pkgs;
with lib;
let
  pythonWithJupyter = python38.withPackages (p: [ p.notebook ]);
  startup-jl = runCommand "startup.jl" { inherit pythonWithJupyter; } ''
    substituteAll "${./startup.jl.in}" $out
  '';
in
{
  home.packages = [
    julia-bin
  ];

  home.file.".julia/config/startup.jl".source = startup-jl;
}

キモは、runCommandの中でsubstituteAllを使ってstartup.jl.inの中の@pythonWithJupyter@の部分をNixで作成したjupyter環境へのパスで置換していること、そして、置換してできたstartup.jlのパス(これの実態はnix storeの中のテキストファイル)からhome.fileを利用して~/.julia/config/startup.jlへシンボリックを貼っていることである。

このモジュールをhome.nixでインポートする。

.config/nixpkgs/home.nix
imports = [ ./hm-modules/julia ];

ついでに、julia-binのインストールはjulia/default.nixの方に書いてあるので、home.nixhome.packagesjulia-binの記述がある場合は消しておいたほうがよい。

以上のことを終えたうえでhome-manager switchしてbuild IJuliaすればIJulia.jlがちゃんと機能する。

> home-manager switch

> julia -q

julia> ]

(@v1.5) pkg> build IJulia
   Building Conda ─→ `~/.julia/packages/Conda/x5ml4/deps/build.log`
   Building IJulia → `~/.julia/packages/IJulia/IDNmS/deps/build.log`

julia> using IJulia

julia> notebook()
[ Info: running `/nix/store/smfflp34ggglyyamw45sazgiv49snh7h-python3-3.8.6-env/bin/jupyter notebook`

やったぜ。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1