現在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
参考サイト
- 全体的な調査
- Dockerfile
- Linux -> Windows
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.cfg
をhello.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用のコマンドラインツールでの動作検証