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

[インデックス 14094] ファイルの概要

このコミットは、Go言語のツールチェインにおけるcmd/goコマンドのビルドタグの扱いに関するバグ修正です。具体的には、標準コマンド(Goの配布に含まれるコマンド)に対してビルドタグが正しく適用されない問題を解決します。

コミット

commit 6cab8aa4e44c83be20a1b6cb1681a1bcbc43aa86
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Tue Oct 9 19:54:14 2012 +0400

    cmd/go: fix handling of build tags for standard commands
    Otherwise if I add '+build !race' to e.g. src/cmd/fix/reflect_test.go,
    it does not work.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6642044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/6cab8aa4e44c83be20a1b6cb1681a1bcbc43aa86

元コミット内容

src/cmd/go/pkg.go ファイルにおいて、build.ImportDir の呼び出しが buildContext.ImportDir に変更されています。

--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -602,7 +602,7 @@ func loadPackage(arg string, stk *importStack) *Package {
 		}
 		stk.push(arg)
 		defer stk.pop()
-		bp, err := build.ImportDir(filepath.Join(gorootSrc, arg), 0)
+		bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)
 		bp.ImportPath = arg
 		bp.Goroot = true
 		bp.BinDir = gorootBin
@@ -630,7 +630,7 @@ func loadPackage(arg string, stk *importStack) *Package {
 	// referring to io/ioutil rather than a hypothetical import of
 	// "./ioutil".
 	if build.IsLocalImport(arg) {
-		bp, _ := build.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
+		bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
 		if bp.ImportPath != "" && bp.ImportPath != "." {
 			arg = bp.ImportPath
 		}

変更の背景

このコミットの背景には、Go言語のビルドシステムにおけるビルドタグの処理の不備がありました。コミットメッセージに記載されているように、src/cmd/fix/reflect_test.go のような標準コマンドのソースファイルに +build !race のようなビルドタグを追加しても、それが正しく認識されず、期待通りにビルドから除外されない問題が発生していました。

Goのビルドタグは、特定の環境や条件に基づいてファイルのコンパイルを制御するための強力なメカニズムです。しかし、cmd/go ツールが内部的にパッケージをロードする際に、このビルドタグの考慮が不十分であったため、標準コマンドのビルドプロセスにおいて意図しないファイルが含まれてしまう可能性がありました。この修正は、このビルドタグの処理を改善し、Goツールチェインの堅牢性を高めることを目的としています。

前提知識の解説

Goのビルドタグ (Build Tags)

Goのビルドタグは、ソースファイルの先頭に特定のコメント形式で記述することで、そのファイルを特定のビルド条件でのみコンパイル対象とするための仕組みです。 形式は // +build tagname または // +build tag1,tag2 のようになります。複数のタグをスペースで区切るとAND条件、カンマで区切るとOR条件になります。 例えば、// +build linux,amd64 はLinuxかつAMD64アーキテクチャの場合にのみコンパイルされ、// +build debugdebugタグが有効な場合にのみコンパイルされます。 ビルドタグは、異なるOS、アーキテクチャ、またはカスタムのビルド設定(例: race検出器の有効/無効)に応じてコードを切り替える際に非常に有用です。

go/build パッケージ

go/build パッケージは、Goのソースコードを解析し、パッケージの依存関係、ビルドタグ、ファイルセットなどを特定するための機能を提供します。Goツールチェインの go buildgo install などのコマンドは、このパッケージの機能を利用して、どのファイルをコンパイルすべきかを決定します。

  • build.ImportDir(dir string, mode build.ImportMode): この関数は、指定されたディレクトリ内のGoパッケージをインポートし、そのパッケージに関する情報(ソースファイル、依存関係など)を返します。mode引数によって、インポートの挙動を制御できます。 しかし、この関数は、呼び出し元のGoプログラムのビルドコンテキスト(つまり、go/buildパッケージが初期化された際のデフォルトのビルドタグや環境設定)を使用します。

  • build.Context 構造体: go/build パッケージには Context 構造体が存在します。この構造体は、Goのビルド環境に関するすべての情報(GOOS, GOARCH, GOROOT, GOPATH, ビルドタグなど)をカプセル化します。 build.Default は、現在の環境のデフォルト設定を持つ build.Context のインスタンスです。

  • buildContext.ImportDir(dir string, mode build.ImportMode): このコミットで導入された(または既存の)buildContext は、おそらく build.Context 型の変数であり、特定のビルド設定(この場合は cmd/go ツールが使用すべきビルドタグを含む設定)を持つものです。 buildContext.ImportDir を使用することで、build.ImportDir がデフォルトのコンテキストを使用するのに対し、明示的に指定された build.Context の設定(特にビルドタグ)を考慮してパッケージをインポートできるようになります。

技術的詳細

この修正の核心は、build.ImportDir の代わりに buildContext.ImportDir を使用することです。

元のコードでは、build.ImportDir が直接呼び出されていました。build.ImportDir は、go/build パッケージが提供するグローバルなデフォルトビルドコンテキスト(build.Default)を使用してパッケージを解析します。このデフォルトコンテキストは、cmd/go ツールが起動された時点の環境変数(GOOS, GOARCHなど)に基づいて初期化されますが、特定のビルドタグの有効/無効を動的に制御する機能が不足していました。

問題は、cmd/go ツールが、例えば go testgo install のようなサブコマンドを実行する際に、そのサブコマンドが特定のビルドタグ(例: race タグ)を考慮してファイルをロードする必要がある場合です。build.ImportDir は、これらのサブコマンドが要求するビルドタグを適切に伝達・適用できないため、+build !race のようなタグが付いたファイルが誤って含まれてしまうことがありました。

修正後のコードでは、buildContext という変数(これは build.Context 型のインスタンスであると推測されます)が使用されています。この buildContext は、cmd/go ツールが現在の操作(例えば、テストの実行や特定のパッケージのビルド)に必要なビルドタグやその他のビルド設定を適切に設定した上で、ImportDir メソッドを呼び出すことを可能にします。

これにより、cmd/go は、標準コマンドのソースファイルを解析する際に、そのコマンドが意図するビルドタグ(例: race検出器を無効にする !race タグ)を正確に考慮できるようになり、ビルドタグによって除外されるべきファイルが正しくスキップされるようになります。

コアとなるコードの変更箇所

変更は src/cmd/go/pkg.go ファイルの2箇所です。

  1. 602行目:

    • 変更前: bp, err := build.ImportDir(filepath.Join(gorootSrc, arg), 0)
    • 変更後: bp, err := buildContext.ImportDir(filepath.Join(gorootSrc, arg), 0)

    この箇所は、Goの標準ライブラリやGo自身のソースコード(gorootSrc)内のパッケージをロードする際に使用されます。

  2. 630行目:

    • 変更前: bp, _ := build.ImportDir(filepath.Join(cwd, arg), build.FindOnly)
    • 変更後: bp, _ := buildContext.ImportDir(filepath.Join(cwd, arg), build.FindOnly)

    この箇所は、カレントワーキングディレクトリ(cwd)からの相対パスで指定されたローカルパッケージをロードする際に使用されます。build.FindOnly モードは、パッケージのパスを見つけるだけで、完全な解析は行わないことを示します。

コアとなるコードの解説

このコミットの目的は、cmd/go ツールがパッケージをロードする際に、より柔軟かつ正確なビルドコンテキスト(特にビルドタグ)を適用できるようにすることです。

build.ImportDir は、go/build パッケージのデフォルトのビルドコンテキストを使用します。これは、go コマンドが起動された際の環境設定に依存します。しかし、cmd/go の内部処理では、特定のサブコマンド(例: go test -race)に応じて、異なるビルドタグのセットを適用してパッケージを解析する必要があります。

buildContext は、おそらく cmd/go ツールが内部で管理している build.Context 型の変数であり、現在の操作に必要なビルドタグ(例: race タグの有効/無効)が適切に設定されています。buildContext.ImportDir を呼び出すことで、go/build パッケージは、このカスタムのビルドコンテキストに基づいてパッケージを解析し、ビルドタグの条件に合致するファイルのみを対象とすることができます。

これにより、+build !race のようなタグが付いたテストファイルが、race検出器が有効なビルド時にはスキップされ、無効なビルド時には含まれるといった、期待通りの挙動が実現されます。この変更は、Goツールチェインのビルドタグ処理の正確性と信頼性を向上させる上で重要な役割を果たします。

関連リンク

参考にした情報源リンク