Goは1つのコードで複数のOS, アーキテクチャにクロスコンパイルすることが出来る。
それも面倒な事前準備とかが必要ないのも特徴でGo1.5より前はmake.bash
をコンパイルするプラットフォームで実行してみたいなことが必要だったけどGo1.5からは必要なくなって次のようなコマンドでコンパイル出来るようになっている。
$ GOOS=linux GOARCH=amd64 go build main.go $ GOOS=linux GOARCH=386 go build main.go $ GOOS=darwin GOARCH=amd64 go build main.go $ GOOS=darwin GOARCH=386 go build main.go
※ 対応しているOS, ARCHはここから確認が出来る
Goではcgoを使ってCのコードを呼び出すことが出来るものがあるけど、これを使ったコードをクロスコンパイルする時にいくつか問題にあたった。
今回はUbuntuでビルドしてました。
クロスコンパイル時はCGO_ENABLEDはデフォルトでは有効にならない
Goではbuild時にCのコードをgccなどを使ってコンパイルしている。
それをCGO_ENABLED
という環境変数で管理していて、build時にその環境にあったものを指定した時(例えば64bitのlinuxマシンでGOOS=linux GOARCH=amd64を指定する)に自動でCGO_ENABLED
を有効にしてくれる。
ただクロスコンパイル時は無効になるので明示してあげないといけなかった。
これはドキュメントにも記載されている
The cgo tool is enabled by default for native builds on systems where it is expected to work. It is disabled by default when cross-compiling. You can control this by setting the CGO_ENABLED environment variable when running the go tool: set it to 1 to enable the use of cgo, and to 0 to disable it. The go tool will set the build constraint "cgo" if cgo is enabled.
有効にするにはbuild時にCGO_ENABLED=1
を指定すれば有効になる。
$ GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build main.go $ GOOS=linux GOARCH=386 CGO_ENABLED=1 go build main.go $ GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go build main.go $ GOOS=darwin GOARCH=386 CGO_ENABLED=1 go build main.go
32bit用のパッケージをインストールしてビルドする
64bitのLinuxマシンではGOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build main.go
でビルドが出来るがGOOS=linux GOARCH=386 CGO_ENABLED=1 go build main.go
の時は次のようなエラーになってしまった。
/usr/bin/ld: cannot find -xxxxx
これは使用するCのパッケージが64bitのものはインストールされているが32bitのものがないというだけの問題だった。
ただ32bitマシンを用意するのかというとそれは面倒すぎるので、次の方法で32bit用のものを用意した。
$ dpkg --add-architecture i386 $ apt-get update -y $ apt-get install -y [package name]:i386
これで無事32, 64どちらでもビルド出来るようになった。
Macでもビルド出来るようにする
Macでビルドする時に-x
するとclang
を使ってビルドしているのでLinuxマシンでMac用にbuildする時はコンパイラはgccではなくてclang
を使いたかった。
コンパイラ自体はビルド時にCC=gcc
やCC=clang
のように変更は出来るが、32bitと64bitのMac向けにビルドする必要がある。
これに関してはMacOSのSDKをLinuxで使えるようにしたDocker公式で提供しているdockercore/golang-crossを使って32, 64ごとにビルド出来るようにした。
/osxcross/target/bin
内を見ると32bit用のclangのo32-clang
、64bit用のo64-clang
が入っているのでビルド時にそれぞれを指定してあげることでCをコンパイルしてくれる。
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 CC=o64-clang go build GOOS=darwin GOARCH=386 CGO_ENABLED=1 CC=o32-clang go build
最後に
無事コンパイル通った時は嬉しかった。。。