[インデックス 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つのアクセスが書き込み操作である。
- それらのアクセスが同期メカニズム(ミューテックス、チャネルなど)によって保護されていない。
データ競合が発生すると、プログラムの実行結果が非決定的になり、予測不能な動作、データの破損、クラッシュなどにつながる可能性があります。これは、異なるゴルーチンがメモリにアクセスする順序が実行ごとに変わり得るためです。
Go Race Detector
Go言語のRace Detectorは、実行時にデータ競合を検出するためのツールです。プログラムを特殊な方法でコンパイルし、実行時にメモリアクセスを監視することで、データ競合のパターンを特定します。検出された競合は、ファイル名、行番号、スタックトレースなどの詳細情報とともに報告されます。
Race Detectorは、プログラムの実行速度を低下させる(通常5〜10倍)ため、本番環境での常時使用には適していません。しかし、開発中やテスト中に使用することで、見つけにくい並行処理のバグを効率的に特定できます。
go コマンドとビルドプロセス
go コマンドは、Go言語のソースコードのコンパイル、テスト、実行、パッケージ管理などを行うための主要なツールです。go build、go install、go run、go test などのサブコマンドがあり、それぞれ異なるビルドフェーズや実行フェーズを担当します。
このコミットでは、これらのサブコマンドが共通して利用するビルドシステムの設定に、-race フラグを処理するロジックを追加しています。
go/build パッケージ
go/build パッケージは、Goのソースコードパッケージの構造を解析し、ビルドに必要な情報を取得するための標準ライブラリです。Context 構造体は、ビルド環境に関する情報(OS、アーキテクチャ、GOPATH、ビルドタグなど)をカプセル化します。このコミットでは、Context 構造体に InstallTag フィールドが追加され、ビルド成果物のインストールパスに影響を与えるようになります。
技術的詳細
このコミットの技術的な変更は、主に以下の点に集約されます。
-raceフラグの導入:src/cmd/go/build.go、src/cmd/go/run.go、src/cmd/go/test.goにraceInit()関数が追加され、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/)。
go/build.Context構造体へのInstallTagフィールド追加:src/pkg/go/build/build.goのgo/build.Context構造体にInstallTag stringフィールドが追加されました。- この
InstallTagは、ビルド成果物(.aファイルなど)のインストールパスを決定する際に使用されます。具体的には、pkg/GOOS_GOARCH/の後に_InstallTagが追加される形式になります(例:pkg/linux_amd64_race/)。これにより、Race Detectorを有効にしたビルドとそうでないビルドの成果物が衝突するのを防ぎます。
runtime/raceパッケージの依存関係の追加:src/cmd/go/pkg.goにおいて、-raceフラグが有効な場合、すべてのパッケージがruntime/raceパッケージに依存するように変更されました。ただし、runtime/race自体、runtime/cgo、cmd/cgoは循環依存を避けるために除外されます。
- Cgoのビルドロジックの調整:
src/cmd/go/build.goのbuilder.actionメソッド内で、cgoのビルド時にbuildRaceがtrueの場合、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/アーキテクチャチェック、コンパイラ/リンカフラグの追加、InstallTagとBuildTagsの設定)を行います。
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 フラグが指定された場合に呼び出される主要な初期化ロジックです。
if !buildRace { return }:-raceフラグが指定されていない場合は何もしません。if goarch != "amd64" || goos != "linux" && goos != "darwin" { ... }: Race Detectorがサポートされているプラットフォーム(Linux/amd64, macOS/amd64)であるかを確認します。それ以外の場合はエラーメッセージを出力して終了します。これは、Race Detectorが特定のアーキテクチャとOSに依存する低レベルなフックを使用するためです。buildGcflags = append(buildGcflags, "-b"): Goコンパイラ (gc) に渡すフラグに-bを追加します。このフラグは、Race Detectorがコードを計測するために必要な追加のバイトコードを生成するようにコンパイラに指示します。buildLdflags = append(buildLdflags, "-b"): Goリンカに渡すフラグに-bを追加します。これは、Race Detectorのランタイムライブラリをリンクし、必要な初期化コードを組み込むためにリンカに指示します。buildCcflags = append(buildCcflags, "-DRACE"): Cgoコンパイラに渡すフラグに-DRACEを追加します。これにより、Cgoで書かれたコードがRace Detectorと連携するための特別なマクロや定義が有効になります。buildContext.InstallTag = "race": ビルドコンテキストのInstallTagを"race"に設定します。これにより、Race Detectorが有効なビルドの成果物(例:pkg/linux_amd64_race/my_package.a)が、通常のビルドの成果物とは異なるディレクトリにインストールされるようになります。これは、異なるビルド設定の成果物が衝突するのを防ぐために重要です。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 && (...):buildRaceがtrueの場合(つまり-raceフラグが指定されている場合)にのみ、このロジックが実行されます。(!p.Standard || (p.ImportPath != "runtime/race" && p.ImportPath != "runtime/cgo" && p.ImportPath != "cmd/cgo")): この条件は、runtime/race自体、runtime/cgo、cmd/cgoの3つのパッケージを除外しています。これは、これらのパッケージがRace Detectorの内部実装やCgoの低レベルな部分に関わるため、循環依存を避けたり、不必要な依存関係を追加しないようにするためです。importPaths = append(importPaths, "runtime/race"): 上記の条件を満たすすべてのパッケージに対して、runtime/raceをそのインポートパスリストに追加します。これにより、Race DetectorのランタイムライブラリがすべてのGoプログラムにリンクされ、実行時にメモリアクセスを監視できるようになります。
これらの変更は、GoのビルドシステムがRace Detectorをシームレスに統合し、開発者が簡単にデータ競合を検出できる環境を提供する上で不可欠な基盤を築きました。
関連リンク
- Go Race Detectorの公式ドキュメント: https://go.dev/doc/articles/race_detector
- 元の変更リスト (CL 6456044): https://golang.org/cl/6456044 (このコミットが参照している、より大きな変更の最初の部分)
- このコミットの変更リスト (CL 6488075): https://golang.org/cl/6488075
参考にした情報源リンク
- Go Race Detector: https://go.dev/doc/articles/race_detector
- Go Command Documentation: https://go.dev/cmd/go/
- Go
go/buildPackage Documentation: https://pkg.go.dev/go/build - Data Race (Wikipedia): https://en.wikipedia.org/wiki/Race_condition#Data_race
- Goのコミット履歴 (GitHub): https://github.com/golang/go/commits/master
[インデックス 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つのアクセスが書き込み操作である。
- それらのアクセスが同期メカニズム(ミューテックス、チャネルなど)によって保護されていない。
データ競合が発生すると、プログラムの実行結果が非決定的になり、予測不能な動作、データの破損、クラッシュなどにつながる可能性があります。これは、異なるゴルーチンがメモリにアクセスする順序が実行ごとに変わり得るためです。
Go Race Detector
Go言語のRace Detectorは、実行時にデータ競合を検出するためのツールです。プログラムを特殊な方法でコンパイルし、実行時にメモリアクセスを監視することで、データ競合のパターンを特定します。検出された競合は、ファイル名、行番号、スタックトレースなどの詳細情報とともに報告されます。
Race Detectorは、プログラムの実行速度を低下させる(通常5〜10倍)ため、本番環境での常時使用には適していません。しかし、開発中やテスト中に使用することで、見つけにくい並行処理のバグを効率的に特定できます。
go コマンドとビルドプロセス
go コマンドは、Go言語のソースコードのコンパイル、テスト、実行、パッケージ管理などを行うための主要なツールです。go build、go install、go run、go test などのサブコマンドがあり、それぞれ異なるビルドフェーズや実行フェーズを担当します。
このコミットでは、これらのサブコマンドが共通して利用するビルドシステムの設定に、-race フラグを処理するロジックを追加しています。
go/build パッケージ
go/build パッケージは、Goのソースコードパッケージの構造を解析し、ビルドに必要な情報を取得するための標準ライブラリです。Context 構造体は、ビルド環境に関する情報(OS、アーキテクチャ、GOPATH、ビルドタグなど)をカプセル化します。このコミットでは、Context 構造体に InstallTag フィールドが追加され、ビルド成果物のインストールパスに影響を与えるようになります。
技術的詳細
このコミットの技術的な変更は、主に以下の点に集約されます。
-raceフラグの導入:src/cmd/go/build.go、src/cmd/go/run.go、src/cmd/go/test.goにraceInit()関数が追加され、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/)。
go/build.Context構造体へのInstallTagフィールド追加:src/pkg/go/build/build.goのgo/build.Context構造体にInstallTag stringフィールドが追加されました。- この
InstallTagは、ビルド成果物(.aファイルなど)のインストールパスを決定する際に使用されます。具体的には、pkg/GOOS_GOARCH/の後に_InstallTagが追加される形式になります(例:pkg/linux_amd64_race/)。これにより、Race Detectorを有効にしたビルドとそうでないビルドの成果物が衝突するのを防ぎます。
runtime/raceパッケージの依存関係の追加:src/cmd/go/pkg.goにおいて、-raceフラグが有効な場合、すべてのパッケージがruntime/raceパッケージに依存するように変更されました。ただし、runtime/race自体、runtime/cgo、cmd/cgoは循環依存を避けるために除外されます。
- Cgoのビルドロジックの調整:
src/cmd/go/build.goのbuilder.actionメソッド内で、cgoのビルド時にbuildRaceがtrueの場合、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/アーキテクチャチェック、コンパイラ/リンカフラグの追加、InstallTagとBuildTagsの設定)を行います。
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 フラグが指定された場合に呼び出される主要な初期化ロジックです。
if !buildRace { return }:-raceフラグが指定されていない場合は何もしません。if goarch != "amd64" || goos != "linux" && goos != "darwin" { ... }: Race Detectorがサポートされているプラットフォーム(Linux/amd64, macOS/amd64)であるかを確認します。それ以外の場合はエラーメッセージを出力して終了します。これは、Race Detectorが特定のアーキテクチャとOSに依存する低レベルなフックを使用するためです。buildGcflags = append(buildGcflags, "-b"): Goコンパイラ (gc) に渡すフラグに-bを追加します。このフラグは、Race Detectorがコードを計測するために必要な追加のバイトコードを生成するようにコンパイラに指示します。buildLdflags = append(buildLdflags, "-b"): Goリンカに渡すフラグに-bを追加します。これは、Race Detectorのランタイムライブラリをリンクし、必要な初期化コードを組み込むためにリンカに指示します。buildCcflags = append(buildCcflags, "-DRACE"): Cgoコンパイラに渡すフラグに-DRACEを追加します。これにより、Cgoで書かれたコードがRace Detectorと連携するための特別なマクロや定義が有効になります。buildContext.InstallTag = "race": ビルドコンテキストのInstallTagを"race"に設定します。これにより、Race Detectorが有効なビルドの成果物(例:pkg/linux_amd64_race/my_package.a)が、通常のビルドの成果物とは異なるディレクトリにインストールされるようになります。これは、異なるビルド設定の成果物が衝突するのを防ぐために重要です。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 && (...):buildRaceがtrueの場合(つまり-raceフラグが指定されている場合)にのみ、このロジックが実行されます。(!p.Standard || (p.ImportPath != "runtime/race" && p.ImportPath != "runtime/cgo" && p.ImportPath != "cmd/cgo")): この条件は、runtime/race自体、runtime/cgo、cmd/cgoの3つのパッケージを除外しています。これは、これらのパッケージがRace Detectorの内部実装やCgoの低レベルな部分に関わるため、循環依存を避けたり、不必要な依存関係を追加しないようにするためです。importPaths = append(importPaths, "runtime/race"): 上記の条件を満たすすべてのパッケージに対して、runtime/raceをそのインポートパスリストに追加します。これにより、Race DetectorのランタイムライブラリがすべてのGoプログラムにリンクされ、実行時にメモリアクセスを監視できるようになります。
これらの変更は、GoのビルドシステムがRace Detectorをシームレスに統合し、開発者が簡単にデータ競合を検出できる環境を提供する上で不可欠な基盤を築きました。
関連リンク
- Go Race Detectorの公式ドキュメント: https://go.dev/doc/articles/race_detector
- 元の変更リスト (CL 6456044): https://golang.org/cl/6456044 (このコミットが参照している、より大きな変更の最初の部分)
- このコミットの変更リスト (CL 6488075): https://golang.org/cl/6488075
参考にした情報源リンク
- Go Race Detector: https://go.dev/doc/articles/race_detector
- Go Command Documentation: https://go.dev/cmd/go/
- Go
go/buildPackage Documentation: https://pkg.go.dev/go/build - Data Race (Wikipedia): https://en.wikipedia.org/wiki/Race_condition#Data_race
- Goのコミット履歴 (GitHub): https://github.com/golang/go/commits/master