[インデックス 10894] ファイルの概要
コミット
コミットハッシュ: a1198fcc034747f4a423a0ba7af626f7339fb535
作成者: Russ Cox rsc@golang.org
日付: 2011年12月20日 10:28:04 -0500
メッセージ: go: build runtime
レビュー: R=golang-dev, r, adg
コードレビューURL: https://golang.org/cl/5495068
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a1198fcc034747f4a423a0ba7af626f7339fb535
元コミット内容
このコミットは、Go言語の go
コマンドにおけるビルドシステムの重要な改善を行いました。主な変更点は以下の通りです:
- 6つのファイルが変更: 85行の追加、23行の削除
- 変更されたファイル:
src/cmd/go/build.go
(主要な変更)src/cmd/go/list.go
src/cmd/go/main.go
src/cmd/go/pkg.go
src/pkg/go/build/build_test.go
src/pkg/go/build/dir.go
変更の背景
2011年当時、Go言語はまだ1.0リリース前(2012年3月リリース)の開発段階にありました。この時期のGoコンパイラは、Plan 9由来のCベースのツールチェーンを使用していました。具体的には:
- 6g: amd64アーキテクチャ用のGoコンパイラ
- 6a: amd64アーキテクチャ用のアセンブラ
- 6c: amd64アーキテクチャ用のCコンパイラ
- 6l: amd64アーキテクチャ用のリンカ
このコミットは、Go言語の標準ライブラリの中核である runtime
パッケージのビルドを可能にするための重要な変更でした。runtime
パッケージは、ガベージコレクション、ゴルーチン、リフレクションなどの低レベル機能を提供するため、特別なコンパイル処理が必要でした。
前提知識の解説
Go言語のビルドシステム(2011年当時)
2011年のGo言語は、現在とは大きく異なるビルドシステムを使用していました:
-
アーキテクチャ固有のツール: 各アーキテクチャ(386、amd64、arm)に対して、異なる番号プレフィックスを持つツールセットがありました
- 数字の意味: 5(arm)、6(amd64)、8(386)
- 文字の意味: g(Goコンパイラ)、a(アセンブラ)、c(Cコンパイラ)、l(リンカ)
-
C言語による実装: コンパイラ自体がC言語で書かれており、Plan 9のコンパイラを基にしていました
-
環境変数の重要性:
GOOS
とGOARCH
環境変数がビルドターゲットを決定していました
リフレクションとランタイム情報
Go言語のリフレクション機能は、ランタイムに型情報を必要とします。この型情報は:
- 低レベル型情報:
runtime
パッケージが提供 - 高レベルインターフェース:
reflect
パッケージが提供 - コンパイル時生成: 特別なコンパイラフラグ(
-+
)により追加の型データを生成
技術的詳細
1. runtimeパッケージの特別扱い
コミットの最も重要な変更は、runtime
パッケージを特別なケースとして扱うことでした:
// Before: runtime was excluded from building
case "runtime", "runtime/cgo":
// Too complex - can't build.
a.f = (*builder).nop
return a
// After: only runtime/cgo is excluded
case "runtime/cgo":
// Too complex - can't build.
a.f = (*builder).nop
return a
2. 特別なコンパイラフラグの導入
runtime
パッケージのコンパイル時に、特別なフラグ -+
を追加:
gcargs := []string{"-p", a.p.ImportPath}
if a.p.Standard && a.p.ImportPath == "runtime" {
// runtime compiles with a special 6g flag to emit
// additional reflect type data.
gcargs = append(gcargs, "-+")
}
この -+
フラグは「runtimeをコンパイル中」を意味し、リフレクションに必要な追加の型データを生成します。
3. ヘッダファイルの処理改善
プラットフォーム固有のヘッダファイルを標準化された名前にコピーする機能を追加:
// copy .h files named for goos or goarch or goos_goarch
// to names using GOOS and GOARCH.
// For example, defs_linux_amd64.h becomes defs_GOOS_GOARCH.h.
4. アセンブラとCコンパイラの改善
プラットフォーム固有のマクロ定義を自動的に追加:
// アセンブラ用
return b.run(dir, b.arch+"a", "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, sfile)
// Cコンパイラ用
return b.run(dir, b.arch+"c", "-FVw", "-I", inc, "-o", ofile, "-DGOOS_"+b.goos, "-DGOARCH_"+b.goarch, cfile)
5. .Sファイル(GCC用アセンブリ)のサポート
cgoを使用する場合のみ、大文字の .S
ファイルを処理するように改善:
// add the .S files only if we are using cgo
// (which means gcc will compile them).
// The standard assemblers expect .s files.
if len(di.CgoFiles) > 0 {
di.SFiles = append(di.SFiles, Sfiles...)
sort.Strings(di.SFiles)
}
コアとなるコードの変更箇所
1. builder構造体の拡張(build.go:27-28)
type builder struct {
// ... existing fields ...
goarch string // the $GOARCH
goos string // the $GOOS
// ... rest of fields ...
}
2. 初期化処理の改善(build.go:36-37)
b.goarch = build.DefaultContext.GOARCH
b.goos = build.DefaultContext.GOOS
3. Package構造体へのHFilesフィールド追加(pkg.go:199)
type Package struct {
// ... existing fields ...
HFiles []string // .h source files
// ... rest of fields ...
}
4. DirInfo構造体の拡張(dir.go:231)
type DirInfo struct {
// ... existing fields ...
HFiles []string // .h files in dir
// ... rest of fields ...
}
コアとなるコードの解説
builderの初期化処理
func (b *builder) init(aflag, nflag, vflag bool) {
// ... existing initialization ...
b.goarch = build.DefaultContext.GOARCH
b.goos = build.DefaultContext.GOOS
b.arch, err = build.ArchChar(b.goarch)
if err != nil {
fatalf("%s", err)
}
}
この変更により、ビルダーは現在のターゲットプラットフォームの情報を適切に保持し、コンパイラやアセンブラの呼び出し時に適切なフラグを渡せるようになりました。
gcメソッドの改善
func (b *builder) gc(dir, ofile string, gcargs, importArgs []string, gofiles []string) error {
args := []string{b.arch + "g", "-o", ofile}
args = append(args, gcargs...)
args = append(args, importArgs...)
args = append(args, gofiles...)
return b.run(dir, args...)
}
この変更により、コンパイラに渡すフラグをより柔軟に制御できるようになり、runtime
パッケージに必要な特別なフラグ -+
を適切に渡せるようになりました。
main.goでのruntimeディレクトリ処理の削除
// Before: Complex logic to skip runtime subdirectories
if strings.HasPrefix(path, runtime) {
switch path {
case runtime + "darwin", runtime + "freebsd", runtime + "linux", runtime + "netbsd", runtime + "openbsd", runtime + "windows":
return filepath.SkipDir
}
}
// After: This entire block was removed
この変更により、runtime
パッケージの様々なプラットフォーム固有のサブディレクトリが適切にスキャンされるようになりました。
関連リンク
- Go 1.5 Release Notes - 旧ツールチェーンから新ツールチェーンへの移行について
- The Laws of Reflection - 2011年に書かれたGoのリフレクション解説
- Go Programming Language FAQ - Goの設計思想と歴史
- Go Compiler Overhaul Proposal - CからGoへのコンパイラ移行計画