現在Nimのクロスコンパイラ環境をDockerで作ろうとしている。
Chromeのタブを開きまくっているので一度整理したいと思って記述

目的

echo "hello nim"1行を作ったしょぼいファイルを作成した。
src/hello.nimとして保存して、各OSで動作する仕組みを構築したい。

Linux -> Windows

LinuxからWindowsへクロスコンパイルする仕組みを検討。
まずはQiita等で情報収集をしていると、どうやらMinGWを使えば良いとのこと。

MinGWってWindowsのUnixライクなターミナルエミュレータ的なソフトじゃなかったっけ?
Wikipediaによると「Minimalist GNU for Windows」の略らしい。
シェルはMSYS、MinGWはUnix用ソフトウェアをWindowsで動かす為のプロジェクトだったのね。

Dockerfile

DockerHubにあるNimのイメージバージョンによってディストリビューションをコロコロ換えてて、
0.18現在ではAlpineしか用意されていなかった。
なのでAlpineにMinGWを導入したものを探した所、portown/alpine-mingw-w64がヒット。

nimlang/nimをベースに上記Dockerfile記述のものを取り入れようとしたがDL→インストールがうまく動作せずに断念。
調査した所、Dockerfileでのビルド時に「multi stage build」という手法が使えるらしい。
src/hello.nim.cfgを下記のように修正して

amd64.windows.gcc.path = "/usr/local/mingw/bin/"
amd64.windows.gcc.exe = "x86_64-w64-mingw32-gcc"
amd64.windows.gcc.linkerexe = "x86_64-w64-mingw32-gcc"
amd64.windows.gcc.options.linker = ""

コマンドを実行すると、src/hello.exeファイルが生成された。
(なお動作は未確認)

$ nim c --os:windows --cpu:amd64 -d:release src/hello.nim

参考サイト

Alpine -> Ubuntu

Dockerで作ったコンテナがAlpine Linux
コンパイル後にそのまま吐き出されたバイナリファイルを実行するとhello nimが表示されるが、
Ubuntuのメインマシンに持ち帰って実行するとさっぱり動かない。

# コンテナnimlang/nim内でコンパイル実行
$ nim c src/hello.nim

# Ubuntuに戻って実行
$ src/hello
Failed to execute process 'src/hello'. Reason:
The file 'src/hello' does not exist or could not be executed.

調査

Golangがワンバイナリ吐き出すので、それ関係で色々調べた所
C言語では動的リンクと静的リンクという概念がある事がわかった。

早速「C スタティックリンク」というワードで検索。
ファイルサイズが小さくなるように依存モジュールはOSのものを利用する想定でコンパイルするのが普通、
可搬性を重視する時は依存モジュールをバイナリの中に含めてファイルサイズを大きくする。

実践

Nimでそれをやるのにはどうすれば良いか調べた所。
この内容のhello.nim.cfghello.nimと同階層に設置。

@if musl:
  passL = "-static"
  gcc.exe = "/usr/local/musl/bin/musl-gcc"
  gcc.linkerexe = "/usr/local/musl/bin/musl-gcc"
@end

更にコマンド実行時にオプションを追加

$ nim c -d:musl -d:release src/hello.nim

# alpine
$ src/hello
hello nim

# ubuntu
$ src/hello
hello nim

エラーが出ずに動かなくなる事を確認できた

参考サイト

ToDo

動機がリンクを整理したかっただけで、まだまだ先は長いので引き続き調査&動作検証を行っていく。

  • Windows環境での動作チェック
  • Mac用のコンパイラの導入
  • 今作っているNim用のコマンドラインツールでの動作検証

参考サイト