[インデックス 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/build
Package 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/build
Package 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