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

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

このコミットは、Go言語の配布ツール (misc/dist/bindist.go) における変更です。具体的には、Goのレース検出器(Race Detector)を有効にしたバイナリをビルドする際のターゲットマッチングロジックが修正されています。

コミット

misc/dist: build race packages when os suffix present

The "darwin-amd64-osx10.8" target was not matching "darwin-amd64".

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

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

https://github.com/golang/go/commit/f5d25fd695471065a474b7940ef11e006d683aac

元コミット内容

misc/dist: build race packages when os suffix present

The "darwin-amd64-osx10.8" target was not matching "darwin-amd64".

変更の背景

Go言語のビルドシステムでは、特定のOSやアーキテクチャ向けにバイナリを生成する際に、GOOS (オペレーティングシステム) と GOARCH (アーキテクチャ) の組み合わせを使用します。例えば、macOS (Darwin) の64ビットIntelプロセッサ向けであれば darwin-amd64 となります。

Goには、並行処理におけるデータ競合(data race)を検出するための「レース検出器(Race Detector)」という強力なツールが組み込まれています。このレース検出器を有効にしてGoプログラムをビルドする場合、通常は特定のビルドタグや環境変数を設定します。

このコミット以前のGoの配布ツール (misc/dist/bindist.go) では、レース検出器を有効にするべきターゲットを判断する際に、ターゲット文字列が完全に一致するかどうかのみをチェックしていました。しかし、一部のターゲット環境では、darwin-amd64-osx10.8 のように、GOOS-GOARCH の後にさらにOSのバージョンなどのサフィックスが付加されることがありました。

この場合、配布ツールは darwin-amd64-osx10.8 というターゲットを darwin-amd64 とは異なるものと認識し、レース検出器を有効にしたビルドが必要であるにもかかわらず、そのビルドを行わないという問題が発生していました。結果として、特定の環境向けのGoバイナリがレース検出器なしでビルドされてしまい、開発者がデータ競合の問題を検出できない可能性がありました。このコミットは、この不一致を解消し、サフィックスが付いたターゲットに対しても適切にレース検出器を有効にしたビルドが行われるようにするために導入されました。

前提知識の解説

Go言語のビルドシステムとクロスコンパイル

Go言語は、強力なクロスコンパイル機能を内蔵しています。これは、あるOSやアーキテクチャ上で、別のOSやアーキテクチャ向けのバイナリを生成できる能力を指します。この機能は、GOOSGOARCH という環境変数によって制御されます。

  • GOOS: ターゲットとなるオペレーティングシステム(例: linux, windows, darwin (macOS))。
  • GOARCH: ターゲットとなるアーキテクチャ(例: amd64, arm, arm64)。

これらの組み合わせにより、例えば GOOS=windows GOARCH=amd64 go build とすることで、Windows 64bit向けの実行ファイルをLinux上でビルドできます。

Go Race Detector (レース検出器)

Goのレース検出器は、Goプログラムの実行中に発生する可能性のあるデータ競合を動的に検出するツールです。データ競合は、複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが同期メカニズムによって保護されていない場合に発生します。データ競合は、予測不能なプログラムの動作やバグの原因となるため、その検出は並行プログラミングにおいて非常に重要です。

レース検出器は、go build -race コマンドを使用することで有効にできます。有効にすると、コンパイラは追加のインストゥルメンテーションコードを生成し、実行時にメモリアクセスを監視して競合を報告します。

misc/dist パッケージと bindist.go

misc/dist パッケージは、GoのソースコードからGoの配布バイナリ(SDKなど)をビルドするためのツール群です。Goプロジェクト自体がGoで書かれており、そのビルドプロセスもGoのツールによって管理されています。

bindist.go は、この misc/dist パッケージの一部であり、Goのバイナリ配布物を作成する際の主要なロジックを含んでいます。これには、様々なプラットフォーム向けのGoツールチェインや標準ライブラリのビルド、そして必要に応じてレース検出器を有効にしたバイナリの生成などが含まれます。

strings.HasPrefix 関数

Goの標準ライブラリ strings パッケージに含まれる HasPrefix 関数は、ある文字列が特定のプレフィックス(接頭辞)で始まるかどうかをチェックするために使用されます。

func HasPrefix(s, prefix string) bool

この関数は、文字列 s が文字列 prefix で始まる場合に true を返します。

技術的詳細

このコミットの核心は、Goの配布ツールがレース検出器を有効にするべきターゲットを識別する方法の変更にあります。

以前のコードでは、bindist.go 内で、ビルドターゲット(targ)がレース検出器が利用可能なターゲットのリスト(raceAvailable)に含まれるかどうかを厳密に比較していました。

if t == targ { // 厳密な一致のみをチェック
    b.Race = true
}

この厳密な一致のロジックでは、例えば raceAvailable リストに darwin-amd64 が含まれていても、実際のビルドターゲットが darwin-amd64-osx10.8 のようにサフィックスを持つ場合、t == targ の条件は false となり、レース検出器が有効になりませんでした。

このコミットでは、この条件に strings.HasPrefix を用いたチェックが追加されました。

if t == targ || strings.HasPrefix(targ, t+"-") { // 厳密な一致、またはプレフィックス一致をチェック
    b.Race = true
}

この変更により、以下のいずれかの条件が満たされれば、レース検出器が有効になります。

  1. t == targ: ターゲット文字列がレース検出器が利用可能なターゲットと完全に一致する場合(例: targdarwin-amd64 で、tdarwin-amd64 の場合)。
  2. strings.HasPrefix(targ, t+"-"): ターゲット文字列(targ)が、レース検出器が利用可能なターゲット(t)にハイフン (-) を付けた文字列をプレフィックスとして持つ場合(例: targdarwin-amd64-osx10.8 で、tdarwin-amd64 の場合、darwin-amd64- がプレフィックスとしてチェックされる)。

このロジックの追加により、darwin-amd64-osx10.8 のようなサフィックス付きのターゲットも darwin-amd64 の派生として正しく認識され、レース検出器が有効なビルドが実行されるようになりました。これは、Goのビルドシステムがより堅牢になり、特定の環境におけるレース検出器の利用可能性が向上したことを意味します。

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

--- a/misc/dist/bindist.go
+++ b/misc/dist/bindist.go
@@ -175,7 +175,7 @@ func main() {
 			}
 			if *includeRace {
 				for _, t := range raceAvailable {
-					if t == targ {
+					if t == targ || strings.HasPrefix(targ, t+"-") {
 						b.Race = true
 					}
 				}

コアとなるコードの解説

変更は misc/dist/bindist.go ファイルの main 関数内、具体的にはレース検出器を有効にするかどうかのロジック部分で行われています。

元のコードでは、raceAvailable スライス(レース検出器が利用可能なターゲットのリスト)をループし、現在のビルドターゲット targ がそのリスト内のいずれかの要素 t完全に一致する場合にのみ、ビルド設定 bRace フィールドを true に設定していました。

変更後のコードでは、この条件に || strings.HasPrefix(targ, t+"-") が追加されました。 これは論理OR (||) で結合されており、以下のいずれかの条件が真であれば b.Race = true が実行されます。

  1. t == targ: 以前と同様に、ターゲットがレース検出器対応ターゲットと完全に一致する場合。
  2. strings.HasPrefix(targ, t+"-"): 現在のビルドターゲット targ が、レース検出器対応ターゲット t にハイフン (-) を連結した文字列をプレフィックスとして持つ場合。

この修正により、例えば t が "darwin-amd64" で targ が "darwin-amd64-osx10.8" の場合、t == targ は偽ですが、strings.HasPrefix("darwin-amd64-osx10.8", "darwin-amd64-") は真となるため、b.Racetrue に設定され、レース検出器が有効なビルドが行われるようになります。

この変更は、Goのビルドシステムがより柔軟になり、特定のOSバージョンやその他のサフィックスを持つターゲットに対しても、レース検出器のビルドオプションを適切に適用できるようにするための重要な改善です。

関連リンク

参考にした情報源リンク