[インデックス 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/