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

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

このコミットは、Go言語のビルドシステムにデータ競合検出機能を追加するための最初のステップです。具体的には、go コマンドに -race フラグを導入し、データ競合検出を有効にするためのビルドシステム側の変更を行っています。

コミット

commit 8ed026e783ded812ee4bd03a47278f95168b9087
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Tue Sep 18 23:47:15 2012 +0400

    race: build system changes
    This is the first part of a bigger change that adds data race detection feature:
    https://golang.org/cl/6456044
    Adds -race flag to go command.
    API change:
    +pkg go/build, type Context struct, InstallTag string

    R=rsc
    CC=golang-dev
    https://golang.org/cl/6488075

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

https://github.com/golang/go/commit/8ed026e783ded812ee4bd03a47278f95168b9087

元コミット内容

このコミットの元の内容は、Go言語のビルドシステムにデータ競合検出機能を追加するための基盤となる変更です。主な目的は、go コマンドに -race フラグを追加し、このフラグが指定された際にデータ競合検出が有効になるようにビルドプロセスを調整することです。また、go/build パッケージの Context 構造体に InstallTag フィールドが追加され、ビルド成果物のインストールパスにタグを付与できるようになっています。これは、-race ビルドと通常のビルドの成果物を区別するために利用されます。

変更の背景

この変更の背景には、並行プログラミングにおける最も厄介なバグの一つである「データ競合(Data Race)」を開発者が容易に検出できるようにするという強い要望がありました。データ競合は、複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが同期メカニズムによって保護されていない場合に発生します。このような競合は、プログラムの非決定的な動作やクラッシュを引き起こす可能性があり、デバッグが非常に困難です。

Go言語は並行処理を言語レベルでサポートしているため、データ競合の発生リスクも高まります。そのため、Go開発チームは、コンパイル時または実行時にデータ競合を検出するツールを提供することの重要性を認識していました。このコミットは、そのための大規模な取り組みの第一歩であり、go コマンドに統合されたデータ競合検出機能(Race Detector)の導入に向けたビルドシステム側の準備を行っています。

前提知識の解説

データ競合 (Data Race)

データ競合は、並行プログラミングにおいて発生する特定の種類のバグです。以下の3つの条件がすべて満たされたときに発生します。

  1. 複数のゴルーチン(またはスレッド)が同時に同じメモリ位置にアクセスする。
  2. 少なくとも1つのアクセスが書き込み操作である。
  3. それらのアクセスが同期メカニズム(ミューテックス、チャネルなど)によって保護されていない。

データ競合が発生すると、プログラムの実行結果が非決定的になり、予測不能な動作、データの破損、クラッシュなどにつながる可能性があります。これは、異なるゴルーチンがメモリにアクセスする順序が実行ごとに変わり得るためです。

Go Race Detector

Go言語のRace Detectorは、実行時にデータ競合を検出するためのツールです。プログラムを特殊な方法でコンパイルし、実行時にメモリアクセスを監視することで、データ競合のパターンを特定します。検出された競合は、ファイル名、行番号、スタックトレースなどの詳細情報とともに報告されます。

Race Detectorは、プログラムの実行速度を低下させる(通常5〜10倍)ため、本番環境での常時使用には適していません。しかし、開発中やテスト中に使用することで、見つけにくい並行処理のバグを効率的に特定できます。

go コマンドとビルドプロセス

go コマンドは、Go言語のソースコードのコンパイル、テスト、実行、パッケージ管理などを行うための主要なツールです。go buildgo installgo rungo test などのサブコマンドがあり、それぞれ異なるビルドフェーズや実行フェーズを担当します。

このコミットでは、これらのサブコマンドが共通して利用するビルドシステムの設定に、-race フラグを処理するロジックを追加しています。

go/build パッケージ

go/build パッケージは、Goのソースコードパッケージの構造を解析し、ビルドに必要な情報を取得するための標準ライブラリです。Context 構造体は、ビルド環境に関する情報(OS、アーキテクチャ、GOPATH、ビルドタグなど)をカプセル化します。このコミットでは、Context 構造体に InstallTag フィールドが追加され、ビルド成果物のインストールパスに影響を与えるようになります。

技術的詳細

このコミットの技術的な変更は、主に以下の点に集約されます。

  1. -race フラグの導入:
    • src/cmd/go/build.gosrc/cmd/go/run.gosrc/cmd/go/test.goraceInit() 関数が追加され、go build, go install, go run, go test コマンドの実行時に呼び出されます。
    • raceInit() 関数は、-race フラグが指定された場合に、現在のOS/アーキテクチャが linux/amd64 または darwin/amd64 であるかをチェックします。これら以外の環境ではエラーを出力し終了します。
    • -race フラグが有効な場合、コンパイラフラグ (buildGcflags)、リンカフラグ (buildLdflags)、Cgoコンパイラフラグ (buildCcflags) にそれぞれ -b-b-DRACE が追加されます。これらはRace Detectorを有効にするための特別なフラグです。
    • buildContext.InstallTag"race" に設定され、buildContext.BuildTags"race" タグが追加されます。これにより、Race Detectorが有効なビルドと通常のビルドの成果物が異なるディレクトリにインストールされるようになります(例: pkg/linux_amd64_race/)。
  2. go/build.Context 構造体への InstallTag フィールド追加:
    • src/pkg/go/build/build.gogo/build.Context 構造体に InstallTag string フィールドが追加されました。
    • この InstallTag は、ビルド成果物(.a ファイルなど)のインストールパスを決定する際に使用されます。具体的には、pkg/GOOS_GOARCH/ の後に _InstallTag が追加される形式になります(例: pkg/linux_amd64_race/)。これにより、Race Detectorを有効にしたビルドとそうでないビルドの成果物が衝突するのを防ぎます。
  3. runtime/race パッケージの依存関係の追加:
    • src/cmd/go/pkg.go において、-race フラグが有効な場合、すべてのパッケージが runtime/race パッケージに依存するように変更されました。ただし、runtime/race 自体、runtime/cgocmd/cgo は循環依存を避けるために除外されます。
  4. Cgoのビルドロジックの調整:
    • src/cmd/go/build.gobuilder.action メソッド内で、cgo のビルド時に buildRacetrue の場合、cgo バイナリのオーバーライトを防ぐための条件が追加されました。
    • runtime/race または runtime/cgo パッケージのCgoビルドにおいて、-import_syscall=false フラグが追加されました。これは、これらのパッケージがRace Detectorの内部実装やCgoの低レベルな部分に関わるため、特定のシンボル解決を避けるための措置と考えられます。

これらの変更により、go コマンドは -race フラグを認識し、Race Detectorを有効にするための適切なコンパイラ・リンカフラグを設定し、ビルド成果物のパスを分離するようになります。

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

このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。

  • src/cmd/go/build.go:
    • buildRace グローバル変数の追加。
    • addBuildFlags 関数での -race フラグの登録。
    • runBuild, runInstall 関数での raceInit() の呼び出し。
    • builder.action 関数での cgo 関連の条件分岐に !buildRace の追加。
    • raceInit() 関数の追加。この関数が -race フラグが有効な場合の主要な設定(OS/アーキテクチャチェック、コンパイラ/リンカフラグの追加、InstallTagBuildTags の設定)を行います。
  • src/cmd/go/pkg.go:
    • Package.load メソッド内で、buildRace が有効な場合に runtime/race を依存関係に追加するロジック。
  • src/cmd/go/run.go:
    • runRun 関数での raceInit() の呼び出し。
  • src/cmd/go/test.go:
    • runTest 関数での raceInit() の呼び出し。
  • src/cmd/go/testflag.go:
    • testFlagDefn-race フラグの定義を追加し、testFlags 関数でその処理を可能にする。
  • src/pkg/go/build/build.go:
    • Context 構造体に InstallTag string フィールドを追加。
    • Context.Import メソッド内で、ビルド成果物のパス生成ロジックに InstallTag を組み込む変更。

コアとなるコードの解説

raceInit() 関数 (src/cmd/go/build.go)

func raceInit() {
	if !buildRace {
		return
	}
	if goarch != "amd64" || goos != "linux" && goos != "darwin" {
		fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64 and darwin/amd64\n", flag.Args()[0])
		os.Exit(2)
	}
	buildGcflags = append(buildGcflags, "-b")
	buildLdflags = append(buildLdflags, "-b")
	buildCcflags = append(buildCcflags, "-DRACE")
	buildContext.InstallTag = "race"
	buildContext.BuildTags = append(buildContext.BuildTags, "race")
}

この関数は、-race フラグが指定された場合に呼び出される主要な初期化ロジックです。

  1. if !buildRace { return }: -race フラグが指定されていない場合は何もしません。
  2. if goarch != "amd64" || goos != "linux" && goos != "darwin" { ... }: Race Detectorがサポートされているプラットフォーム(Linux/amd64, macOS/amd64)であるかを確認します。それ以外の場合はエラーメッセージを出力して終了します。これは、Race Detectorが特定のアーキテクチャとOSに依存する低レベルなフックを使用するためです。
  3. buildGcflags = append(buildGcflags, "-b"): Goコンパイラ (gc) に渡すフラグに -b を追加します。このフラグは、Race Detectorがコードを計測するために必要な追加のバイトコードを生成するようにコンパイラに指示します。
  4. buildLdflags = append(buildLdflags, "-b"): Goリンカに渡すフラグに -b を追加します。これは、Race Detectorのランタイムライブラリをリンクし、必要な初期化コードを組み込むためにリンカに指示します。
  5. buildCcflags = append(buildCcflags, "-DRACE"): Cgoコンパイラに渡すフラグに -DRACE を追加します。これにより、Cgoで書かれたコードがRace Detectorと連携するための特別なマクロや定義が有効になります。
  6. buildContext.InstallTag = "race": ビルドコンテキストの InstallTag"race" に設定します。これにより、Race Detectorが有効なビルドの成果物(例: pkg/linux_amd64_race/my_package.a)が、通常のビルドの成果物とは異なるディレクトリにインストールされるようになります。これは、異なるビルド設定の成果物が衝突するのを防ぐために重要です。
  7. buildContext.BuildTags = append(buildContext.BuildTags, "race"): ビルドコンテキストの BuildTags"race" タグを追加します。これにより、// +build race ディレクティブを持つソースファイルが、-race フラグが指定されたビルドでのみコンパイルされるようになります。これは、Race Detector固有のコードを条件付きで含めるために使用されます。

go/build.Context 構造体と InstallTag (src/pkg/go/build/build.go)

type Context struct {
	// ... 既存のフィールド ...
	InstallTag  string   // package install directory suffix
	// ... 既存のフィールド ...
}

// Context.Import メソッド内の関連箇所
// ...
case "gc":
	tag := ""
	if ctxt.InstallTag != "" {
		tag = "_" + ctxt.InstallTag
	}
	pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + tag + "/" + p.ImportPath + ".a"
// ...

Context 構造体に追加された InstallTag フィールドは、Goパッケージのビルド成果物(アーカイブファイル .a)がインストールされるディレクトリのパスに影響を与えます。

Context.Import メソッド内で、コンパイラが "gc" の場合、pkga (パッケージアーカイブのパス) を構築する際に InstallTag が考慮されます。InstallTag が空でなければ、_ プレフィックスとともに GOOS_GOARCH の後に追加されます。

例えば、InstallTag"race" であれば、pkg/linux_amd64_race/ のようなパスが生成されます。これにより、通常のビルド (pkg/linux_amd64/) とRace Detectorを有効にしたビルドの成果物が共存できるようになり、開発者は両方のバージョンのバイナリを簡単に切り替えることができます。

runtime/race への依存関係追加 (src/cmd/go/pkg.go)

// ...
	// Everything depends on runtime, except runtime and unsafe.
	if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
		importPaths = append(importPaths, "runtime")
		// When race detection enabled everything depends on runtime/race.
		// Exclude runtime/cgo and cmd/cgo to avoid circular dependencies.
		if buildRace && (!p.Standard || (p.ImportPath != "runtime/race" && p.ImportPath != "runtime/cgo" && p.ImportPath != "cmd/cgo")) {
			importPaths = append(importPaths, "runtime/race")
		}
	}
// ...

このコードスニペットは、go コマンドがパッケージの依存関係を解決する際に、-race フラグが有効な場合に runtime/race パッケージを強制的に依存関係に追加するロジックを示しています。

  • if buildRace && (...): buildRacetrue の場合(つまり -race フラグが指定されている場合)にのみ、このロジックが実行されます。
  • (!p.Standard || (p.ImportPath != "runtime/race" && p.ImportPath != "runtime/cgo" && p.ImportPath != "cmd/cgo")): この条件は、runtime/race 自体、runtime/cgocmd/cgo の3つのパッケージを除外しています。これは、これらのパッケージがRace Detectorの内部実装やCgoの低レベルな部分に関わるため、循環依存を避けたり、不必要な依存関係を追加しないようにするためです。
  • importPaths = append(importPaths, "runtime/race"): 上記の条件を満たすすべてのパッケージに対して、runtime/race をそのインポートパスリストに追加します。これにより、Race DetectorのランタイムライブラリがすべてのGoプログラムにリンクされ、実行時にメモリアクセスを監視できるようになります。

これらの変更は、GoのビルドシステムがRace Detectorをシームレスに統合し、開発者が簡単にデータ競合を検出できる環境を提供する上で不可欠な基盤を築きました。

関連リンク

参考にした情報源リンク

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

このコミットは、Go言語のビルドシステムにデータ競合検出機能を追加するための最初のステップです。具体的には、go コマンドに -race フラグを導入し、データ競合検出を有効にするためのビルドシステム側の変更を行っています。

コミット

commit 8ed026e783ded812ee4bd03a47278f95168b9087
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Tue Sep 18 23:47:15 2012 +0400

    race: build system changes
    This is the first part of a bigger change that adds data race detection feature:
    https://golang.org/cl/6456044
    Adds -race flag to go command.
    API change:
    +pkg go/build, type Context struct, InstallTag string

    R=rsc
    CC=golang-dev
    https://golang.org/cl/6488075

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

https://github.com/golang/go/commit/8ed026e783ded812ee4bd03a47278f95168b9087

元コミット内容

このコミットの元の内容は、Go言語のビルドシステムにデータ競合検出機能を追加するための基盤となる変更です。主な目的は、go コマンドに -race フラグを追加し、このフラグが指定された際にデータ競合検出が有効になるようにビルドプロセスを調整することです。また、go/build パッケージの Context 構造体に InstallTag フィールドが追加され、ビルド成果物のインストールパスにタグを付与できるようになっています。これは、-race ビルドと通常のビルドの成果物を区別するために利用されます。

変更の背景

この変更の背景には、並行プログラミングにおける最も厄介なバグの一つである「データ競合(Data Race)」を開発者が容易に検出できるようにするという強い要望がありました。データ競合は、複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが同期メカニズムによって保護されていない場合に発生します。このような競合は、プログラムの非決定的な動作やクラッシュを引き起こす可能性があり、デバッグが非常に困難です。

Go言語は並行処理を言語レベルでサポートしているため、データ競合の発生リスクも高まります。そのため、Go開発チームは、コンパイル時または実行時にデータ競合を検出するツールを提供することの重要性を認識していました。このコミットは、そのための大規模な取り組みの第一歩であり、go コマンドに統合されたデータ競合検出機能(Race Detector)の導入に向けたビルドシステム側の準備を行っています。

前提知識の解説

データ競合 (Data Race)

データ競合は、並行プログラミングにおいて発生する特定の種類のバグです。以下の3つの条件がすべて満たされたときに発生します。

  1. 複数のゴルーチン(またはスレッド)が同時に同じメモリ位置にアクセスする。
  2. 少なくとも1つのアクセスが書き込み操作である。
  3. それらのアクセスが同期メカニズム(ミューテックス、チャネルなど)によって保護されていない。

データ競合が発生すると、プログラムの実行結果が非決定的になり、予測不能な動作、データの破損、クラッシュなどにつながる可能性があります。これは、異なるゴルーチンがメモリにアクセスする順序が実行ごとに変わり得るためです。

Go Race Detector

Go言語のRace Detectorは、実行時にデータ競合を検出するためのツールです。プログラムを特殊な方法でコンパイルし、実行時にメモリアクセスを監視することで、データ競合のパターンを特定します。検出された競合は、ファイル名、行番号、スタックトレースなどの詳細情報とともに報告されます。

Race Detectorは、プログラムの実行速度を低下させる(通常5〜10倍)ため、本番環境での常時使用には適していません。しかし、開発中やテスト中に使用することで、見つけにくい並行処理のバグを効率的に特定できます。

go コマンドとビルドプロセス

go コマンドは、Go言語のソースコードのコンパイル、テスト、実行、パッケージ管理などを行うための主要なツールです。go buildgo installgo rungo test などのサブコマンドがあり、それぞれ異なるビルドフェーズや実行フェーズを担当します。

このコミットでは、これらのサブコマンドが共通して利用するビルドシステムの設定に、-race フラグを処理するロジックを追加しています。

go/build パッケージ

go/build パッケージは、Goのソースコードパッケージの構造を解析し、ビルドに必要な情報を取得するための標準ライブラリです。Context 構造体は、ビルド環境に関する情報(OS、アーキテクチャ、GOPATH、ビルドタグなど)をカプセル化します。このコミットでは、Context 構造体に InstallTag フィールドが追加され、ビルド成果物のインストールパスに影響を与えるようになります。

技術的詳細

このコミットの技術的な変更は、主に以下の点に集約されます。

  1. -race フラグの導入:
    • src/cmd/go/build.gosrc/cmd/go/run.gosrc/cmd/go/test.goraceInit() 関数が追加され、go build, go install, go run, go test コマンドの実行時に呼び出されます。
    • raceInit() 関数は、-race フラグが指定された場合に、現在のOS/アーキテクチャが linux/amd64 または darwin/amd64 であるかをチェックします。これら以外の環境ではエラーを出力し終了します。
    • -race フラグが有効な場合、コンパイラフラグ (buildGcflags)、リンカフラグ (buildLdflags)、Cgoコンパイラフラグ (buildCcflags) にそれぞれ -b-b-DRACE が追加されます。これらはRace Detectorを有効にするための特別なフラグです。
    • buildContext.InstallTag"race" に設定され、buildContext.BuildTags"race" タグが追加されます。これにより、Race Detectorが有効なビルドと通常のビルドの成果物が異なるディレクトリにインストールされるようになります(例: pkg/linux_amd64_race/)。
  2. go/build.Context 構造体への InstallTag フィールド追加:
    • src/pkg/go/build/build.gogo/build.Context 構造体に InstallTag string フィールドが追加されました。
    • この InstallTag は、ビルド成果物(.a ファイルなど)のインストールパスを決定する際に使用されます。具体的には、pkg/GOOS_GOARCH/ の後に _InstallTag が追加される形式になります(例: pkg/linux_amd64_race/)。これにより、Race Detectorを有効にしたビルドとそうでないビルドの成果物が衝突するのを防ぎます。
  3. runtime/race パッケージの依存関係の追加:
    • src/cmd/go/pkg.go において、-race フラグが有効な場合、すべてのパッケージが runtime/race パッケージに依存するように変更されました。ただし、runtime/race 自体、runtime/cgocmd/cgo は循環依存を避けるために除外されます。
  4. Cgoのビルドロジックの調整:
    • src/cmd/go/build.gobuilder.action メソッド内で、cgo のビルド時に buildRacetrue の場合、cgo バイナリのオーバーライトを防ぐための条件が追加されました。
    • runtime/race または runtime/cgo パッケージのCgoビルドにおいて、-import_syscall=false フラグが追加されました。これは、これらのパッケージがRace Detectorの内部実装やCgoの低レベルな部分に関わるため、特定のシンボル解決を避けるための措置と考えられます。

これらの変更により、go コマンドは -race フラグを認識し、Race Detectorをシームレスに統合し、ビルド成果物のパスを分離するようになります。

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

このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。

  • src/cmd/go/build.go:
    • buildRace グローバル変数の追加。
    • addBuildFlags 関数での -race フラグの登録。
    • runBuild, runInstall 関数での raceInit() の呼び出し。
    • builder.action 関数での cgo 関連の条件分岐に !buildRace の追加。
    • raceInit() 関数の追加。この関数が -race フラグが有効な場合の主要な設定(OS/アーキテクチャチェック、コンパイラ/リンカフラグの追加、InstallTagBuildTags の設定)を行います。
  • src/cmd/go/pkg.go:
    • Package.load メソッド内で、buildRace が有効な場合に runtime/race を依存関係に追加するロジック。
  • src/cmd/go/run.go:
    • runRun 関数での raceInit() の呼び出し。
  • src/cmd/go/test.go:
    • runTest 関数での raceInit() の呼び出し。
  • src/cmd/go/testflag.go:
    • testFlagDefn-race フラグの定義を追加し、testFlags 関数でその処理を可能にする。
  • src/pkg/go/build/build.go:
    • Context 構造体に InstallTag string フィールドを追加。
    • Context.Import メソッド内で、ビルド成果物のパス生成ロジックに InstallTag を組み込む変更。

コアとなるコードの解説

raceInit() 関数 (src/cmd/go/build.go)

func raceInit() {
	if !buildRace {
		return
	}
	if goarch != "amd64" || goos != "linux" && goos != "darwin" {
		fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64 and darwin/amd64\\n", flag.Args()[0])
		os.Exit(2)
	}
	buildGcflags = append(buildGcflags, "-b")
	buildLdflags = append(buildLdflags, "-b")
	buildCcflags = append(buildCcflags, "-DRACE")
	buildContext.InstallTag = "race"
	buildContext.BuildTags = append(buildContext.BuildTags, "race")
}

この関数は、-race フラグが指定された場合に呼び出される主要な初期化ロジックです。

  1. if !buildRace { return }: -race フラグが指定されていない場合は何もしません。
  2. if goarch != "amd64" || goos != "linux" && goos != "darwin" { ... }: Race Detectorがサポートされているプラットフォーム(Linux/amd64, macOS/amd64)であるかを確認します。それ以外の場合はエラーメッセージを出力して終了します。これは、Race Detectorが特定のアーキテクチャとOSに依存する低レベルなフックを使用するためです。
  3. buildGcflags = append(buildGcflags, "-b"): Goコンパイラ (gc) に渡すフラグに -b を追加します。このフラグは、Race Detectorがコードを計測するために必要な追加のバイトコードを生成するようにコンパイラに指示します。
  4. buildLdflags = append(buildLdflags, "-b"): Goリンカに渡すフラグに -b を追加します。これは、Race Detectorのランタイムライブラリをリンクし、必要な初期化コードを組み込むためにリンカに指示します。
  5. buildCcflags = append(buildCcflags, "-DRACE"): Cgoコンパイラに渡すフラグに -DRACE を追加します。これにより、Cgoで書かれたコードがRace Detectorと連携するための特別なマクロや定義が有効になります。
  6. buildContext.InstallTag = "race": ビルドコンテキストの InstallTag"race" に設定します。これにより、Race Detectorが有効なビルドの成果物(例: pkg/linux_amd64_race/my_package.a)が、通常のビルドの成果物とは異なるディレクトリにインストールされるようになります。これは、異なるビルド設定の成果物が衝突するのを防ぐために重要です。
  7. buildContext.BuildTags = append(buildContext.BuildTags, "race"): ビルドコンテキストの BuildTags"race" タグを追加します。これにより、// +build race ディレクティブを持つソースファイルが、-race フラグが指定されたビルドでのみコンパイルされるようになります。これは、Race Detector固有のコードを条件付きで含めるために使用されます。

go/build.Context 構造体と InstallTag (src/pkg/go/build/build.go)

type Context struct {
	// ... 既存のフィールド ...
	InstallTag  string   // package install directory suffix
	// ... 既存のフィールド ...
}

// Context.Import メソッド内の関連箇所
// ...
case "gc":
	tag := ""
	if ctxt.InstallTag != "" {
		tag = "_" + ctxt.InstallTag
	}
	pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + tag + "/" + p.ImportPath + ".a"
// ...

Context 構造体に追加された InstallTag フィールドは、Goパッケージのビルド成果物(アーカイブファイル .a)がインストールされるディレクトリのパスに影響を与えます。

Context.Import メソッド内で、コンパイラが "gc" の場合、pkga (パッケージアーカイブのパス) を構築する際に InstallTag が考慮されます。InstallTag が空でなければ、_ プレフィックスとともに GOOS_GOARCH の後に追加されます。

例えば、InstallTag"race" であれば、pkg/linux_amd64_race/ のようなパスが生成されます。これにより、通常のビルド (pkg/linux_amd64/) とRace Detectorを有効にしたビルドの成果物が共存できるようになり、開発者は両方のバージョンのバイナリを簡単に切り替えることができます。

runtime/race への依存関係追加 (src/cmd/go/pkg.go)

// ...
	// Everything depends on runtime, except runtime and unsafe.
	if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
		importPaths = append(importPaths, "runtime")
		// When race detection enabled everything depends on runtime/race.
		// Exclude runtime/cgo and cmd/cgo to avoid circular dependencies.
		if buildRace && (!p.Standard || (p.ImportPath != "runtime/race" && p.ImportPath != "runtime/cgo" && p.ImportPath != "cmd/cgo")) {
			importPaths = append(importPaths, "runtime/race")
		}
	}
// ...

このコードスニペットは、go コマンドがパッケージの依存関係を解決する際に、-race フラグが有効な場合に runtime/race パッケージを強制的に依存関係に追加するロジックを示しています。

  • if buildRace && (...): buildRacetrue の場合(つまり -race フラグが指定されている場合)にのみ、このロジックが実行されます。
  • (!p.Standard || (p.ImportPath != "runtime/race" && p.ImportPath != "runtime/cgo" && p.ImportPath != "cmd/cgo")): この条件は、runtime/race 自体、runtime/cgocmd/cgo の3つのパッケージを除外しています。これは、これらのパッケージがRace Detectorの内部実装やCgoの低レベルな部分に関わるため、循環依存を避けたり、不必要な依存関係を追加しないようにするためです。
  • importPaths = append(importPaths, "runtime/race"): 上記の条件を満たすすべてのパッケージに対して、runtime/race をそのインポートパスリストに追加します。これにより、Race DetectorのランタイムライブラリがすべてのGoプログラムにリンクされ、実行時にメモリアクセスを監視できるようになります。

これらの変更は、GoのビルドシステムがRace Detectorをシームレスに統合し、開発者が簡単にデータ競合を検出できる環境を提供する上で不可欠な基盤を築きました。

関連リンク

参考にした情報源リンク