[インデックス 12416] ファイルの概要
このコミットは、Go言語のビルドツールであるgo
コマンドに、使用するコンパイラを指定するための-compiler
フラグを追加し、それに伴いgo/build
パッケージにContext.Compiler
フィールドを導入する変更です。これにより、gc
(標準Goコンパイラ)とgccgo
(GCCベースのGoコンパイラ)の切り替えがより柔軟に行えるようになります。
コミット
commit 347cc981f043193dc9b29e92b485b158aa6c85f8
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 6 00:36:24 2012 -0500
cmd/go: add -compiler
go/build: add Context.Compiler
Fixes #3157.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5756047
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/347cc981f043193dc9b29e92b485b158aa6c85f8
元コミット内容
cmd/go: add -compiler
go/build: add Context.Compiler
Fixes #3157.
変更の背景
Go言語の初期のビルドシステムでは、コンパイラの選択が環境変数GC
に依存していました。具体的には、GC=gccgo
を設定することでgccgo
コンパイラを使用し、それ以外の場合はデフォルトのgc
コンパイラが使用されていました。しかし、このような環境変数による制御は、ビルドの柔軟性やコマンドラインからの直接的な制御の点で限界がありました。
このコミットは、Goのビルドプロセスにおいて、より明示的かつコマンドラインから直接コンパイラを指定できるようにすることを目的としています。これにより、ユーザーはgo build
やgo install
などのコマンド実行時に、-compiler
フラグを使ってgc
またはgccgo
を簡単に切り替えられるようになります。これは、異なるコンパイラでのテストや、特定のコンパイラに依存するビルド環境での作業において、開発者の利便性を向上させます。
コミットメッセージにあるFixes #3157
は、この変更がGoプロジェクトのIssue 3157を解決することを示唆しています。このIssueは、Goツールチェーンにおけるコンパイラ選択の柔軟性に関する議論や要望であったと推測されます。
前提知識の解説
Go言語のビルドシステム
Go言語のビルドシステムは、ソースコードをコンパイルし、実行可能なバイナリやライブラリを生成する一連のツールとプロセスを指します。主要なツールはgo
コマンドであり、go build
、go install
、go test
などのサブコマンドを通じて、コンパイル、リンク、テストなどの操作を行います。
Goコンパイラ(gc)
gc
は、Go言語の公式かつデフォルトのコンパイラです。Go言語のソースコードを機械語に変換し、実行可能なバイナリを生成します。Go言語の進化に合わせて開発されており、Goのランタイムと密接に連携しています。
GCCベースのGoコンパイラ(gccgo)
gccgo
は、GCC(GNU Compiler Collection)をバックエンドとして使用するGo言語のコンパイラです。gc
とは異なる実装であり、GCCの最適化機能や、C/C++とのより深い連携(Cgoを介した既存のC/C++ライブラリとのリンクなど)を利用できる場合があります。gccgo
は、特に既存のC/C++プロジェクトとの統合や、特定のプラットフォームでのパフォーマンス要件がある場合に選択肢となり得ます。
Goのツールチェーン
Goのツールチェーンとは、Goプログラムの開発に必要な一連のツール(コンパイラ、リンカ、アセンブラ、パッケージマネージャなど)の集合体を指します。go
コマンドは、これらのツールを統合的に管理し、ビルドプロセスを自動化します。
go/build
パッケージ
go/build
パッケージは、Goのソースコードパッケージの構造を解析し、ビルドに必要な情報を取得するための標準ライブラリです。このパッケージは、Goのビルドシステムがソースファイルを特定し、依存関係を解決し、適切なコンパイラやツールチェーンのパスを決定するために使用されます。Context
構造体は、ビルド環境に関する情報(OS、アーキテクチャ、ビルドタグなど)を保持します。
技術的詳細
このコミットの技術的な核心は、Goのビルドシステムがコンパイラを動的に選択できるようにするためのメカニズムの導入です。
-
cmd/go
における-compiler
フラグの追加:src/cmd/go/build.go
において、go
コマンドのビルドフラグとして-compiler name
が追加されました。name
にはgc
またはgccgo
を指定できます。このフラグは、buildCompiler
というflag.Var
インターフェースを実装するカスタム型によって処理されます。Set
メソッドが呼び出されると、指定されたコンパイラ名に基づいてbuildToolchain
変数が適切なツールチェーン実装(gcToolchain
またはgccgcToolchain
)に設定され、同時にbuildContext.Compiler
も更新されます。 -
go/build
パッケージへのContext.Compiler
の追加:src/pkg/go/build/build.go
のContext
構造体にCompiler string
フィールドが追加されました。これは、ビルドコンテキストが現在どのコンパイラを使用しているかを追跡するためのものです。以前はGccgo bool
というブーリアンフラグでgccgo
の使用を判断していましたが、より汎用的なCompiler
文字列に置き換えられました。これにより、将来的に他のコンパイラが追加された場合でも、既存の構造体を拡張することなく対応できるようになります。 -
ツールチェーン抽象化の改善:
src/cmd/go/build.go
には、toolchain
インターフェースが定義されており、compiler()
、linker()
、gc()
、asm()
などのメソッドを通じて、各コンパイラ(gc
とgccgo
)固有のビルド操作を抽象化しています。このコミットでは、goToolchain
がgcToolchain
に、gccgoToolchain
がgccgcToolchain
にリネームされ、より明確な命名になりました。また、noToolchain
という新しい型が追加され、コンパイラが未設定の場合のエラーハンドリングが強化されました。 -
オブジェクトパス計算の変更:
src/pkg/go/build/build.go
のContext.Import
メソッド内で、パッケージのオブジェクトパス(.a
ファイルのパス)を計算するロジックがctxt.Gccgo
ブーリアンからctxt.Compiler
文字列に依存するように変更されました。これにより、gc
とgccgo
で異なるパス構造(例:pkg/gccgo/
vspkg/GOOS_GOARCH/
)が適切に処理されます。 -
testflag.go
の更新:src/cmd/go/testflag.go
では、テストコマンドに渡されるフラグの定義に-compiler
が追加され、テスト実行時にもコンパイラを指定できるようになりました。
これらの変更により、Goのビルドシステムは、コンパイラの選択に関してより柔軟で、将来の拡張性を持つ設計へと進化しました。
コアとなるコードの変更箇所
src/cmd/go/build.go
buildCompiler
というflag.Var
を実装する新しい型が追加され、-compiler
フラグの処理を担う。addBuildFlags
関数にcmd.Flag.Var(buildCompiler{}, "compiler", "")
が追加され、-compiler
フラグを登録。buildToolchain
の初期化ロジックが、環境変数GC
からbuild.Default.Compiler
の値に基づいて行われるように変更。action
メソッドやincludeArgs
メソッド内で、buildToolchain.(gccgoToolchain)
の型アサーションがbuildToolchain.(gccgcToolchain)
に修正。toolchain
インターフェースの実装として、noToolchain
、gcToolchain
、gccgcToolchain
が定義され、それぞれがcompiler()
,linker()
,gc()
,asm()
,pkgpath()
,pack()
,ld()
,cc()
などのメソッドを実装。特に、goToolchain
がgcToolchain
に、gccgoToolchain
がgccgcToolchain
にリネームされた。cgo
関数内で、buildToolchain.(gccgoToolchain)
の型アサーションがbuildToolchain.(gccgcToolchain)
に修正。
src/cmd/go/testflag.go
testFlagDefn
に{name: "compiler"}
が追加され、テストコマンドで-compiler
フラグが認識されるように。testFlags
関数内で、case "compiler": buildContext.Compiler = value
が追加され、テスト実行時のコンパイラ設定を反映。
src/pkg/go/build/build.go
Context
構造体からGccgo bool
フィールドが削除され、代わりにCompiler string
フィールドが追加。defaultContext()
関数で、c.Compiler = runtime.Compiler
が追加され、デフォルトのコンパイラが設定されるように。Context.Import
メソッド内で、パッケージのアーカイブファイル(.a
)のパスを決定するロジックがctxt.Gccgo
からctxt.Compiler
に依存するように変更。switch ctxt.Compiler
文が導入され、gc
とgccgo
で異なるパス生成ロジックが適用される。binaryOnly
の条件式にpkga != ""
が追加され、pkga
が空でない場合にのみバイナリのみのインポートが許可されるように。p.PkgObj
の設定がif pkga != ""
の条件付きになり、pkga
が空の場合は設定されないように。Context.Import
の戻り値で、pkgerr
が返されるように修正され、不明なコンパイラが指定された場合にエラーが伝播されるように。
コアとなるコードの解説
このコミットの最も重要な変更は、Goのビルドシステムがコンパイラを抽象化し、コマンドラインから選択できるようにした点です。
src/cmd/go/build.go
のbuildCompiler
型は、flag.Var
インターフェースを実装しています。これにより、go
コマンドは-compiler
フラグを受け取ることができます。Set
メソッドが呼び出されると、ユーザーが指定したコンパイラ名(例: "gc"や"gccgo")に基づいて、グローバル変数buildToolchain
が適切なツールチェーン実装(gcToolchain
またはgccgcToolchain
)に設定されます。同時に、go/build
パッケージのbuildContext.Compiler
フィールドも更新され、ビルドコンテキスト全体で選択されたコンパイラが認識されるようになります。
// src/cmd/go/build.go
type buildCompiler struct{}
func (c buildCompiler) Set(value string) error {
switch value {
case "gc":
buildToolchain = gcToolchain{}
case "gccgo":
buildToolchain = gccgcToolchain{}
default:
return fmt.Errorf("unknown compiler %q", value)
}
buildContext.Compiler = value
return nil
}
func (c buildCompiler) String() string {
return buildContext.Compiler
}
toolchain
インターフェースは、コンパイラ、リンカ、アセンブラなどの各ツールが提供すべき操作を定義しています。gcToolchain
とgccgcToolchain
はそれぞれこのインターフェースを実装し、各コンパイラ固有のコマンドや引数をラップしています。これにより、go
コマンドのビルドロジックは、具体的なコンパイラの実装に依存することなく、抽象化されたtoolchain
インターフェースを通じて操作を実行できます。
// src/cmd/go/build.go (抜粋)
type toolchain interface {
compiler() string
linker() string
gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error)
asm(b *builder, p *Package, obj, ofile, sfile string) error
pkgpath(basedir string, p *Package) string
pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
cc(b *builder, p *Package, objdir, ofile, cfile string) error
}
src/pkg/go/build/build.go
のContext
構造体へのCompiler
フィールドの追加は、ビルドプロセス全体でコンパイラの選択を伝播させるために重要です。特に、Context.Import
メソッドは、パッケージのインポートパスに基づいて、対応するアーカイブファイル(.a
)のパスを決定します。このパスはコンパイラによって異なる場合があるため、Compiler
フィールドの値に基づいて適切なパスが生成されるようにロジックが変更されました。
// src/pkg/go/build/build.go (抜粋)
type Context struct {
// ...
Compiler string // compiler to assume when computing target paths
// ...
}
func (ctxt *Context) Import(path string, src string, mode ImportMode) (*Package, error) {
// ...
var pkga string
var pkgerr error
switch ctxt.Compiler {
case "gccgo":
dir, elem := pathpkg.Split(p.ImportPath)
pkga = "pkg/gccgo/" + dir + "lib" + elem + ".a"
case "gc":
pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + p.ImportPath + ".a"
default:
// Save error for end of function.
pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
}
// ...
return p, pkgerr
}
これらの変更により、Goのビルドシステムは、コンパイラの選択をより柔軟に、かつ明示的に制御できるようになり、異なるコンパイラ環境での開発とテストが容易になりました。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Goコマンドのドキュメント: https://go.dev/cmd/go/
go/build
パッケージのドキュメント: https://pkg.go.dev/go/build
参考にした情報源リンク
- コミットハッシュ:
347cc981f043193dc9b29e92b485b158aa6c85f8
のGitHubページ: https://github.com/golang/go/commit/347cc981f043193dc9b29e92b485b158aa6c85f8 - Go言語のIssueトラッカー (Issue 3157に関する具体的な情報は見つかりませんでしたが、コミットメッセージから関連性を推測しました): https://github.com/golang/go/issues
- Go言語のビルドプロセスに関する一般的な知識
- GCCGoに関する情報 (例: https://gcc.gnu.org/onlinedocs/gccgo/)