Skip to content

Goツールチェーンのビルドステージ

Plan 9で最初からGoをビルドするでも少し見たが、Go 1.10でcontent-aware build cacheが導入されて、ビルドログの出力がステージを表現するように変更された。

Terminal window
% ./make.rc
Building Go cmd/dist using /usr/glenda/go1.22. (go1.22.12 plan9/amd64)
Building Go toolchain1 using /usr/glenda/go1.22.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 using go_bootstrap and Go toolchain2.
Building packages and commands for plan9/amd64.
Packaging archives for plan9/amd64.

GOROOT_BOOTSTRAP によって参照される以前のツールチェーンで cmd/dist をビルドする。dist コマンドはGoツールチェーンのビルドやテストを総括するためのコマンド群で、ビルドプロセスが完了すれば削除される。

GOROOT_BOOTSTRAP に利用可能な最小バージョンはGoツールチェーンをブートストラップ可能な最小バージョンの条件に書いた。

GOROOT_BOOTSTRAP によって参照される以前のツールチェーンと go コマンドで、ターゲットバージョンのツールチェーンをビルドする。ツールチェーンが具体的に何を意味するのかはGoツールチェーンの定義に書いたが、dist/build.goのコメントによれば cmd 以下のアセンブラ、リンカ等をツールチェーンと扱うらしい。

// To recap, so far we have built the new toolchain
// (cmd/asm, cmd/cgo, cmd/compile, cmd/link, cmd/preprofile)
// using the Go bootstrap toolchain and go command.

toolchain1 をビルドするとき、GOROOT_BOOTSTRAP によって参照されるコンパイラはターゲットよりも以前のバージョンなので、ターゲットをビルドしたときに生成されるコードや最適化の程度は、以前のバージョンにどれを使うかで結果が変わる。極端な例ではバイナリのフォーマットやABIが異なる場合もあるかもしれない。

toolchain1 = mk(new toolchain, go1.17 toolchain, go1.17 cmd/go)

toolchain1cmd/dist でターゲットバージョンの go コマンド(go_bootstrap)をビルドする1。おそらくだが、go_bootstraptoolchain1 でビルドしたライブラリを静的リンクする。なので、フォーマットや最適化状況などは GOROOT_BOOTSTRAP に依存するものの、バグがなければ動作としてはターゲットと同一になる。

go_bootstrap = mk(new cmd/go, toolchain1, cmd/dist)

コメントによると、toolchain1cmd/go を使っていてビルドIDが無いので再ビルドが必要とあった。

toolchain1go_bootstrap でターゲットのソースコードを改めてビルドする。この時点で、toolchain1 とビルドターゲットが同じバージョンで揃うので、toolchain1 をビルドしたGoのバージョンが何であれ同じバイナリが作られる。このときソースコードの解釈は toolchain1 と全く同じになるが、新しいバージョンでビルドするため生成されるバイナリは異なる。

toolchain2 = mk(new toolchain, toolchain1, go_bootstrap)

toolchain2go_bootstrap でターゲットのソースコードを改めてビルドする。

toolchain3 = mk(new toolchain, toolchain2, go_bootstrap)

a

Go 1.25のソースコードをGo 1.22でビルドした場合、

ステージコンパイラツールチェーンソースコード出力フォーマット
cmd/distGo 1.22Go 1.22Go 1.22と解釈Go 1.22相当
toolchain1Go 1.22Go 1.22Go 1.22と解釈Go 1.22相当
go_bootstrapcmd/disttoolchain1Go 1.25と解釈Go 1.25相当
toolchain2go_bootstraptoolchain1Go 1.25と解釈Go 1.25相当
toolchain3go_bootstraptoolchain2Go 1.25と解釈Go 1.25相当

toolchain1 はコンパイラもツールチェーンも古いものが使われる。toolchain2 の時点では、go_bootstraptoolchain2 が出力するバイナリは新しいものになっているのだが、toolchain2 のビルドに使われた toolchain1 が古いバージョンでビルドされている。なので最後に全て新しいバージョンでビルドした toolchain3 がある。

  1. ここでGoコンパイラはどれが使われるんだろう、cmd/dist がそれ?