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

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

このコミットは、Go言語のテストツールである gotest において、アーキテクチャに対応するオブジェクトファイル文字(O)の決定方法を改善するものです。具体的には、これまで gotest 内部でハードコードされていたアーキテクチャと文字のマッピングを削除し、Goのビルドシステムが提供する build.ArchChar() 関数を使用するように変更しています。これにより、より堅牢で将来のアーキテクチャ変更にも対応しやすいコードになっています。

コミット

gotest: use build.ArchChar()

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5480060

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

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

元コミット内容

gotest: use build.ArchChar()

変更の背景

この変更の背景には、Go言語のビルドシステムにおけるアーキテクチャの表現方法の標準化と、gotest ツールの堅牢性向上が挙げられます。

Go言語のコンパイラやリンカは、ターゲットとするCPUアーキテクチャ(例: amd64, arm, 386)に応じて、生成されるオブジェクトファイルやアーカイブファイルに特定の文字(例: 6 for amd64, 5 for arm, 8 for 386)を付与する慣習があります。これは、異なるアーキテクチャ向けのオブジェクトファイルを区別し、ビルドプロセスを円滑に進めるために重要です。

以前の gotest ツールでは、このアーキテクチャとオブジェクトファイル文字のマッピングが theChar という内部マップにハードコードされていました。しかし、この方法は以下のような問題点を抱えていました。

  1. 保守性の問題: 新しいアーキテクチャがGoにサポートされるたびに、gotest のコードも更新する必要がありました。これは、Goの進化に伴うアーキテクチャの追加や変更に対して、gotest が追従しきれないリスクを伴います。
  2. 一貫性の欠如: Goのビルドシステム全体でアーキテクチャ情報を管理する一元的なメカニズムがあるにもかかわらず、gotest が独自のマッピングを持つことは、コードベース全体の一貫性を損ないます。
  3. エラーハンドリングの不足: ハードコードされたマップに存在しないアーキテクチャが指定された場合、単純なマップ参照では適切なエラー処理が困難でした。

これらの問題を解決するため、Goのビルドシステムが提供する build.ArchChar() 関数を利用することで、gotest はアーキテクチャ情報の取得を標準化された方法に委ね、より柔軟で保守しやすい設計へと移行しました。

前提知識の解説

このコミットを理解するためには、以下のGo言語およびビルドシステムに関する前提知識が必要です。

  1. GOARCH 環境変数: GOARCH はGo言語のビルド環境変数の一つで、プログラムをビルドするターゲットのCPUアーキテクチャを指定します。例えば、amd64 (64-bit x86), 386 (32-bit x86), arm (ARM), arm64 (ARM 64-bit) などがあります。Goのツールチェーンは、この GOARCH の値に基づいて適切なコンパイラやライブラリを選択します。

  2. Goのビルドシステムとオブジェクトファイル: Goのビルドプロセスでは、ソースコードがコンパイルされてオブジェクトファイルが生成されます。これらのオブジェクトファイルは、通常、ターゲットアーキテクチャを示す文字を含む名前を持ちます。例えば、_obj/main.6 のように、.6amd64 アーキテクチャを示します。この慣習は、Goの初期のビルドツール(go tool 6g, go tool 8g など)に由来しており、6amd6483865arm を意味していました。これらの文字は、Goのツールチェーンが内部的に使用するアーキテクチャ識別子として機能します。

  3. gotest ツール: gotest は、Go言語の標準テストフレームワーク (testing パッケージ) を実行するためのコマンドラインツールです。Goのソースコードツリー内の src/cmd/gotest に位置し、テストのコンパイルと実行を管理します。このツールは、テストバイナリをビルドする際に、ターゲットアーキテクチャに応じた適切なビルドフラグや環境変数を設定する必要があります。

  4. build パッケージ: Goの標準ライブラリには、Goのビルドシステムに関する情報を提供する go/build パッケージ(または、より低レベルな cmd/go/internal/build パッケージなど、内部的なビルド関連のユーティリティ)が存在します。このパッケージは、Goのソースツリーの構造、環境変数、ターゲットアーキテクチャに関する情報などをプログラム的に取得するために使用されます。build.ArchChar() のような関数は、このパッケージの一部として、アーキテクチャとそれに対応するビルド文字のマッピングを提供します。

技術的詳細

このコミットの技術的な核心は、gotest ツールがアーキテクチャ固有のオブジェクトファイル文字 (O) を取得する方法を、静的なマップ参照から動的な build.ArchChar() 関数呼び出しへと変更した点にあります。

変更前は、src/cmd/gotest/gotest.go 内に theChar というグローバル変数マップが定義されていました。

// theChar is the map from architecture to object character.
var theChar = map[string]string{
	"arm":   "5",
	"amd64": "6",
	"386":   "8",
}

そして、setEnvironment 関数内で GOARCH 環境変数の値に基づいてこのマップから対応する文字を取得していました。

	O = theChar[GOARCH]
	if O == "" {
		Fatalf("unknown architecture %s", GOARCH)
	}

このアプローチの問題点は、theChar マップがGoがサポートするすべてのアーキテクチャを網羅している必要があり、新しいアーキテクチャが追加された場合にはこのマップを手動で更新しなければならないことでした。また、マップに存在しないアーキテクチャが指定された場合、O が空文字列になり、その後の Fatalf でエラーを報告する形でしたが、これはより堅牢なエラーハンドリングとは言えませんでした。

変更後、theChar マップは完全に削除されました。代わりに、build.ArchChar(GOARCH) 関数が使用されています。

	var err error
	O, err = build.ArchChar(GOARCH)
	if err != nil {
		Fatalf("unknown architecture: %s", err)
	}

build.ArchChar() 関数は、Goのビルドシステムが内部的に管理しているアーキテクチャとオブジェクトファイル文字のマッピングを利用します。この関数は、指定された GOARCH に対応する文字と、エラーが発生した場合にはエラーオブジェクトを返します。これにより、以下の利点が得られます。

  • 中央集権的な管理: アーキテクチャと文字のマッピングがGoのビルドシステム内で一元的に管理されるため、gotest がその詳細を知る必要がなくなります。Goのツールチェーンが新しいアーキテクチャをサポートするようになれば、build.ArchChar() は自動的にそれに対応します。
  • 堅牢なエラーハンドリング: build.ArchChar() はエラーを返すため、gotest はより明確に「未知のアーキテクチャ」というエラーを捕捉し、ユーザーに適切なメッセージを提示できます。これは、単にマップにキーが存在しないことをチェックするよりも、より情報量が多く、エラーの原因を特定しやすいです。
  • コードの簡素化: theChar マップの定義とそれに関連するロジックが不要になり、コードが簡素化されます。

この変更は、Goのツールチェーン全体の一貫性を高め、将来的な拡張性に対応するための重要なリファクタリングと言えます。

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

src/cmd/gotest/gotest.go ファイルが変更されています。

--- a/src/cmd/gotest/gotest.go
+++ b/src/cmd/gotest/gotest.go
@@ -114,13 +114,6 @@ func Fatalf(s string, args ...interface{}) {
 	os.Exit(2)
 }

-// theChar is the map from architecture to object character.
-var theChar = map[string]string{
-	"arm":   "5",
-	"amd64": "6",
-	"386":   "8",
-}
-
 // addEnv adds a name=value pair to the environment passed to subcommands.
 // If the item is already in the environment, addEnv replaces the value.
 func addEnv(name, value string) {
@@ -143,9 +136,10 @@ func setEnvironment() {
 		GOARCH = runtime.GOARCH
 	}
 	addEnv("GOARCH", GOARCH)
-	O = theChar[GOARCH]
-	if O == "" {
-		Fatalf("unknown architecture %s", GOARCH)
+	var err error
+	O, err = build.ArchChar(GOARCH)
+	if err != nil {
+		Fatalf("unknown architecture: %s", err)
 	}

 	// Commands and their flags.

コアとなるコードの解説

変更は主に2つの部分に分けられます。

  1. theChar マップの削除: src/cmd/gotest/gotest.go の117行目から123行目にかけて定義されていた theChar というグローバル変数マップが削除されました。このマップは、"arm": "5", "amd64": "6", "386": "8" のように、Goのアーキテクチャ名とそれに対応するオブジェクトファイル文字をハードコードしていました。このマップが不要になったことで、コードの冗長性が減り、将来のアーキテクチャ追加時のメンテナンスコストが削減されます。

  2. build.ArchChar() の使用: setEnvironment 関数内の O 変数(オブジェクトファイル文字を格納する変数)への値の割り当て方法が変更されました。 変更前は O = theChar[GOARCH] と直接マップから値を取得し、その結果が空文字列であればエラーとしていました。 変更後は、var err error でエラー変数を宣言し、O, err = build.ArchChar(GOARCH) を呼び出して Oerr の両方を受け取っています。 そして、if err != nil というGoの標準的なエラーハンドリングパターンを用いて、build.ArchChar() がエラーを返した場合に Fatalf を呼び出してプログラムを終了させています。エラーメッセージも unknown architecture: %s となり、build.ArchChar() から返された具体的なエラー情報を含むようになりました。

この変更により、gotest はGoのビルドシステムが提供する公式なAPIを通じてアーキテクチャ情報を取得するようになり、より堅牢で将来のGoの進化に対応しやすい設計になりました。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特に go/build パッケージや cmd/go/internal/build 関連のコード)
  • Go言語のコミット履歴とコードレビューコメント
  • Go言語のビルドシステムに関する一般的な知識
  • GOARCH 環境変数に関するGoの公式ドキュメントやチュートリアル
  • Goのツールチェーンにおけるオブジェクトファイル命名規則に関する情報 (例: 6g, 8g, 5g などの古いコンパイラ名)
  • gotest ツールの役割と機能に関する情報# [インデックス 10697] ファイルの概要

このコミットは、Go言語のテストツールである gotest において、アーキテクチャに対応するオブジェクトファイル文字(O)の決定方法を改善するものです。具体的には、これまで gotest 内部でハードコードされていたアーキテクチャと文字のマッピングを削除し、Goのビルドシステムが提供する build.ArchChar() 関数を使用するように変更しています。これにより、より堅牢で将来のアーキテクチャ変更にも対応しやすいコードになっています。

コミット

gotest: use build.ArchChar()

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5480060

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

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

元コミット内容

gotest: use build.ArchChar()

変更の背景

この変更の背景には、Go言語のビルドシステムにおけるアーキテクチャの表現方法の標準化と、gotest ツールの堅牢性向上が挙げられます。

Go言語のコンパイラやリンカは、ターゲットとするCPUアーキテクチャ(例: amd64, arm, 386)に応じて、生成されるオブジェクトファイルやアーカイブファイルに特定の文字(例: 6 for amd64, 5 for arm, 8 for 386)を付与する慣習があります。これは、異なるアーキテクチャ向けのオブジェクトファイルを区別し、ビルドプロセスを円滑に進めるために重要です。

以前の gotest ツールでは、このアーキテクチャとオブジェクトファイル文字のマッピングが theChar という内部マップにハードコードされていました。しかし、この方法は以下のような問題点を抱えていました。

  1. 保守性の問題: 新しいアーキテクチャがGoにサポートされるたびに、gotest のコードも更新する必要がありました。これは、Goの進化に伴うアーキテクチャの追加や変更に対して、gotest が追従しきれないリスクを伴います。
  2. 一貫性の欠如: Goのビルドシステム全体でアーキテクチャ情報を管理する一元的なメカニズムがあるにもかかわらず、gotest が独自のマッピングを持つことは、コードベース全体の一貫性を損ないます。
  3. エラーハンドリングの不足: ハードコードされたマップに存在しないアーキテクチャが指定された場合、単純なマップ参照では適切なエラー処理が困難でした。

これらの問題を解決するため、Goのビルドシステムが提供する build.ArchChar() 関数を利用することで、gotest はアーキテクチャ情報の取得を標準化された方法に委ね、より柔軟で保守しやすい設計へと移行しました。

前提知識の解説

このコミットを理解するためには、以下のGo言語およびビルドシステムに関する前提知識が必要です。

  1. GOARCH 環境変数: GOARCH はGo言語のビルド環境変数の一つで、プログラムをビルドするターゲットのCPUアーキテクチャを指定します。例えば、amd64 (64-bit x86), 386 (32-bit x86), arm (ARM), arm64 (ARM 64-bit) などがあります。Goのツールチェーンは、この GOARCH の値に基づいて適切なコンパイラやライブラリを選択します。

  2. Goのビルドシステムとオブジェクトファイル: Goのビルドプロセスでは、ソースコードがコンパイルされてオブジェクトファイルが生成されます。これらのオブジェクトファイルは、通常、ターゲットアーキテクチャを示す文字を含む名前を持ちます。例えば、_obj/main.6 のように、.6amd64 アーキテクチャを示します。この慣習は、Goの初期のビルドツール(go tool 6g, go tool 8g など)に由来しており、6amd6483865arm を意味していました。これらの文字は、Goのツールチェーンが内部的に使用するアーキテクチャ識別子として機能します。

  3. gotest ツール: gotest は、Go言語の標準テストフレームワーク (testing パッケージ) を実行するためのコマンドラインツールです。Goのソースコードツリー内の src/cmd/gotest に位置し、テストのコンパイルと実行を管理します。このツールは、テストバイナリをビルドする際に、ターゲットアーキテクチャに応じた適切なビルドフラグや環境変数を設定する必要があります。

  4. build パッケージ: Goの標準ライブラリには、Goのビルドシステムに関する情報を提供する go/build パッケージ(または、より低レベルな cmd/go/internal/build パッケージなど、内部的なビルド関連のユーティリティ)が存在します。このパッケージは、Goのソースツリーの構造、環境変数、ターゲットアーキテクチャに関する情報などをプログラム的に取得するために使用されます。build.ArchChar() のような関数は、このパッケージの一部として、アーキテクチャとそれに対応するビルド文字のマッピングを提供します。

技術的詳細

このコミットの技術的な核心は、gotest ツールがアーキテクチャ固有のオブジェクトファイル文字 (O) を取得する方法を、静的なマップ参照から動的な build.ArchChar() 関数呼び出しへと変更した点にあります。

変更前は、src/cmd/gotest/gotest.go 内に theChar というグローバル変数マップが定義されていました。

// theChar is the map from architecture to object character.
var theChar = map[string]string{
	"arm":   "5",
	"amd64": "6",
	"386":   "8",
}

そして、setEnvironment 関数内で GOARCH 環境変数の値に基づいてこのマップから対応する文字を取得していました。

	O = theChar[GOARCH]
	if O == "" {
		Fatalf("unknown architecture %s", GOARCH)
	}

このアプローチの問題点は、theChar マップがGoがサポートするすべてのアーキテクチャを網羅している必要があり、新しいアーキテクチャが追加された場合にはこのマップを手動で更新しなければならないことでした。また、マップに存在しないアーキテクチャが指定された場合、単純なマップ参照では適切なエラー処理が困難でした。

変更後、theChar マップは完全に削除されました。代わりに、build.ArchChar(GOARCH) 関数が使用されています。

	var err error
	O, err = build.ArchChar(GOARCH)
	if err != nil {
		Fatalf("unknown architecture: %s", err)
	}

build.ArchChar() 関数は、Goのビルドシステムが内部的に管理しているアーキテクチャとオブジェクトファイル文字のマッピングを利用します。この関数は、指定された GOARCH に対応する文字と、エラーが発生した場合にはエラーオブジェクトを返します。これにより、以下の利点が得られます。

  • 中央集権的な管理: アーキテクチャと文字のマッピングがGoのビルドシステム内で一元的に管理されるため、gotest がその詳細を知る必要がなくなります。Goのツールチェーンが新しいアーキテクチャをサポートするようになれば、build.ArchChar() は自動的にそれに対応します。
  • 堅牢なエラーハンドリング: build.ArchChar() はエラーを返すため、gotest はより明確に「未知のアーキテクチャ」というエラーを捕捉し、ユーザーに適切なメッセージを提示できます。これは、単にマップにキーが存在しないことをチェックするよりも、より情報量が多く、エラーの原因を特定しやすいです。
  • コードの簡素化: theChar マップの定義とそれに関連するロジックが不要になり、コードが簡素化されます。

この変更は、Goのツールチェーン全体の一貫性を高め、将来的な拡張性に対応するための重要なリファクタリングと言えます。

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

src/cmd/gotest/gotest.go ファイルが変更されています。

--- a/src/cmd/gotest/gotest.go
+++ b/src/cmd/gotest/gotest.go
@@ -114,13 +114,6 @@ func Fatalf(s string, args ...interface{}) {
 	os.Exit(2)
 }

-// theChar is the map from architecture to object character.
-var theChar = map[string]string{
-	"arm":   "5",
-	"amd64": "6",
-	"386":   "8",
-}
-
 // addEnv adds a name=value pair to the environment passed to subcommands.
 // If the item is already in the environment, addEnv replaces the value.
 func addEnv(name, value string) {
@@ -143,9 +136,10 @@ func setEnvironment() {
 		GOARCH = runtime.GOARCH
 	}
 	addEnv("GOARCH", GOARCH)
-	O = theChar[GOARCH]
-	if O == "" {
-		Fatalf("unknown architecture %s", GOARCH)
+	var err error
+	O, err = build.ArchChar(GOARCH)
+	if err != nil {
+		Fatalf("unknown architecture: %s", err)
 	}

 	// Commands and their flags.

コアとなるコードの解説

変更は主に2つの部分に分けられます。

  1. theChar マップの削除: src/cmd/gotest/gotest.go の117行目から123行目にかけて定義されていた theChar というグローバル変数マップが削除されました。このマップは、"arm": "5", "amd64": "6", "386": "8" のように、Goのアーキテクチャ名とそれに対応するオブジェクトファイル文字をハードコードしていました。このマップが不要になったことで、コードの冗長性が減り、将来のアーキテクチャ追加時のメンテナンスコストが削減されます。

  2. build.ArchChar() の使用: setEnvironment 関数内の O 変数(オブジェクトファイル文字を格納する変数)への値の割り当て方法が変更されました。 変更前は O = theChar[GOARCH] と直接マップから値を取得し、その結果が空文字列であればエラーとしていました。 変更後は、var err error でエラー変数を宣言し、O, err = build.ArchChar(GOARCH) を呼び出して Oerr の両方を受け取っています。 そして、if err != nil というGoの標準的なエラーハンドリングパターンを用いて、build.ArchChar() がエラーを返した場合に Fatalf を呼び出してプログラムを終了させています。エラーメッセージも unknown architecture: %s となり、build.ArchChar() から返された具体的なエラー情報を含むようになりました。

この変更により、gotest はGoのビルドシステムが提供する公式なAPIを通じてアーキテクチャ情報を取得するようになり、より堅牢で将来のGoの進化に対応しやすい設計になりました。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特に go/build パッケージや cmd/go/internal/build 関連のコード)
  • Go言語のコミット履歴とコードレビューコメント
  • Go言語のビルドシステムに関する一般的な知識
  • GOARCH 環境変数に関するGoの公式ドキュメントやチュートリアル
  • Goのツールチェーンにおけるオブジェクトファイル命名規則に関する情報 (例: 6g, 8g, 5g などの古いコンパイラ名)
  • gotest ツールの役割と機能に関する情報