Julia 1.1.0 をソースからビルドして RaspberryPi Zeroシリーズ や 3B+ とかで使いたいんじゃが？（Dockerでクロスコンパイルでどうじゃろ？）

# 本日は

一般にプログラミング言語の Julia はビルド済みのバイナリーを公式サイトからダウンロードしパスを通すことで使用することができます.


- https://julialang.org/downloads/


ラズパイはどうでしょうか？ `Generic Linux Binaries for ARM` の ３２ ビットのを選ぶことでできます.
ただし, 提供されているものは Juliaのバージョンの v1.0.3 であり, `ARMv7-a hard float` をサポートするCPUという制限付きです. ３２ビットで動作するラズビアンをOSとする Raspberry Pi 2, ３B および ３B+ では利用することができますが、Raspberry Pi Zero シリーズだと搭載されているCPUの命令セットがこれらのと異なるため `Illegal instruction` で怒られてしまいます(この現象は Julia に限らず, 例えば, Pi3 上で TensorFlow を pip でインストールしたSDカードを Pi zero に移して動かすと出てしまうということでも起きます). 

## そうだビルドしよう.

ZeroシリーズはCPUは貧弱ですが小型さ故に意外と人気のあるので Julia を使いたい人もいるやもしれません. 
公式で用意されていないのであれば自分でビルドすればいいのです.本日は Raspberry Pi シリーズで Julia をソースからビルドして使う方法を紹介します.

- ~~2019/5/1 現在 Arm32bit が　Tier 3 に格下げになってしまったようです.~~
- 現行では Tier3 から Tier2 に修正されました．

# まずビルドの流れをおさえます.

Raspberry Pi シリーズに限らず(Intel CPU をハードに持つ Ubuntu マシーン上などで) Julia をソースから（ビルドそしてインストール）する方法は次の手順に従います。

1. https://github.com/JuliaLang/julia の `README.md` を読む
1. `apt install` などで依存パッケージを導入 [See here](https://github.com/JuliaLang/julia/blob/master/doc/build/build.md#required-build-tools-and-external-libraries)
1. https://github.com/JuliaLang/julia からソースをクローンする
1. ビルドして使いたいJuliaのバージョンを指定するためにチェックアウトする
1. 必要に応じて `Make.user` を指定（`prefix=hoge/moge/piyo/` でインストールする場所を指定します）
1. `make -j N && make install` を実行（ここでNは並列ビルドするときのジョブの数）


(2019/5/1 現在では Julia のドキュメント構造が色々動いているみたいです。 適宜最新のドキュメントをチェックするようにしましょう。)

上記のフローを Ubuntu マシーンで Docker による自動化する方法を [こちらのGist](本日は Raspberry Pi シリーズで Julia をソースからビルドして使う方法を紹介します.) にて公開しています. Dockerﾜｶﾗﾝな人でもDockerfileに書かれている内容をターミナルで動かすと雰囲気をつかめると思います。恐れずにやってみましょう。

やってみるとわかるのですが　`make -j N && make install`　の作業は時間がかかります.性能の良いPCがあると快適にビルドができます。

# ラズパイ３の上でビルド

https://github.com/JuliaLang/julia/blob/v1.1.0/README.arm.md を参考に進めます。
master のドキュメントの生息場所が変わったようです（https://github.com/JuliaLang/julia/blob/master/doc/build/arm.md）
OSはRaspbianを用います。(CUIをベースとする lite で成功確認)

まずは依存パッケージを導入します。

```console
$ sudo apt-get update 
$ sudo apt-get install build-essential libatomic1 python gfortran perl wget m4 cmake pkg-config git
$ git clone --depth=1 -b v1.1.0 https://github.com/JuliaLang/julia.git 
```

次に下記の内容を `Make.uer` というファイル名で作成します。

```
JULIA_CPU_TARGET=cortex-a7
MARCH=armv7-a 
prefix=/home/pi/work/julia-1.1.0
```

これをクローンした `julia` の直下に保存します。
この後 make を走らせればいいのですが、ラズパイのメモリが少ないのでスワップ領域を増やします

`/etc/dphys-swapfile` を編集し `CONF_SWAPSIZE=100` を `CONF_SWAPSIZE=2048` にします。
公式だと500で十分っぽいですが念の為増やしています。

```
sudo /etc/init.d/dphys-swapfile stop
sudo /etc/init.d/dphys-swapfile start
```

でスワップ領域の値を更新します。

そして `make -j 4 && sudo make install` を実行します。1日ないしは2日待ちます。

# 手元の Desktop マシーン上で Docker を用いたクロスコンパイルする

手元のマシーンが高性能な場合はクロスコンパイルすることも検討したほうがいいかもしれません. 下記の記事が参考になります.

- [x86_64のUbuntuでC/C++のソースコードをARM/ARM64用にクロスコンパイルしてQEMUで実行する方法のまとめ](https://qiita.com/tetsu_koba/items/9bdcb59f912efbff3128)
- [ラズパイ向けのOpenCVを、x86_64機のDockerでビルド](https://qiita.com/mt08/items/51a2187076ddca0db7b0)


~~[こちらのGist](https://gist.github.com/terasakisatoshi/00fa7d7b81b7c6748f2298f6ff65bf6e) にて公開している方法を実行していきます。~~

おそらくこの方法で良いです．See: opencv-rpi-buildenv-docker/inst_prereq.sh

```
$ apt-get update
$ apt-get install -y qemu-user-static binfmt-support 
```

`resin/rpi-raspbian:stretch` は deprecated になったらしいので `balenalib/raspberrypi3:stretch` を用います。まずは下記を実行しコンテナが立ち上がるかを確認します。

```console
$ sudo docker run --rm -it -v $PWD:/home/pi/work -w /home/pi/work balenalib/raspberrypi3:stretch bash
# 動作を確認したら終了する
```

動かない場合は docker-machine が入っていない可能性があります。今一度見直しておきます。

```
# 多分これをすればいい気がする See
# https://github.com/mt08xx/opencv-rpi-buildenv-docker/blob/master/inst_prereq.sh
$ sudo apt-get install -y qemu-user-static binfmt-support
```


`Make.user` という名前で下記を記述します。

```
JULIA_CPU_TARGET=cortex-a7
MARCH=armv7-a 
prefix=/home/pi/work/julia-1.1.0
```

そして `prepare.sh` というスクリプトを用意します。

```
apt-get update
apt-get install build-essential libatomic1 python gfortran perl wget m4 cmake pkg-config git
git clone --depth=1 -b v1.1.0 https://github.com/JuliaLang/julia.git
cp Make.user julia/Make.user
```

これらをホストの作業ディレクトリに移し、コンテナを立ち上げます。

```
$ ls 
Make.user prepare.sh
$ sudo docker run --rm -it -v $PWD:/home/pi/work -w /home/pi/work balenalib/raspberrypi3:stretch bash
```

コンテナの中で下記を実行します。

```
# bash prepare.sh
# cd julia
# make -j 8 && make install
# exit
```

-j の値は各自のCPU論理コア数に合わせて指定しておきます。これも結構かかります。寝る前にしておくと良いでしょう。

ビルドが成功するとホストの作業ディレクトリに `julia-1.1.0` というのができます。これをラズパイ３に移動して `/path/to/julia-1.1.0/bin` をラズパイの環境変数の `PATH` に追加することで実行できます.

# Zero用にクロスコンパイルする

PiZero上でビルドするのはあまりにも遅すぎたので大人しく `balenalib/raspberry-pi:stretch` を用いてクロスコンパイルします. Pi3 と異なり使用するDockerのイメージは異なりますので注意してください。

[こちらのGist](https://gist.github.com/terasakisatoshi/3f8a55391b1fc22a5db4a43da8d92c98) にて手順書を公開しています.

Zeroシリーズ向けのビルドでは OpenBlas のビルドがこけてしまうので apt で導入したパッケージを用いますということを宣言するために `Make.user` に色々 override の設定を書く必要がありました。

```
JULIA_CPU_TARGET=arm1176jzf-s
prefix=/home/pi/work/julia-1.1.0
override USE_SYSTEM_BLAS=1
override USE_SYSTEM_LAPACK=1
override USE_SYSTEM_LIBM=1
override USE_SYSTEM_GMP=1
override USE_SYSTEM_MPFR=1
```

あとはDockerのコンテナを立ち上げでその中で依存パッケージを導入して make するだけです。同様に時間がかかりますので寝る前に放置しておきましょう。

ホスト側の作業ディレクトリに `julia-1.1.0` ができますのでこれを手元の Pi Zero に移してあげて PATH を通しておきます。Juliaの実行時に依存パッケージを用いるのでそれらを導入しておきます。

```
$ sudo su (or you can type sudo apt install ....)
# apt-get update
# apt-get install build-essential libatomic1 python gfortran perl wget m4 cmake pkg-config git 

# apt install libopenblas-base libopenblas-dev
# apt install libatlas3-base libatlas-base-dev
# apt install liblapack-dev
# apt install libmpfr-dev libgmp3-dev
# apt install libgfortran3
```

これで使えるはずです。
今の所問題なく動いています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/c71eff6c-4e8c-b7a6-3bf9-5389548d60d3.png)


# まとめ

- Juliaをソースからビルドする手順を公開しました。
- ラズパイシリーズでビルドは困難なのでDockerによるクロスコンパイルをする手法をとりました。