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

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

このコミットは、Go言語のコマンドラインツール go test における cgo パッケージの取り扱いに関するバグ修正です。具体的には、go test -i コマンドが cgo パッケージを正しく処理し、特に runtime/cgo パッケージ自体が古い場合に適切に再ビルドされるようにするための変更が含まれています。

コミット

commit 9c1f54c9ed67b77385940c58fb15af18166d4840
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Wed Feb 15 13:26:22 2012 -0500

    cmd/go: go test -i correctly handle cgo packages
    Previous CL (5674043) omit the case where runtime/cgo itself is out-of-date.
    Fixes #2936 (again).
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/5674048

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

https://github.com/golang/go/commit/9c1f54c9ed67b77385940c58fb15af18166d4840

元コミット内容

cmd/go: go test -i correctly handle cgo packagescmd/go: go test -icgo パッケージを正しく処理するようにする)

Previous CL (5674043) omit the case where runtime/cgo itself is out-of-date. (以前の変更リスト (5674043) は、runtime/cgo 自体が古いケースを見落としていた。)

Fixes #2936 (again). (Issue #2936 を(再び)修正。)

変更の背景

このコミットは、Go言語のビルドシステムにおける cgo パッケージの依存関係解決に関する既存のバグを修正するために行われました。特に、go test -i コマンド(テストに必要な依存関係をインストールするオプション)を使用する際に、cgo を利用するパッケージのテストが正しく動作しない問題がありました。

以前の変更リスト (CL 5674043) では、この問題の一部が修正されましたが、runtime/cgo パッケージ自体が古い(つまり、再ビルドが必要な)場合に、そのケースが考慮されていませんでした。これにより、cgo を使用するテストが、runtime/cgo の古いバージョンに依存してしまい、期待通りに動作しない、またはビルドエラーが発生する可能性がありました。

このコミットは、Go Issue #2936 に関連しており、この問題が以前にも報告され、修正が試みられたものの、完全に解決されていなかったことを示唆しています。今回の修正は、runtime/cgo の更新が必要なシナリオを明示的に考慮に入れることで、より堅牢な cgo パッケージの依存関係解決を実現し、go test -i の信頼性を向上させることを目的としています。

前提知識の解説

Go言語のビルドシステムとパッケージ管理

Go言語は、go buildgo installgo test といったコマンドを通じて、ソースコードのコンパイル、パッケージのインストール、テストの実行を行います。これらのコマンドは、Goのワークスペース(GOPATH)やモジュールシステム(Go Modules)に基づいて、依存関係を自動的に解決し、必要なパッケージをビルドします。

go test -i コマンド

go test コマンドは、Goパッケージのテストを実行するために使用されます。-i フラグは、テストを実行する前に、テスト対象のパッケージとその依存関係をインストール(ビルドしてGOPATH/pkgまたはモジュールキャッシュに配置)することを指示します。これにより、テストの実行が高速化されたり、特定のビルド環境での依存関係の問題を回避したりできます。

cgo とは

cgo は、GoプログラムからC言語のコードを呼び出すためのGoの機能です。これにより、既存のCライブラリをGoプロジェクトで再利用したり、Goでは実装が難しい低レベルの操作を行ったりすることが可能になります。cgo を使用するGoパッケージは、通常のGoコードとは異なり、Cコンパイラ(通常はGCCやClang)とGoコンパイラの両方によって処理される必要があります。

cgo を使用するパッケージは、import "C" という特別なインポート宣言を含みます。この宣言は、Goのビルドツールに対して、そのパッケージがCコードを含んでおり、cgo ツールによる特別な処理が必要であることを伝えます。

runtime/cgo パッケージ

runtime/cgo は、GoランタイムとCコード間の相互運用を管理する内部パッケージです。cgo を使用するすべてのGoプログラムは、この runtime/cgo パッケージに暗黙的に依存します。このパッケージは、C関数呼び出しのスタック管理、GoとCのメモリモデルの調整、スレッドの管理など、cgo の低レベルなメカニズムを提供します。

依存関係グラフとビルド順序

Goのビルドシステムは、パッケージ間の依存関係を解決し、正しい順序でビルドを行います。あるパッケージが別のパッケージに依存している場合、依存先のパッケージが先にビルドされる必要があります。cgo を使用するパッケージの場合、その依存関係グラフには runtime/cgo が含まれます。

Go Issue #2936

Go Issue #2936 は、go test -i コマンドが cgo パッケージの依存関係を正しく処理しないというバグを追跡するために作成されたものです。この問題は、特に runtime/cgo パッケージが再ビルドを必要とする場合に顕在化し、テストの失敗やビルドエラーを引き起こしていました。

技術的詳細

このコミットの技術的な核心は、go test -i コマンドがパッケージの依存関係を解決する際に、cgo を使用するパッケージの特別なケースを適切に処理することにあります。

Goのビルドシステムでは、パッケージの依存関係は内部的にマップ(deps)として管理されます。このマップには、ビルド対象のパッケージが依存するすべてのパッケージが含まれます。cgo を使用するパッケージは、Goのソースコード内で import "C" と記述することで、C言語のコードとの連携を示します。しかし、この "C" は実際のGoパッケージではなく、cgo ツールに対する指示です。

以前の go test の実装では、"C" という擬似パッケージが依存関係リストに含まれていた場合、それを単に無視していました。これは、"C" 自体がビルドされるべきパッケージではないため、一見正しいように見えます。しかし、cgo を使用するパッケージは、実際には runtime/cgo パッケージに依存しており、さらに、クロスコンパイル環境でない限り、cmd/cgo ツールにも依存します。

このコミットの修正前は、deps["C"] が存在する場合に delete(deps, "C") が行われていましたが、これは runtime/cgocmd/cgo への依存関係を明示的に追加する処理の前に実行されていました。その結果、runtime/cgo が古い場合でも、その依存関係が正しく認識されず、再ビルドがトリガーされないという問題が発生していました。

今回の修正では、"C" が依存関係リストに存在する場合、それを runtime/cgocmd/cgo(ホストOS/アーキテクチャとターゲットOS/アーキテクチャが一致する場合)に変換するように変更されました。これにより、cgo を使用するパッケージのビルド時に、runtime/cgo が最新の状態であることが保証され、必要に応じて再ビルドが実行されるようになります。

特に重要なのは、buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH という条件です。これは、現在のビルドがホスト環境(つまり、クロスコンパイルではない)で行われている場合にのみ cmd/cgo への依存関係を追加することを示しています。クロスコンパイルの場合、cmd/cgo はホスト上で実行されるため、ターゲット環境の依存関係としては不要です。

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

変更は src/cmd/go/test.go ファイルに集中しています。

--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -15,6 +15,7 @@ import (
 	"os/exec"
 	"path"
 	"path/filepath"
+	"runtime"
 	"sort"
 	"strings"
 	"text/template"
@@ -273,8 +274,15 @@ func runTest(cmd *Command, args []string) {
 			}
 		}
 
+		// translate C to runtime/cgo
+		if deps["C"] {
+			delete(deps, "C")
+			deps["runtime/cgo"] = true
+			if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH {
+				deps["cmd/cgo"] = true
+			}
+		}
 		// Ignore pseudo-packages.
-		delete(deps, "C")
 		delete(deps, "unsafe")
 
 		all := []string{}

コアとなるコードの解説

  1. import "runtime" の追加: runtime パッケージが新しくインポートされています。これは、runtime.GOOSruntime.GOARCH を使用して、現在の実行環境のOSとアーキテクチャを判定するために必要です。

  2. // translate C to runtime/cgo ブロックの追加: この新しいコードブロックが、既存の delete(deps, "C") の行のに挿入されています。

    • if deps["C"] { ... }: deps マップに "C" というキーが存在するかどうかを確認します。これは、テスト対象のパッケージが cgo を使用していることを意味します。
    • delete(deps, "C"): まず、擬似パッケージである "C" を依存関係リストから削除します。これは以前の動作と同じですが、重要なのはこの削除が runtime/cgo への依存関係を追加する前に行われることです。
    • deps["runtime/cgo"] = true: cgo を使用するパッケージは必ず runtime/cgo に依存するため、この依存関係を明示的に追加します。これにより、runtime/cgo が必要に応じてビルドされるようになります。
    • if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH { deps["cmd/cgo"] = true }: この条件は、現在のビルドがクロスコンパイルではない(つまり、ビルドターゲットのOSとアーキテクチャが現在の実行環境のOSとアーキテクチャと同じである)場合にのみ真となります。この場合、cmd/cgo ツール自体もビルド依存関係として追加されます。cmd/cgocgo コードを処理するためのツールであり、ホスト環境で実行されるため、クロスコンパイル時にはターゲットの依存関係としては不要です。
  3. 既存の delete(deps, "C") の削除: 新しいブロックで "C" の削除と変換が行われるため、以前の delete(deps, "C") の行は不要となり、削除されました。

この変更により、go test -icgo を使用するパッケージの依存関係をより正確に解決し、特に runtime/cgo が古い場合に適切に再ビルドをトリガーできるようになりました。これにより、Go Issue #2936 で報告された問題が根本的に解決されます。

関連リンク

参考にした情報源リンク

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

このコミットは、Go言語のコマンドラインツール go test における cgo パッケージの取り扱いに関するバグ修正です。具体的には、go test -i コマンドが cgo パッケージを正しく処理し、特に runtime/cgo パッケージ自体が古い場合に適切に再ビルドされるようにするための変更が含まれています。

コミット

commit 9c1f54c9ed67b77385940c58fb15af18166d4840
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Wed Feb 15 13:26:22 2012 -0500

    cmd/go: go test -i correctly handle cgo packages
    Previous CL (5674043) omit the case where runtime/cgo itself is out-of-date.
    Fixes #2936 (again).
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/5674048

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

https://github.com/golang/go/commit/9c1f54c9ed67b77385940c58fb15af18166d4840

元コミット内容

cmd/go: go test -i correctly handle cgo packagescmd/go: go test -icgo パッケージを正しく処理するようにする)

Previous CL (5674043) omit the case where runtime/cgo itself is out-of-date. (以前の変更リスト (5674043) は、runtime/cgo 自体が古いケースを見落としていた。)

Fixes #2936 (again). (Issue #2936 を(再び)修正。)

変更の背景

このコミットは、Go言語のビルドシステムにおける cgo パッケージの依存関係解決に関する既存のバグを修正するために行われました。特に、go test -i コマンド(テストに必要な依存関係をインストールするオプション)を使用する際に、cgo を利用するパッケージのテストが正しく動作しない問題がありました。

以前の変更リスト (CL 5674043) では、この問題の一部が修正されましたが、runtime/cgo パッケージ自体が古い(つまり、再ビルドが必要な)場合に、そのケースが考慮されていませんでした。これにより、cgo を使用するテストが、runtime/cgo の古いバージョンに依存してしまい、期待通りに動作しない、またはビルドエラーが発生する可能性がありました。

このコミットは、Go Issue #2936 に関連しており、この問題が以前にも報告され、修正が試みられたものの、完全に解決されていなかったことを示唆しています。今回の修正は、runtime/cgo の更新が必要なシナリオを明示的に考慮に入れることで、より堅牢な cgo パッケージの依存関係解決を実現し、go test -i の信頼性を向上させることを目的としています。

前提知識の解説

Go言語のビルドシステムとパッケージ管理

Go言語は、go buildgo installgo test といったコマンドを通じて、ソースコードのコンパイル、パッケージのインストール、テストの実行を行います。これらのコマンドは、Goのワークスペース(GOPATH)やモジュールシステム(Go Modules)に基づいて、依存関係を自動的に解決し、必要なパッケージをビルドします。

go test -i コマンド

go test コマンドは、Goパッケージのテストを実行するために使用されます。-i フラグは、テストを実行する前に、テスト対象のパッケージとその依存関係をインストール(ビルドしてGOPATH/pkgまたはモジュールキャッシュに配置)することを指示します。これにより、テストの実行が高速化されたり、特定のビルド環境での依存関係の問題を回避したりできます。

cgo とは

cgo は、GoプログラムからC言語のコードを呼び出すためのGoの機能です。これにより、既存のCライブラリをGoプロジェクトで再利用したり、Goでは実装が難しい低レベルの操作を行ったりすることが可能になります。cgo を使用するGoパッケージは、通常のGoコードとは異なり、Cコンパイラ(通常はGCCやClang)とGoコンパイラの両方によって処理される必要があります。

cgo を使用するパッケージは、import "C" という特別なインポート宣言を含みます。この宣言は、Goのビルドツールに対して、そのパッケージがCコードを含んでおり、cgo ツールによる特別な処理が必要であることを伝えます。

runtime/cgo パッケージ

runtime/cgo は、GoランタイムとCコード間の相互運用を管理する内部パッケージです。cgo を使用するすべてのGoプログラムは、この runtime/cgo パッケージに暗黙的に依存します。このパッケージは、C関数呼び出しのスタック管理、GoとCのメモリモデルの調整、スレッドの管理など、cgo の低レベルなメカニズムを提供します。

依存関係グラフとビルド順序

Goのビルドシステムは、パッケージ間の依存関係を解決し、正しい順序でビルドを行います。あるパッケージが別のパッケージに依存している場合、依存先のパッケージが先にビルドされる必要があります。cgo を使用するパッケージの場合、その依存関係グラフには runtime/cgo が含まれます。

Go Issue #2936

Go Issue #2936 は、go test -i コマンドが cgo パッケージの依存関係を正しく処理しないというバグを追跡するために作成されたものです。この問題は、特に runtime/cgo パッケージが再ビルドを必要とする場合に顕在化し、テストの失敗やビルドエラーを引き起こしていました。Web検索の結果によると、この問題は go test -iimport 'C' の行で失敗し、「can't load package: C: package could not be found locally」のようなエラーが発生するというものでした。

技術的詳細

このコミットの技術的な核心は、go test -i コマンドがパッケージの依存関係を解決する際に、cgo を使用するパッケージの特別なケースを適切に処理することにあります。

Goのビルドシステムでは、パッケージの依存関係は内部的にマップ(deps)として管理されます。このマップには、ビルド対象のパッケージが依存するすべてのパッケージが含まれます。cgo を使用するパッケージは、Goのソースコード内で import "C" と記述することで、C言語のコードとの連携を示します。しかし、この "C" は実際のGoパッケージではなく、cgo ツールに対する指示です。

以前の go test の実装では、"C" という擬似パッケージが依存関係リストに含まれていた場合、それを単に無視していました。これは、"C" 自体がビルドされるべきパッケージではないため、一見正しいように見えます。しかし、cgo を使用するパッケージは、実際には runtime/cgo パッケージに依存しており、さらに、クロスコンパイル環境でない限り、cmd/cgo ツールにも依存します。

このコミットの修正前は、deps["C"] が存在する場合に delete(deps, "C") が行われていましたが、これは runtime/cgocmd/cgo への依存関係を明示的に追加する処理の前に実行されていました。その結果、runtime/cgo が古い場合でも、その依存関係が正しく認識されず、再ビルドがトリガーされないという問題が発生していました。

今回の修正では、"C" が依存関係リストに存在する場合、それを runtime/cgocmd/cgo(ホストOS/アーキテクチャとターゲットOS/アーキテクチャが一致する場合)に変換するように変更されました。これにより、cgo を使用するパッケージのビルド時に、runtime/cgo が最新の状態であることが保証され、必要に応じて再ビルドが実行されるようになります。

特に重要なのは、buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH という条件です。これは、現在のビルドがホスト環境(つまり、クロスコンパイルではない)で行われている場合にのみ cmd/cgo への依存関係を追加することを示しています。クロスコンパイルの場合、cmd/cgo はホスト上で実行されるため、ターゲット環境の依存関係としては不要です。

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

変更は src/cmd/go/test.go ファイルに集中しています。

--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -15,6 +15,7 @@ import (
 	"os/exec"
 	"path"
 	"path/filepath"
+	"runtime"
 	"sort"
 	"strings"
 	"text/template"
@@ -273,8 +274,15 @@ func runTest(cmd *Command, args []string) {
 			}
 		}
 
+		// translate C to runtime/cgo
+		if deps["C"] {
+			delete(deps, "C")
+			deps["runtime/cgo"] = true
+			if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH {
+				deps["cmd/cgo"] = true
+			}
+		}
 		// Ignore pseudo-packages.
-		delete(deps, "C")
 		delete(deps, "unsafe")
 
 		all := []string{}

コアとなるコードの解説

  1. import "runtime" の追加: runtime パッケージが新しくインポートされています。これは、runtime.GOOSruntime.GOARCH を使用して、現在の実行環境のOSとアーキテクチャを判定するために必要です。

  2. // translate C to runtime/cgo ブロックの追加: この新しいコードブロックが、既存の delete(deps, "C") の行のに挿入されています。

    • if deps["C"] { ... }: deps マップに "C" というキーが存在するかどうかを確認します。これは、テスト対象のパッケージが cgo を使用していることを意味します。
    • delete(deps, "C"): まず、擬似パッケージである "C" を依存関係リストから削除します。これは以前の動作と同じですが、重要なのはこの削除が runtime/cgo への依存関係を追加する前に行われることです。
    • deps["runtime/cgo"] = true: cgo を使用するパッケージは必ず runtime/cgo に依存するため、この依存関係を明示的に追加します。これにより、runtime/cgo が必要に応じてビルドされるようになります。
    • if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH { deps["cmd/cgo"] = true }: この条件は、現在のビルドがクロスコンパイルではない(つまり、ビルドターゲットのOSとアーキテクチャが現在の実行環境のOSとアーキテクチャと同じである)場合にのみ真となります。この場合、cmd/cgo ツール自体もビルド依存関係として追加されます。cmd/cgocgo コードを処理するためのツールであり、ホスト環境で実行されるため、クロスコンパイル時にはターゲットの依存関係としては不要です。
  3. 既存の delete(deps, "C") の削除: 新しいブロックで "C" の削除と変換が行われるため、以前の delete(deps, "C") の行は不要となり、削除されました。

この変更により、go test -icgo を使用するパッケージの依存関係をより正確に解決し、特に runtime/cgo が古い場合に適切に再ビルドをトリガーできるようになりました。これにより、Go Issue #2936 で報告された問題が根本的に解決されます。

関連リンク

参考にした情報源リンク