Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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言語は、現在とは大きく異なるビルドシステムを使用していました:

  1. アーキテクチャ固有のツール: 各アーキテクチャ(386、amd64、arm)に対して、異なる番号プレフィックスを持つツールセットがありました

    • 数字の意味: 5(arm)、6(amd64)、8(386)
    • 文字の意味: g(Goコンパイラ)、a(アセンブラ)、c(Cコンパイラ)、l(リンカ)
  2. C言語による実装: コンパイラ自体がC言語で書かれており、Plan 9のコンパイラを基にしていました

  3. 環境変数の重要性: GOOSGOARCH環境変数がビルドターゲットを決定していました

リフレクションとランタイム情報

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 パッケージの様々なプラットフォーム固有のサブディレクトリが適切にスキャンされるようになりました。

関連リンク

参考にした情報源リンク