去る2017年2月16日にGo言語のメジャーバージョンアップであるGo 1.8がリリースされました (リリースノート)。 大きな新機能や特徴はリリースノートを読んでいただくとして、ここでは個人的に長年の懸案事項であったNetBSD/armで使用することについての2017年3月9日現在の状況を記しています。
なお、例によって個人の勝手な思い込みで書いている部分が多数あり、正確な表現ではなかったり、根本的に勘違いで間違っている部分もあるかもしれません。 もしも何かの参考にこの文書を利用しようなんて奇特な方がいましたらぜひとも自身で確認し、自分なりの認識の上で使用してください。
まず最初に現在の動作状況をまとめておきます。
ここではNetBSD/arm環境をターゲットにしたバイナリを(OSやCPUが異なる)他の環境でクロスビルドする方法を示します。これには以下のような前提条件があります。
この前提条件が満たされるのであれば、作成したいプログラムのビルド時に以下の様に環境変数を設定することでNetBSD/earm用の実行ファイルを作成することができます。
$ GOOS=netbsd GOARCH=arm GOARM=6 go build (ターゲットソース)
$ GOOS=netbsd GOARCH=arm GOARM=7 go build (ターゲットソース)
もちろん複雑なソース構造で単純なコンパイルでは済まない場合もあるでしょうが、基本的には環境変数を指定するだけでクロスでバイナリを作成できます。
- 注1:
- Go 1.7までも同様にGOOS=netbsd GOARCH=armを指定してgo buildすることでNetBSD/arm用のバイナリを出力できましたが、これはNetBSD/arm上で正常に動作しないバイナリが生成されます。Abort trapで実行開始できなかったり、SIGKILL以外受け付けないハングアッププロセスとなったり、最悪カーネルが無応答になったりします(カーネル無応答はNetBSD側に原因があると思いますが)
Goの開発環境(goコマンドやライブラリ等)はWindowsやLinuxの各種Arch, OS X(x86 64bit), それにFreeBSDのamd64/i386用にはオフィシャルのバイナリが提供されていますが当然NetBSD用はありませんのでソースから構築する必要があります。 一方、Goは1.5以降、基本的にすべてGoで記述されているため、Goコンパイラがなければ構築できません。標準手順ではGo 1.4のバイナリを使用するようです(Go 1.4はC言語で書かれていたのでGoコンパイラがなくても構築できました)。が、当然NetBSD/armにはGo 1.4バイナリなんかありません。Go 1.4をNetBSD/armに移植するという手段もありますが(注2)、通常はクロス環境でGo自身を構築します。
NetBSD/arm上で動作するGo自身のビルド環境に必要な前提条件は以下です。
条件が満たされたなら、次の様にクロスビルド用のbootstrap.bashを実行します。
$ cd /where/to/workdir/go/src (NetBSD/earmv6hf用バイナリを作成する場合は以下) $ GOROOT_BOOTSTRAP=/usr/pkg/go14 GOOS=netbsd GOARCH=ARM GOARM=6 ./bootstrap.bash (NetBSD/earmv7hf用バイナリを作成する場合は以下) $ GOROOT_BOOTSTRAP=/usr/pkg/go14 GOOS=netbsd GOARCH=ARM GOARM=7 ./bootstrap.bash
上記ではGo 1.8のビルドに使用するGo言語が/usr/pkg/go14に存在する場合です。/usr/local/go等、環境に合わせて指定します。また、最終的なターゲット環境のインストールディレクトリが決まっているのであれば、以下の様にGOROOT_FINALを指定しておくといいかもしれません。
$ GOROOT_BOOTSTRAP=/usr/pkg/go14 GOROOT_FINAL=/usr/local/go GOOS=netbsd GOARCH=ARM GOARM=7 ./bootstrap.bash
なお、v6hf用とv7hf用のバイナリは同時に作成することはできません。また、作成したv6hf用のバイナリはv7hfの「マルチCPU/マルチコア]環境では使用できません(シングルCPU環境では使用可能)。もちろんv7hf用バイナリはv6なCPUでは実行できません。ターゲットのCPU環境に合わせて選択します。
無事にビルドが終了すると、goディレクトリと同じ階層に1つのディレクトリと、それをアーカイブしたtar ballが作成されています。
$ cd /where/to/workdir $ ls -F go/ go-netbsd-arm-bootstrap/ go-netbsd-arm-bootstrap.tbz
go-netbsd-arm-bootstrapディレクトリにターゲット用のバイナリ一式があり、それをアーカイブしたものがgo-netbsd-arm-bootstrap.tbzとなります。
なお、このディレクトリ名やファイル名はbootstrap.bashで$GOOS/$GOARCHからのみ作成されるようになっているため、GOARMの6と7を同時に作ることができません。両方を作成するには、スクリプトを変更するか、1つづつ作成して手動で移動させなければなりません。
作成したgo-netbsd-arm-bootstrap.tbzを、ターゲットであるNetBSD/earm環境に何らかの方法でコピーし、適当なディレクトリに展開、適切にGOROOTやPATHを設定することで、セルフ開発環境が構築できます。
rpi2$ uname -srpmp NetBSD 7.1_RC2 evbarm earmv7hf rpi2$ cd /home/user rpi2$ /&tar zxpf go-netbsd-arm-bootstrap.tbz rpi2$ mv go-netbsd-arm-bootstrap golang rpi2$ export GOROOT=/home/user/golang PATH=$PATH:/home/user/golang/bin rpi2$ go version go version go1.8 netbsd/arm rpi2$ file golang/bin/go golang/bin/go: ELF 32-bit LSB executable, ARM, EABI5 version 1 (NetBSD), statically linked, for NetBSD 5.99, not stripped
これでNetBSD/arm用のGo開発環境が作成できました。
現状では実行環境やその動作にいくつか制限があります。
runtime: this system has multiple CPUs and must use atomic synchronization instructions. Recompile using GOARM=7.その一方、同じくARMv7 CPUであるnetwalkerはシングルコアのため動作させることができます。 この制限はGo開発環境(goコマンド)そのものも同じで、ARMv6用のGo開発環境はマルチコア/SMPのARMv7環境では動作しません。 これはおそらくFreeBSD/armでも同様だと思います。
残念ながらまだ問題点、動作不良が残っています。とりあえず分かっている範囲で。
いくつかの制限やまだ問題はあるもののGo 1.8の正式リリース版を使うことでとにもかくにもNetBSD/armのうちearmv6hfとearmv7hf上でGo環境が動くようになりました。これまで動作するように独自にパッチを作ったりしていましたが、主要な部分が本家とほぼ同等のコードとなったため、ようやくスタートラインに立った状態と言えます。
個人的に制限項目を解決したり緩和するものを含め、いくつかの変更を加えた独自変更版を作っています。
ソースはGithubに登録してあります。go1.4-netbsd branchなら独自変更版のGo 1.4, go1.8-netbsdならGo 1.8ブランチの独自変更版となります。netbsdブランチは一応Masterの開発版です。気の向いたときに本家に追従してますが、更新頻度はあんまり高くありません。
もうほとんど本家と差はありません。説明が難しいところもありますが、いくつかは本家に入れてもらえるように報告していくつもり。
NetBSDではサードパーティアプリケーションはpkgsrc化するのが好ましいのですが、Go1.8でNetBSD/earm用にセルフ開発環境を用意できるようになったとはいえ、標準ではGo 1.4が必要かつGo 1.4はNetBSD/arm用は正式には作れません。現在のpkgsrcはセルフコンパイルが前提であり、ビルド途中で実行ホストのarchを切り替えてクロスコンパイルさせるような荒技はありません。
このため、現状および今後のGoのバージョンをpkgsrcで対応するには2つの方法が考えられます。
いずれにせよ、pkgsrcとはあまり相性は良くなさそうです。そもそもARMターゲットでセルフビルドってそんなに普通なのかは私にはわかりません。
一応現状のpkgsrcツリーに組み込んだものをGitHubに置いてあります(更新頻度はgolang本体よりも低くなってます)。