自分用メモ。
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を作る。まず、こんな感じのテンプレートファイルを作る。
{ 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
'';
}
なにが起こっているかわからないが、buildInputs
にautoPatchElfHook
というのを入れておくと、Nixがパッケージのビルドのときによしなにリンクを貼ってバイナリが動くようにしてくれるらしい。
そんでこんな感じのoverlayを作る。
self: super: {
julia-bin = super.callPackage ./template.nix {
version = "1.5.3";
sha256 = "1yc60dl39sa0rbiaj2v7vf79j0c9zd93h1mwcahq99w44c81k3q6";
};
}
で、home.nix
のhome.packages
にjulia-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を書いて、
with import <nixpkgs> { };
python38.withPackages (p: [ p.notebook ])
以下のコマンドを打てば、Jupyter Notebookが使える。
> nix-shell shell.nix --run 'jupyter notebook'
Juliaから使えるようにする
IJulia.jlは、ENV["JUPYTER"]
にjupyter
コマンドのパスを渡してやるとそちらを優先して使ってくれる。そこで、startup.jl
にENV["JUPYTER"]
を設定するスクリプトを書いてしまう。
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
を作成する。
ENV["JUPYTER"] = @pythonWithJupyter@/bin/jupyter
@pythonWithJupyter@
の部分がNixで置換される。
このテンプレートファイルから実際のstartup.jl
を作成するためのhome-manager moduleを作成する。
{ 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
でインポートする。
imports = [ ./hm-modules/julia ];
ついでに、julia-bin
のインストールはjulia/default.nix
の方に書いてあるので、home.nix
のhome.packages
にjulia-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`
やったぜ。