Nimのクロスコンパイル環境をDockerで整える

# 本記事について
Nimのクロスコンパイル環境をDocker上で構築したのでそれのまとめ．
基本的に今後の自分のためのまとめになりますが，他の人の参考になれれば幸いです．

利用する際には，[rirycasals/nim-cross-compile-env](https://hub.docker.com/r/rirycasals/nim-cross-compile-env/tags) をpullするか，[RiRyCasals/nim-cross-compile-env](https://github.com/RiRyCasals/nim-cross-compile-env) にあるDockerfileをビルドしてください．

# Dockerfile
```Dockerfile:Dockerfile
FROM --platform=arm64 ubuntu:latest
ENV SDK_VERSION=11.3
ENV TZ=Asia/Tokyo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone &&\
    apt update && apt upgrade -y &&\
    apt install -y  gcc clang cmake make automake autogen patch cpio gzip bzip2 vim wget git sed tar pip \
                    python xz-utils uuid-dev llvm-dev lzma-dev libxml2-dev libssl-dev libbz2-dev libtool \
                    gcc-x86-64-linux-gnu mingw-w64 binutils-mingw-w64 gcc-mingw-w64 g++-mingw-w64 &&\
    git clone https://github.com/nim-lang/Nim /Nim &&\
    echo 'export PATH=$PATH:/Nim/bin' >> ~/.bashrc &&\
    cd /Nim &&\
    sh build_all.sh &&\
    git clone https://github.com/tpoechtrager/osxcross.git /osxcross &&\
    wget -P /osxcross/tarballs https://github.com/phracker/MacOSX-SDKs/releases/download/${SDK_VERSION}/MacOSX${SDK_VERSION}.sdk.tar.xz &&\
    cd /osxcross &&\
    echo -e "\n" | ./build.sh &&\
    echo 'export PATH=$PATH:/osxcross/target/bin' >> ~/.bashrc
WORKDIR /work
CMD ["bash"]
```

---

```Dockerfile:
FROM --platform=arm64 ubuntu:latest
```
ベースイメージは Ubuntu．（本当はタグを指定すべきだと思う）
プラットフォームが arm64 なのは，後述する [osxcross](https://github.com/tpoechtrager/osxcross) のビルドが amd64 上だとうまく行かなかったためである．
また，公式の[nimlang/nim](https://hub.docker.com/r/nimlang/nim/tags) はアーキテクチャが amd64 で，上記と同じ理由で使用していない．

---

```Dockerfile:
ENV SDK_VERSION=11.3
```
後述する [MacOSX SDK](https://github.com/phracker/MacOSX-SDKs) のバージョンのための変数．

---

```Dockerfile:
ENV TZ=Asia/Tokyo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone &&\
```
初回の `apt install` のときにタイムゾーンの入力を求められたので，それに対する対応策．

---

```Dockerfile:RUNの2~5行目
    apt update && apt upgrade -y &&\
    apt install -y  gcc clang cmake make automake autogen patch cpio gzip bzip2 vim wget git sed tar pip \
                    python xz-utils uuid-dev llvm-dev lzma-dev libxml2-dev libssl-dev libbz2-dev libtool \
                    gcc-x86-64-linux-gnu mingw-w64 binutils-mingw-w64 gcc-mingw-w64 g++-mingw-w64 &&\
```
`gcc-x86_64-linux-gnu` は cpu アーキテクチャが am64/x86_64 の Linux に向けたクロスコンパイルを行う際に必要となる，クロスコンパイラツールチェーン．
`mingw-w64 binutils-mingw-w64 gcc-mingw-w64 g++-mingw-w64` は cpu アーキテクチャが am64/x86_64 の Windows に向けたクロスコンパイルを行う際に必要となる，クロスコンパイラツールチェーン．

---

```Dockerfile:RUNの6~9行目
    git clone https://github.com/nim-lang/Nim /Nim &&\
    echo 'export PATH=$PATH:/Nim/bin' >> ~/.bashrc &&\
    cd /Nim &&\
    sh build_all.sh &&\
```
Nimのビルドインストール．

---

```Dockerfile:RUNの9行目以降
    git clone https://github.com/tpoechtrager/osxcross.git /osxcross &&\
    wget -P /osxcross/tarballs https://github.com/phracker/MacOSX-SDKs/releases/download/${SDK_VERSION}/MacOSX${SDK_VERSION}.sdk.tar.xz &&\
    cd /osxcross &&\
    echo -e "\n" | ./build.sh &&\
    echo 'export PATH=$PATH:/osxcross/target/bin' >> ~/.bashrc
```
[osxcross](https://github.com/tpoechtrager/osxcross) は MaxOSX へのクロスコンパイルを行うためのクロスコンパイルツールチェーンのビルド．
SDKのバージョンを `${SDK_VERSION}` で指定しているので，これ以外のバージョンへクロスコンパイルを行うためには Dockerfile を変更するか，立ち上げたコンテナ内で別のSDKをインストールし，ビルドし直す必要がある．
osxcross をビルドするためには MacOSX SDK をビルドして取り込む必要があるのだが，それを [GitHub (MacOSX-SDKs)](https://github.com/phracker/MacOSX-SDKs) で公開してくれている人がいるので利用．
`./build.sh` をすると，Enterの入力を求められるので，`echo -e "\n" | ./build.sh &&\` として入力を渡してあげる．

---

```Dockerfile:
WORKDIR /work
CMD ["bash"]
```
基本的にDockerの利用目的が開発環境の構築なので，いつも作業スペースとして `/work` を用意し，コンテナ立ち上げ時には `bash` に入るようにしている．

# ~.nim.cfg
クロスコンパイル時に使うコンパイラの指定をする．
`nim.config` に直接記述する方法もあるとは思うが，`ビルドしたいnimファイル名.cfg` で設定できる．
以降，コンパイル対象のファイルを `hello.nim` ，コンパイル設定ファイルを `hello.nim.cfg` とする．

```nim:hello.nim.cfg
# for Linux
# amd64/x86_64
amd64.linux.gcc.path = "/usr/bin"
amd64.linux.gcc.exe = "x86_64-linux-gnu-gcc"
amd64.linux.gcc.linkerexe = "x86_64-linux-gnu-gcc"
# arm64/aarch64
arm64.linux.gcc.path = "/usr/bin"
arm64.linux.gcc.exe = "aarch64-linux-gnu-gcc"
arm64.linux.gcc.linkerexe = "aarch64-linux-gnu-gcc"

# for MacOSX
# amd64/x86_64
amd64.macosx.clang.path = "/osxcross/target/bin"
amd64.macosx.clang.exe = "x86_64-apple-darwin20.4-clang"
amd64.macosx.clang.linkerexe = "x86_64-apple-darwin20.4-clang"
# arm64/aarch64
arm64.macosx.clang.path = "/osxcross/target/bin"
arm64.macosx.clang.exe = "aarch64-apple-darwin20.4-clang"
arm64.macosx.clang.linkerexe = "aarch64-apple-darwin20.4-clang"

# for Windows
# amd64/x86_64
amd64.windows.gcc.path = "/usr/bin"
amd64.windows.gcc.exe = "x86_64-w64-mingw32-gcc"
amd64.windows.gcc.linkerexe = "x86_64-w64-mingw32-gcc"
```

---

```nim:
# for Linux
# amd64/x86_64
amd64.linux.gcc.path = "/usr/bin"
amd64.linux.gcc.exe = "x86_64-linux-gnu-gcc"
amd64.linux.gcc.linkerexe = "x86_64-linux-gnu-gcc"
# arm64/aarch64
arm64.linux.gcc.path = "/usr/bin"
arm64.linux.gcc.exe = "aarch64-linux-gnu-gcc"
arm64.linux.gcc.linkerexe = "aarch64-linux-gnu-gcc"
```

`x86_64-linux-gnu-gcc` は `gcc-x86_64-linux-gnu` をインストールすることで利用できる．
`aarch64-linux-gnu-gcc` は `gcc` インストール時のデフォルト．（プラットフォームが arm64 だから）

---

```nim:
# for MacOSX
# amd64/x86_64
amd64.macosx.clang.path = "/osxcross/target/bin"
amd64.macosx.clang.exe = "x86_64-apple-darwin20.4-clang"
amd64.macosx.clang.linkerexe = "x86_64-apple-darwin20.4-clang"
# arm64/aarch64
arm64.macosx.clang.path = "/osxcross/target/bin"
arm64.macosx.clang.exe = "aarch64-apple-darwin20.4-clang"
arm64.macosx.clang.linkerexe = "aarch64-apple-darwin20.4-clang"
```

`x86_64-apple-darwin20.4-clang` と `aarch64-apple-darwin20.4-clang` は osxcross のビルドに成功すれば利用できる．

---

```nim:
# for Windows
# amd64/x86_64
amd64.windows.gcc.path = "/usr/bin"
amd64.windows.gcc.exe = "x86_64-w64-mingw32-gcc"
amd64.windows.gcc.linkerexe = "x86_64-w64-mingw32-gcc"
```

`x86_64-w64-mingw32-gcc` は `mingw-w64 binutils-mingw-w64 gcc-mingw-w64 g++-mingw-w64` をインストールすることで利用できる．

# コンパイルコマンド

* Linux
  * amd64/x86_64
    `nim c --os:linux --cpu:amd64 hello.nim`
* Linux
  * arm64/aarch64
    `nim c --os:linux --cpu:arm64 hello.nim`
* MacOSX
  * amd64/x86_64
    `nim c --os:macosx --cpu:amd64 hello.nim`
* MacOSX
  * arm64/aarch64
    `nim c --os:macosx --cpu:arm64 hello.nim`
* Windows
  * amd64/x86_64
    `nim c --os:windows --cpu:amd64 hello.nim`