[インデックス 12785] ファイルの概要
このコミットは、Go言語のビルドシステムにおけるパッケージインポートのチェックに関するバグ修正です。具体的には、go/buildパッケージ内のContext.Import関数が、GOROOT配下のパッケージの存在確認を行う際に、誤ったパスを参照していた問題を修正しています。これにより、一部の標準ライブラリパッケージが正しく認識されず、インポートできない、または意図しないパッケージが優先される可能性がありました。
コミット
commit 671862747ef238f1713170f712e85d1cd6d46685
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 27 11:16:10 2012 -0400
go/build: fix import check
When we find a package in DIR/src/foo, we only let it
be known as foo if there is no other foo in an earlier
GOPATH directory or the GOROOT directory.
The GOROOT check was looking in GOROOT/src/foo
instead of GOROOT/src/pkg/foo, which meant that
the import paths "lib9", "libbio", "libmach", and so
on were unavailable, and the import paths "math",
"errors", and so on were available. Correct this.
Fixes #3390.
R=golang-dev, minux.ma
CC=golang-dev
https://golang.org/cl/5927050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/671862747ef238f1713170f712e85d1cd6d46685
元コミット内容
このコミットは、Go言語のビルドシステムがパッケージを解決する際のロジック、特にGOROOT内のパッケージの検索パスに関する問題を修正しています。
コミットメッセージによると、DIR/src/fooのようなパスでパッケージが見つかった場合、それがfooとして認識されるのは、より優先順位の高いGOPATHディレクトリやGOROOTディレクトリに同じ名前のfooが存在しない場合に限られます。
問題は、GOROOT内のチェックがGOROOT/src/fooというパスを見ていた点にありました。しかし、Goの標準ライブラリパッケージは通常GOROOT/src/pkg/fooのような構造で配置されています。このパスの不一致により、lib9, libbio, libmachといった一部のパッケージが正しくインポートできず、一方でmath, errorsといった他のパッケージは利用可能であるという矛盾が生じていました。
このコミットは、GOROOT内のパッケージチェックのパスをGOROOT/src/pkg/fooに修正することで、この問題を解決しています。
変更の背景
この変更の背景には、Go言語のパッケージ管理とビルドシステムにおけるパス解決の厳密性があります。Goのビルドツールは、ソースコードをコンパイルする際に、インポートパスに基づいて必要なパッケージを見つけ出します。この検索順序とパスの正確性は、ビルドの再現性と信頼性を保証するために非常に重要です。
コミットメッセージにFixes #3390とあることから、この問題はGitHubのIssueトラッカーで報告されていたバグであることがわかります。当時のGoのビルドシステムでは、GOROOT内のパッケージの検索ロジックに誤りがあり、特定の標準ライブラリパッケージ(特にlib9, libbio, libmachなど、Goの初期のシステムプログラミングに関連する低レベルライブラリ)が正しく解決されないという問題が発生していました。これは、開発者がこれらのパッケージをインポートしようとした際に、ビルドエラーや予期せぬ動作を引き起こす可能性がありました。
この修正は、GoのビルドシステムがGOROOT内の標準パッケージを正しく識別し、インポートの競合解決ロジックが意図通りに機能するようにするために不可欠でした。
前提知識の解説
このコミットを理解するためには、以下のGo言語の基本的な概念とビルドシステムに関する知識が必要です。
-
Go言語のパッケージシステム:
- Goのコードは「パッケージ」という単位で整理されます。パッケージは関連する機能の集合であり、再利用可能なコードの最小単位です。
- 他のパッケージの機能を利用するには、
import "path/to/package"という形式でインポート宣言を行います。 - インポートパスは、通常、ファイルシステム上のディレクトリ構造に対応しています。
-
GOROOT:GOROOTは、Go言語のSDK(コンパイラ、標準ライブラリ、ツールなど)がインストールされているルートディレクトリを指す環境変数です。- 標準ライブラリのソースコードは、通常
$GOROOT/src/pkg(Go 1.4以前)または$GOROOT/src(Go 1.5以降)以下に配置されています。このコミットが作成された2012年時点では、$GOROOT/src/pkgが標準的な配置でした。 - ビルドツールは、まず
GOROOT内のパッケージを検索します。
-
GOPATH:GOPATHは、Goのワークスペースのルートディレクトリを指す環境変数です。Go 1.11のGo Modules導入以前は、Goプロジェクトのソースコード、コンパイル済みバイナリ、パッケージの依存関係を管理するための主要なメカニズムでした。GOPATHは複数のパスを設定でき、ビルドツールはこれらのパスを順に検索してパッケージを見つけます。GOPATH内のディレクトリ構造は、通常$GOPATH/src(ソースコード)、$GOPATH/pkg(コンパイル済みパッケージ)、$GOPATH/bin(コンパイル済みコマンド)となります。- ビルドツールは、
GOROOTの次にGOPATH内のパッケージを検索します。
-
go/buildパッケージ:- Goの標準ライブラリの一部である
go/buildパッケージは、Goのソースコードを解析し、パッケージの依存関係を解決するための機能を提供します。 go buildコマンドなどのGoツールチェインの基盤となるパッケージであり、Goのソースファイルやディレクトリ構造を理解し、インポートパスを解決するロジックを含んでいます。Context構造体は、ビルド環境のコンテキスト(GOROOT,GOPATHなど)を保持し、Importメソッドは指定されたインポートパスに対応するパッケージを検索・解決する役割を担います。
- Goの標準ライブラリの一部である
-
インポートパスの解決順序:
- Goのビルドツールは、インポートパスを解決する際に特定の優先順位でディレクトリを検索します。一般的には、
GOROOT内の標準ライブラリが最も優先され、次にGOPATH内のパッケージ、そして現在のプロジェクト内の相対パスが考慮されます。 - このコミットの文脈では、「
DIR/src/fooでパッケージが見つかった場合でも、より優先順位の高いGOPATHやGOROOTに同じ名前のfooが存在しない場合にのみ、それがfooとして認識される」というロジックが重要です。これは、名前の衝突を避け、意図しないパッケージがインポートされるのを防ぐためのものです。
- Goのビルドツールは、インポートパスを解決する際に特定の優先順位でディレクトリを検索します。一般的には、
技術的詳細
このコミットは、go/buildパッケージのContext.Importメソッド内のロジックに焦点を当てています。このメソッドは、Goのソースコードがimport文で指定するパスを解決し、対応するパッケージの情報を返す役割を担っています。
問題の箇所は、Context.Importメソッドが、特定のパッケージ(sub変数で表される)がGOROOT内に存在するかどうかを確認する部分です。このチェックは、現在のディレクトリで見つかったパッケージが、GOROOT内のより優先されるパッケージと競合しないことを確認するために行われます。
修正前のコードでは、GOROOT内のパッケージのパスを構築する際に、ctxt.joinPath(ctxt.GOROOT, "src", sub)という形式を使用していました。これは、$GOROOT/src/lib9のようなパスを生成します。しかし、当時のGoの標準ライブラリの配置は、$GOROOT/src/pkg/lib9のように、srcの下にさらにpkgディレクトリを挟む構造になっていました。
このパスの不一致が原因で、go/buildツールはlib9などのパッケージをGOROOT内で見つけることができませんでした。その結果、これらのパッケージは「利用不可」と判断され、インポートエラーが発生するか、あるいはGOPATH内の同名のパッケージが誤って優先されてしまう可能性がありました。
一方で、mathやerrorsのような一部のパッケージは、GOROOT/src/pkg/mathやGOROOT/src/pkg/errorsといったパスに存在していましたが、これらのパッケージはGOROOT/src/mathのようなパスでも偶然見つかることがあったため、問題が顕在化しにくかったと考えられます。
このコミットは、GOROOT内のパッケージパスの構築をctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub)に変更することで、この問題を解決しました。これにより、$GOROOT/src/pkg/lib9のような正しいパスが生成され、go/buildツールがGOROOT内の標準ライブラリパッケージを正確に識別できるようになりました。
この修正は、Goのビルドシステムの堅牢性を高め、パッケージインポートの予測可能性と信頼性を向上させる上で重要なものでした。
コアとなるコードの変更箇所
変更はsrc/pkg/go/build/build.goファイルの一箇所のみです。
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -387,7 +387,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
// but check that using it wouldn't find something
// else first.
if ctxt.GOROOT != "" {
- if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
+ if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) {
goto Found
}
}
具体的には、389行目のctxt.joinPathの呼び出しにおいて、引数に"pkg"が追加されています。
コアとなるコードの解説
変更された行は、Context.Importメソッド内で、GOROOT内に特定のサブパッケージ(sub変数で表される)が存在するかどうかを確認する条件分岐の一部です。
if ctxt.GOROOT != "":GOROOT環境変数が設定されている場合にのみ、このチェックを実行します。ctxt.joinPath(...): これは、Goのビルドコンテキスト(ctxt)が提供するヘルパー関数で、与えられたパス要素を結合して完全なファイルシステムパスを構築します。ctxt.isDir(dir): 構築されたパスdirが実際にディレクトリとして存在するかどうかを確認します。
変更前:
if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
この行は、$GOROOT/src/<sub_package_name>というパスを構築し、それがディレクトリであるかを確認していました。例えば、subが"lib9"であれば、$GOROOT/src/lib9をチェックします。しかし、当時のGoの標準ライブラリは$GOROOT/src/pkg/lib9に存在していたため、このチェックは失敗していました。
変更後:
if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) {
この行は、$GOROOT/src/pkg/<sub_package_name>という正しいパスを構築し、それがディレクトリであるかを確認するように修正されました。例えば、subが"lib9"であれば、$GOROOT/src/pkg/lib9をチェックします。これにより、GOROOT内の標準ライブラリパッケージが正しく検出されるようになりました。
goto Found: もしGOROOT内で該当するパッケージが見つかった場合、Foundラベルにジャンプし、それ以上他の場所(例えばGOPATH)を検索する必要がないことを示します。これは、GOROOT内のパッケージが最も優先されるべきであるというGoのパッケージ解決の原則に基づいています。
この修正は、Goのビルドシステムがパッケージのインポートパスを解決する際の正確性を保証し、特にGOROOT内の標準ライブラリの検出に関する問題を解決する上で非常に重要でした。
関連リンク
- Go Issue #3390: https://github.com/golang/go/issues/3390 (このコミットが修正したIssue)
- Gerrit Change-Id:
5927050(GoプロジェクトのGerritレビューシステムにおける変更のID)
参考にした情報源リンク
- Go言語の公式ドキュメント (当時のバージョンに関する情報): https://go.dev/doc/
- Go Modules以前の
GOPATHに関する情報: https://go.dev/doc/code go/buildパッケージのドキュメント: https://pkg.go.dev/go/build- Go言語のソースコードリポジトリ: https://github.com/golang/go
- Russ CoxのブログやGoに関する発表 (当時のGoの設計思想や変更の背景を理解するため): https://research.swtch.com/ (一般的な情報源として)
- Goの歴史的な変更に関する情報 (Go 1.5での
GOROOT構造の変更など): https://go.dev/doc/go1.5 (Go 1.5は2015年リリースなので、このコミットの2012年時点とは異なるが、Goのパス解決の変遷を理解する上で参考になる) - GoのIssueトラッカー: https://github.com/golang/go/issues (Issue #3390の詳細を確認するため)
- GoのGerritコードレビューシステム: https://go-review.googlesource.com/ (変更リスト
5927050の詳細を確認するため)
[インデックス 12785] ファイルの概要
このコミットは、Go言語のビルドシステムにおけるパッケージインポートのチェックに関するバグ修正です。具体的には、go/buildパッケージ内のContext.Import関数が、GOROOT配下のパッケージの存在確認を行う際に、誤ったパスを参照していた問題を修正しています。これにより、一部の標準ライブラリパッケージが正しく認識されず、インポートできない、または意図しないパッケージが優先される可能性がありました。
コミット
commit 671862747ef238f1713170f712e85d1cd6d46685
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 27 11:16:10 2012 -0400
go/build: fix import check
When we find a package in DIR/src/foo, we only let it
be known as foo if there is no other foo in an earlier
GOPATH directory or the GOROOT directory.
The GOROOT check was looking in GOROOT/src/foo
instead of GOROOT/src/pkg/foo, which meant that
the import paths "lib9", "libbio", "libmach", and so
on were unavailable, and the import paths "math",
"errors", and so on were available. Correct this.
Fixes #3390.
R=golang-dev, minux.ma
CC=golang-dev
https://golang.org/cl/5927050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/671862747ef238f1713170f712e85d1cd6d46685
元コミット内容
このコミットは、Go言語のビルドシステムがパッケージを解決する際のロジック、特にGOROOT内のパッケージの検索パスに関する問題を修正しています。
コミットメッセージによると、DIR/src/fooのようなパスでパッケージが見つかった場合、それがfooとして認識されるのは、より優先順位の高いGOPATHディレクトリやGOROOTディレクトリに同じ名前のfooが存在しない場合に限られます。
問題は、GOROOT内のチェックがGOROOT/src/fooというパスを見ていた点にありました。しかし、Goの標準ライブラリパッケージは通常GOROOT/src/pkg/fooのような構造で配置されていました(このコミットが作成された2012年時点)。このパスの不一致により、lib9, libbio, libmachといった一部のパッケージが正しくインポートできず、一方でmath, errorsといった他のパッケージは利用可能であるという矛盾が生じていました。
このコミットは、GOROOT内のパッケージチェックのパスをGOROOT/src/pkg/fooに修正することで、この問題を解決しています。
変更の背景
この変更の背景には、Go言語のパッケージ管理とビルドシステムにおけるパス解決の厳密性があります。Goのビルドツールは、ソースコードをコンパイルする際に、インポートパスに基づいて必要なパッケージを見つけ出します。この検索順序とパスの正確性は、ビルドの再現性と信頼性を保証するために非常に重要です。
コミットメッセージにFixes #3390とあることから、この問題はGitHubのIssueトラッカーで報告されていたバグであることがわかります。当時のGoのビルドシステムでは、GOROOT内のパッケージの検索ロジックに誤りがあり、特定の標準ライブラリパッケージ(特にlib9, libbio, libmachなど、Goの初期のシステムプログラミングに関連する低レベルライブラリ)が正しく解決されないという問題が発生していました。これは、開発者がこれらのパッケージをインポートしようとした際に、ビルドエラーや予期せぬ動作を引き起こす可能性がありました。
この修正は、GoのビルドシステムがGOROOT内の標準パッケージを正しく識別し、インポートの競合解決ロジックが意図通りに機能するようにするために不可欠でした。
前提知識の解説
このコミットを理解するためには、以下のGo言語の基本的な概念とビルドシステムに関する知識が必要です。
-
Go言語のパッケージシステム:
- Goのコードは「パッケージ」という単位で整理されます。パッケージは関連する機能の集合であり、再利用可能なコードの最小単位です。
- 他のパッケージの機能を利用するには、
import "path/to/package"という形式でインポート宣言を行います。 - インポートパスは、通常、ファイルシステム上のディレクトリ構造に対応しています。
-
GOROOT:GOROOTは、Go言語のSDK(コンパイラ、標準ライブラリ、ツールなど)がインストールされているルートディレクトリを指す環境変数です。- 2012年当時、Goの標準ライブラリのソースコードは、通常
$GOROOT/src/pkg以下に配置されていました。 - ビルドツールは、まず
GOROOT内のパッケージを検索します。
-
GOPATH:GOPATHは、Goのワークスペースのルートディレクトリを指す環境変数です。Go 1.11のGo Modules導入以前は、Goプロジェクトのソースコード、コンパイル済みバイナリ、パッケージの依存関係を管理するための主要なメカニズムでした。GOPATHは複数のパスを設定でき、ビルドツールはこれらのパスを順に検索してパッケージを見つけます。GOPATH内のディレクトリ構造は、通常$GOPATH/src(ソースコード)、$GOPATH/pkg(コンパイル済みパッケージ)、$GOPATH/bin(コンパイル済みコマンド)となります。- ビルドツールは、
GOROOTの次にGOPATH内のパッケージを検索します。
-
go/buildパッケージ:- Goの標準ライブラリの一部である
go/buildパッケージは、Goのソースコードを解析し、パッケージの依存関係を解決するための機能を提供します。 go buildコマンドなどのGoツールチェインの基盤となるパッケージであり、Goのソースファイルやディレクトリ構造を理解し、インポートパスを解決するロジックを含んでいます。Context構造体は、ビルド環境のコンテキスト(GOROOT,GOPATHなど)を保持し、Importメソッドは指定されたインポートパスに対応するパッケージを検索・解決する役割を担います。
- Goの標準ライブラリの一部である
-
インポートパスの解決順序:
- Goのビルドツールは、インポートパスを解決する際に特定の優先順位でディレクトリを検索します。一般的には、
GOROOT内の標準ライブラリが最も優先され、次にGOPATH内のパッケージ、そして現在のプロジェクト内の相対パスが考慮されます。 - このコミットの文脈では、「
DIR/src/fooでパッケージが見つかった場合でも、より優先順位の高いGOPATHやGOROOTに同じ名前のfooが存在しない場合にのみ、それがfooとして認識される」というロジックが重要です。これは、名前の衝突を避け、意図しないパッケージがインポートされるのを防ぐためのものです。
- Goのビルドツールは、インポートパスを解決する際に特定の優先順位でディレクトリを検索します。一般的には、
技術的詳細
このコミットは、go/buildパッケージのContext.Importメソッド内のロジックに焦点を当てています。このメソッドは、Goのソースコードがimport文で指定するパスを解決し、対応するパッケージの情報を返す役割を担っています。
問題の箇所は、Context.Importメソッドが、特定のパッケージ(sub変数で表される)がGOROOT内に存在するかどうかを確認する部分です。このチェックは、現在のディレクトリで見つかったパッケージが、GOROOT内のより優先されるパッケージと競合しないことを確認するために行われます。
修正前のコードでは、GOROOT内のパッケージのパスを構築する際に、ctxt.joinPath(ctxt.GOROOT, "src", sub)という形式を使用していました。これは、$GOROOT/src/lib9のようなパスを生成します。しかし、当時のGoの標準ライブラリの配置は、$GOROOT/src/pkg/lib9のように、srcの下にさらにpkgディレクトリを挟む構造になっていました。
このパスの不一致が原因で、go/buildツールはlib9などのパッケージをGOROOT内で見つけることができませんでした。その結果、これらのパッケージは「利用不可」と判断され、インポートエラーが発生するか、あるいはGOPATH内の同名のパッケージが誤って優先されてしまう可能性がありました。
一方で、mathやerrorsのような一部のパッケージは、GOROOT/src/pkg/mathやGOROOT/src/pkg/errorsといったパスに存在していましたが、これらのパッケージはGOROOT/src/mathのようなパスでも偶然見つかることがあったため、問題が顕在化しにくかったと考えられます。
このコミットは、GOROOT内のパッケージパスの構築をctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub)に変更することで、この問題を解決しました。これにより、$GOROOT/src/pkg/lib9のような正しいパスが生成され、go/buildツールがGOROOT内の標準ライブラリパッケージを正確に識別できるようになりました。
この修正は、Goのビルドシステムの堅牢性を高め、パッケージインポートの予測可能性と信頼性を向上させる上で重要なものでした。
コアとなるコードの変更箇所
変更はsrc/pkg/go/build/build.goファイルの一箇所のみです。
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -387,7 +387,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
// but check that using it wouldn't find something
// else first.
if ctxt.GOROOT != "" {
- if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
+ if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) {
goto Found
}
}
具体的には、389行目のctxt.joinPathの呼び出しにおいて、引数に"pkg"が追加されています。
コアとなるコードの解説
変更された行は、Context.Importメソッド内で、GOROOT内に特定のサブパッケージ(sub変数で表される)が存在するかどうかを確認する条件分岐の一部です。
if ctxt.GOROOT != "":GOROOT環境変数が設定されている場合にのみ、このチェックを実行します。ctxt.joinPath(...): これは、Goのビルドコンテキスト(ctxt)が提供するヘルパー関数で、与えられたパス要素を結合して完全なファイルシステムパスを構築します。ctxt.isDir(dir): 構築されたパスdirが実際にディレクトリとして存在するかどうかを確認します。
変更前:
if dir := ctxt.joinPath(ctxt.GOROOT, "src", sub); ctxt.isDir(dir) {
この行は、$GOROOT/src/<sub_package_name>というパスを構築し、それがディレクトリであるかを確認していました。例えば、subが"lib9"であれば、$GOROOT/src/lib9をチェックします。しかし、当時のGoの標準ライブラリは$GOROOT/src/pkg/lib9に存在していたため、このチェックは失敗していました。
変更後:
if dir := ctxt.joinPath(ctxt.GOROOT, "src", "pkg", sub); ctxt.isDir(dir) {
この行は、$GOROOT/src/pkg/<sub_package_name>という正しいパスを構築し、それがディレクトリであるかを確認するように修正されました。例えば、subが"lib9"であれば、$GOROOT/src/pkg/lib9をチェックします。これにより、GOROOT内の標準ライブラリパッケージが正しく検出されるようになりました。
goto Found: もしGOROOT内で該当するパッケージが見つかった場合、Foundラベルにジャンプし、それ以上他の場所(例えばGOPATH)を検索する必要がないことを示します。これは、GOROOT内のパッケージが最も優先されるべきであるというGoのパッケージ解決の原則に基づいています。
この修正は、Goのビルドシステムがパッケージのインポートパスを解決する際の正確性を保証し、特にGOROOT内の標準ライブラリの検出に関する問題を解決する上で非常に重要でした。
関連リンク
- Go Issue #3390: https://github.com/golang/go/issues/3390 (このコミットが修正したIssue)
- Gerrit Change-Id:
5927050(GoプロジェクトのGerritレビューシステムにおける変更のID)
参考にした情報源リンク
- Go言語の公式ドキュメント (当時のバージョンに関する情報): https://go.dev/doc/
- Go Modules以前の
GOPATHに関する情報: https://go.dev/doc/code go/buildパッケージのドキュメント: https://pkg.go.dev/go/build- Go言語のソースコードリポジトリ: https://github.com/golang/go
- GoのIssueトラッカー: https://github.com/golang/go/issues
- GoのGerritコードレビューシステム: https://go-review.googlesource.com/