[インデックス 12414] ファイルの概要
このコミットは、Go言語のビルドシステムに関連するテストファイル src/pkg/go/build/deps_test.go
に変更を加えています。具体的には、WindowsおよびPlan 9環境でのビルドテストにおいて、特定のパッケージ(log/syslog
)がエラーを引き起こす既知の問題に対する一時的な修正("band-aid fix")を導入しています。
コミット
commit 9ff00c8fc99b203138747a622f7014dff317c013
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Mon Mar 5 21:33:44 2012 -0800
go/build: fix windows and plan9 builds
Bit of a band-aid fix.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5757045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9ff00c8fc99b2031387747a622f7014dff317c013
元コミット内容
--- a/src/pkg/go/build/deps_test.go
+++ b/src/pkg/go/build/deps_test.go
@@ -349,6 +349,17 @@ var bools = []bool{false, true}\n var geese = []string{"darwin", "freebsd", "linux", "netbsd", "openbsd", "plan9", "windows"}\n var goarches = []string{"386", "amd64", "arm"}\n \n+type osPkg struct {\n+\tgoos, pkg string\n+}\n+\n+// allowedErrors are the operating systems and packages known to contain errors\n+// (currently just "no Go source files")\n+var allowedErrors = map[osPkg]bool{\n+\tosPkg{"windows", "log/syslog"}: true,\n+\tosPkg{"plan9", "log/syslog"}: true,\n+}\n+\n func TestDependencies(t *testing.T) {\n \tvar all []string\n \n@@ -365,6 +376,9 @@ func TestDependencies(t *testing.T) {\n \t\t\t}\n \t\t\tp, err := ctxt.Import(pkg, "", 0)\n \t\t\tif err != nil {\n+\t\t\t\tif allowedErrors[osPkg{ctxt.GOOS, pkg}] {\n+\t\t\t\t\tcontinue\n+\t\t\t\t}\n \t\t\t\t// Some of the combinations we try might not\n \t\t\t\t// be reasonable (like arm,plan9,cgo), so ignore\n \t\t\t\t// errors for the auto-generated combinations.\n```
## 変更の背景
Go言語のビルドシステムは、異なるオペレーティングシステム(OS)やアーキテクチャ(ARCH)の組み合わせでパッケージのインポート可能性をテストする `TestDependencies` 関数を持っています。このテストは、Goのクロスコンパイル能力と、特定の環境に依存するパッケージの挙動を検証するために重要です。
しかし、`log/syslog` パッケージは、その性質上、Unix系システム(Linux, macOSなど)のSyslogデーモンとの連携を前提としています。WindowsやPlan 9といったOSには、ネイティブなSyslog実装が存在しないか、Goの標準ライブラリが直接サポートしていないため、これらの環境で `log/syslog` をインポートしようとすると「Goソースファイルがない」といったエラーが発生します。
このエラーは、`log/syslog` パッケージがOS固有のビルドタグ(例: `// +build linux darwin freebsd netbsd openbsd`)を使用して、サポートされていないOSではコンパイルされないように設計されているためです。`go/build` パッケージの `Import` 関数が、特定のOS/ARCHコンテキストでパッケージを解決しようとした際に、該当するソースファイルが見つからないためにエラーを返していました。
このコミットが行われた2012年3月時点では、これらのエラーがテストの失敗を引き起こし、ビルドの健全性チェックを妨げていました。このコミットは、根本的な解決策ではなく、テストがこれらの既知のエラーを無視して続行できるようにするための「一時しのぎ(band-aid fix)」として導入されました。
## 前提知識の解説
### Go言語のビルドシステム (`go/build` パッケージ)
`go/build` パッケージは、Go言語のソースコードを解析し、パッケージの依存関係を解決するための機能を提供します。これは、`go build` や `go install` といったコマンドの基盤となる重要なパッケージです。
- **パッケージのインポート**: `go/build` パッケージは、指定されたOSやアーキテクチャのコンテキストに基づいて、Goのソースファイルからパッケージをインポートするロジックを扱います。これには、ビルドタグ(`// +build` ディレクティブ)の解釈が含まれます。
- **ビルドタグ**: Goのソースファイルには、特定のOS、アーキテクチャ、Goバージョン、またはカスタムタグに基づいてファイルのコンパイルを制御するためのビルドタグを含めることができます。例えば、`// +build windows` はそのファイルがWindowsでのみコンパイルされることを意味し、`// +build !windows` はWindows以外でコンパイルされることを意味します。
- **`Context` 構造体**: `go/build` パッケージの `Context` 構造体は、現在のビルド環境(`GOOS`, `GOARCH`, `GOROOT`, `GOPATH` など)をカプセル化します。`TestDependencies` では、この `Context` を動的に変更して、様々なOS/ARCHの組み合わせをシミュレートします。
### `log/syslog` パッケージ
`log/syslog` はGoの標準ライブラリの一部であり、Unix系システムで利用可能なSyslogプロトコルを介してログメッセージを送信するための機能を提供します。
- **Syslog**: Syslogは、システムメッセージやイベントログを収集するための標準的なプロトコルです。主にUnix/Linux環境で広く使用されており、システムデーモンやアプリケーションがログメッセージを中央のSyslogサーバーに送信するために利用されます。
- **OS依存性**: `log/syslog` パッケージは、Syslogデーモンとの通信にOS固有のシステムコールやソケット通信メカニズムを使用するため、その実装はOSに強く依存します。WindowsやPlan 9のようなSyslogがネイティブに存在しない環境では、このパッケージは機能しません。Goの標準ライブラリでは、このようなOS依存性をビルドタグで管理し、サポートされていない環境では関連するソースファイルがビルドに含まれないようにしています。
### `deps_test.go` ファイル
`src/pkg/go/build/deps_test.go` は、`go/build` パッケージの依存関係解決ロジックをテストするためのファイルです。
- **`TestDependencies` 関数**: このテスト関数は、Goがサポートする様々なOS (`geese` 変数で定義されている "darwin", "freebsd", "linux", "netbsd", "openbsd", "plan9", "windows") とアーキテクチャ (`goarches` 変数で定義されている "386", "amd64", "arm") の組み合わせを網羅的に試行します。
- **パッケージのインポートテスト**: 各OS/ARCHの組み合わせに対して、Goの標準ライブラリに含まれるすべてのパッケージをインポートしようと試みます。これにより、特定の環境でパッケージのインポートが正しく解決されるか、または意図通りにエラーとなるかを確認します。
- **エラーハンドリング**: 通常、`ctxt.Import(pkg, "", 0)` がエラーを返した場合、それはテストの失敗を意味します。しかし、一部の組み合わせ(例: `arm`, `plan9`, `cgo`)では、そもそも合理的なビルドが期待されないため、エラーが無視されるロジックが既に存在していました。
## 技術的詳細
このコミットの技術的詳細は、`TestDependencies` 関数におけるエラー処理の改善にあります。
1. **`osPkg` 構造体の導入**:
```go
type osPkg struct {
goos, pkg string
}
```
この新しい構造体は、オペレーティングシステム名 (`goos`) とパッケージパス (`pkg`) のペアを表現するために定義されました。これにより、特定のOSと特定のパッケージの組み合わせを一意に識別できるようになります。これは、Goのマップのキーとして使用するために設計されています。
2. **`allowedErrors` マップの導入**:
```go
// allowedErrors are the operating systems and packages known to contain errors
// (currently just "no Go source files")
var allowedErrors = map[osPkg]bool{
osPkg{"windows", "log/syslog"}: true,
osPkg{"plan9", "log/syslog"}: true,
}
```
`allowedErrors` は、`osPkg` をキーとし、`bool` 値を値とするマップです。このマップは、`TestDependencies` が実行中に遭遇してもテストを失敗としない、既知のエラーを持つOSとパッケージの組み合わせを記録するために使用されます。
現在のところ、`windows` と `log/syslog` の組み合わせ、および `plan9` と `log/syslog` の組み合わせが `true` に設定されており、これらの組み合わせでエラーが発生しても許容されることを示しています。コメントにもあるように、これらのエラーは主に「Goソースファイルがない」ことに起因します。
3. **エラー無視ロジックの追加**:
`TestDependencies` 関数内の `ctxt.Import` 呼び出し後のエラーチェック部分に、以下の条件が追加されました。
```go
if err != nil {
if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
continue
}
// Some of the combinations we try might not
// be reasonable (like arm,plan9,cgo), so ignore
// errors for the auto-generated combinations.
```
この変更により、`ctxt.Import` がエラーを返した場合、まず `allowedErrors` マップをチェックします。現在のテストコンテキストの `GOOS` と現在インポートしようとしている `pkg` の組み合わせが `allowedErrors` マップに存在し、その値が `true` であれば、そのエラーは無視され、テストは次のイテレーションに進みます(`continue`)。
これにより、`log/syslog` がWindowsやPlan 9でインポートできないことによるテストの失敗が回避され、他の重要なテスト結果が埋もれることなく確認できるようになります。
この修正は「band-aid fix」(一時しのぎの修正)と明記されています。これは、`log/syslog` がWindowsやPlan 9で動作しないという根本的な問題を解決するものではなく、単にそのエラーがテストを妨げないようにするためのものです。理想的には、`log/syslog` パッケージ自体が、サポートされていないOSではビルドタグによって完全に除外されるか、またはより適切なエラーメッセージを返すように設計されるべきですが、このコミット時点ではテストの安定性を優先した形です。
## コアとなるコードの変更箇所
変更は `src/pkg/go/build/deps_test.go` ファイルに集中しています。
- **新しい型定義**: `osPkg` 構造体が定義されました。
- **新しい変数定義**: `allowedErrors` マップが定義され、`windows` と `plan9` における `log/syslog` の組み合わせが既知のエラーとして登録されました。
- **条件付きエラー処理**: `TestDependencies` 関数内の `ctxt.Import` のエラーチェック部分に、`allowedErrors` マップを参照して既知のエラーをスキップする `if` 文が追加されました。
## コアとなるコードの解説
このコミットの核心は、Goのビルドテストにおける「許容されるエラー」の概念を明示的に導入した点です。
`TestDependencies` は、Goのビルドシステムが様々な環境でどのように動作するかを検証するための包括的なテストです。このテストは、GoがサポートするすべてのOSとアーキテクチャの組み合わせに対して、標準ライブラリのすべてのパッケージをインポートしようと試みます。この網羅的なアプローチは非常に強力ですが、同時に、特定のOSに強く依存するパッケージ(例: `log/syslog`)が、そのOSでサポートされていない場合にエラーを発生させるという問題も引き起こします。
以前は、このようなエラーが発生するとテストが失敗していました。しかし、`log/syslog` のようなパッケージが特定のOSで動作しないのは設計上の意図であり、Goのビルドシステムが正しくその状況を検出していることを意味します。したがって、このエラーは「バグ」ではなく「期待される挙動」と見なされるべきです。
このコミットは、`allowedErrors` マップを導入することで、このような「期待されるエラー」をテストフレームワークに明示的に認識させます。`osPkg` 構造体は、OSとパッケージの組み合わせをキーとして使用できるようにするためのシンプルなラッパーです。
```go
if err != nil { // エラーが発生した場合
if allowedErrors[osPkg{ctxt.GOOS, pkg}] { // 現在のOSとパッケージの組み合わせがallowedErrorsマップに存在するか?
continue // 存在すれば、このエラーは許容されるので、次のテストケースへスキップ
}
// それ以外のエラーは、引き続きテスト失敗として扱う
}
このロジックにより、log/syslog
がWindowsやPlan 9でインポートできないことによるテストの失敗が抑制され、テストスイート全体の安定性が向上しました。これにより、開発者は本当に修正が必要なビルドエラーに集中できるようになります。
「Bit of a band-aid fix.」というコミットメッセージは、この修正が根本的な解決策ではないことを示唆しています。理想的には、log/syslog
のようなOS依存パッケージは、サポートされていない環境ではビルドシステムによって完全に無視されるべきであり、インポート時にエラーを発生させるべきではありません。しかし、テストの安定性を確保するためには、このような一時的な回避策が必要でした。これは、ソフトウェア開発において、完璧な解決策がすぐに利用できない場合に、実用的な妥協点を見つけることの重要性を示しています。
関連リンク
- Go言語の
go/build
パッケージのドキュメント: https://pkg.go.dev/go/build - Go言語の
log/syslog
パッケージのドキュメント: https://pkg.go.dev/log/syslog - Go言語のビルドタグに関する公式ドキュメント(
go doc build
コマンドで確認できる内容)
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコードリポジトリ
- Syslogプロトコルに関する一般的な情報源 (RFC 5424など)
- Go言語のビルドプロセスとクロスコンパイルに関する技術記事