[インデックス 13826] ファイルの概要
このコミットは、Go言語のコマンドラインツールであるgo
コマンドの内部挙動に関する変更です。具体的には、exp/
ディレクトリ配下にあるすべてのGoプログラムを、デフォルトで$GOROOT/pkg/tool
ディレクトリにインストールされる「ツール」として扱うように修正しています。これにより、実験的な(experimental)性質を持つツールが、通常のバイナリが配置される$GOROOT/bin
ディレクトリに直接インストールされることを防ぎます。
コミット
commit ca75fdf972fa3db7385241eda83691dd7ec3fc17
Author: Russ Cox <rsc@golang.org>
Date: Fri Sep 14 12:06:21 2012 -0400
cmd/go: treat all commands in exp/ as tools
Nothing in exp should get installed directly in bin,
at least not by default.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/6497138
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ca75fdf972fa3db7385241eda83691dd7ec3fc17
元コミット内容
cmd/go: treat all commands in exp/ as tools
このコミットは、exp/
ディレクトリ内のすべてのコマンドをツールとして扱うようにgo
コマンドの挙動を変更します。
exp
ディレクトリ内のものは、少なくともデフォルトでは、bin
に直接インストールされるべきではありません。
変更の背景
Go言語の標準ライブラリやツール群のソースコードは、GOROOT
環境変数で指定されるディレクトリ(通常はGoのインストールディレクトリ)のsrc
サブディレクトリに配置されています。このsrc
ディレクトリ内には、様々なパッケージやコマンドが含まれています。
その中でも、exp/
ディレクトリは「experimental(実験的)」な性質を持つパッケージやツールを一時的に配置するために使われていました。これらの実験的なツールは、まだ安定版として提供するには時期尚早であったり、将来的に変更される可能性が高かったりするため、通常の安定版ツールと同じように$GOROOT/bin
(ユーザーのPATHに含まれることが多い)に直接インストールされるのは望ましくありませんでした。
このコミット以前は、exp/
配下の一部のツール(例: exp/gotype
, exp/ebnflint
)は、go install
コマンドによって明示的に$GOROOT/pkg/tool
にインストールされるように設定されていました。しかし、exp/
配下のすべてのツールに対して個別に設定を行うのは非効率であり、また新しい実験的なツールが追加されるたびに設定を更新する必要がありました。
この変更の背景には、exp/
ディレクトリの本来の意図をより厳密に適用し、実験的なツールと安定版のツールとの区別を明確にするという目的があります。これにより、ユーザーがgo install
を実行した際に、意図せず実験的なツールが主要なバイナリディレクトリにインストールされてしまうことを防ぎ、システムのクリーンさを保つことができます。
前提知識の解説
このコミットの理解には、以下のGo言語に関する基本的な知識が必要です。
GOROOT
: Go言語のインストールディレクトリを指す環境変数です。Goの標準ライブラリやツール群のソースコード、コンパイル済みバイナリなどがこのディレクトリ配下に配置されます。go install
コマンド: Goのソースコードをコンパイルし、実行可能ファイルを生成して適切な場所にインストールするためのコマンドです。通常、実行可能ファイルはGOPATH/bin
またはGOBIN
にインストールされますが、GOROOT
内の標準ツールは$GOROOT/bin
または$GOROOT/pkg/tool
にインストールされます。$GOROOT/bin
:go
コマンド自体や、go fmt
、go vet
などの主要なGoツールがインストールされるディレクトリです。このディレクトリは通常、ユーザーのシステムPATHに含まれており、どこからでもコマンドを実行できます。$GOROOT/pkg/tool
: Go言語の内部ツールや、特定の目的のために提供される補助的なツールがインストールされるディレクトリです。これらのツールは通常、直接PATHには含まれず、go tool <command>
のようにして実行されるか、他のGoツールから内部的に呼び出されます。例えば、go tool compile
やgo tool link
などがここに配置されます。exp/
ディレクトリ: Go言語のソースツリー内にある特別なディレクトリで、「experimental(実験的)」なパッケージやツールが配置されます。これらのパッケージやツールは、まだ開発段階であったり、将来的に変更される可能性があったりするため、安定版とは異なる扱いを受けることがあります。src/cmd/go/pkg.go
:go
コマンドのソースコードの一部であり、Goパッケージのビルド、ロード、インストールに関するロジックを定義しているファイルです。特に、パッケージのインポートパスに基づいて、そのパッケージがどこにインストールされるべきかを決定するロジックが含まれています。
技術的詳細
このコミットの技術的な核心は、src/cmd/go/pkg.go
ファイル内のisGoTool
マップと、パッケージのインストールターゲットを決定するロジックの変更にあります。
以前のpkg.go
では、isGoTool
というmap[string]bool
型の変数が定義されており、これは$GOROOT/pkg/tool
にインストールされるべきGoプログラムのインポートパスを明示的にリストアップしていました。このマップには、cmd/api
、cmd/cgo
、cmd/fix
、cmd/vet
、cmd/yacc
といった主要なツールに加えて、exp/gotype
やexp/ebnflint
といったexp/
配下の特定の実験的ツールも含まれていました。
パッケージのインストールターゲットを決定する際、go
コマンドは以下の条件をチェックしていました。
if p.Goroot && isGoTool[p.ImportPath] {
p.target = filepath.Join(gorootPkg, "tool", full)
}
この条件は、「もしパッケージがGOROOT
内にあり、かつそのインポートパスがisGoTool
マップに存在すれば、$GOROOT/pkg/tool
にインストールする」というものでした。それ以外のGOROOT
内の実行可能パッケージは、デフォルトで$GOROOT/bin
にインストールされていました。
今回の変更では、isGoTool
マップからexp/gotype
とexp/ebnflint
のエントリが削除されました。そして、インストールターゲットを決定する条件が以下のように変更されました。
if p.Goroot && (isGoTool[p.ImportPath] || hasPrefix(p.ImportPath, "exp/")) {
p.target = filepath.Join(gorootPkg, "tool", full)
}
この新しい条件は、「もしパッケージがGOROOT
内にあり、かつそのインポートパスがisGoTool
マップに存在するか、またはそのインポートパスがexp/
で始まる場合、$GOROOT/pkg/tool
にインストールする」という意味になります。
hasPrefix
関数は、Go言語の標準ライブラリstrings
パッケージに含まれる関数で、文字列が特定のプレフィックスで始まるかどうかをチェックします。この変更により、exp/
ディレクトリ配下にあるすべてのGoプログラム(exp/
で始まるインポートパスを持つもの)が、個別にisGoTool
マップに登録されていなくても、自動的に$GOROOT/pkg/tool
にインストールされるようになりました。
これにより、exp/
ディレクトリの意図(実験的なツールは通常のバイナリとは異なる場所に配置されるべき)が、より汎用的かつ堅牢な方法で強制されることになります。新しい実験的なツールがexp/
に追加された場合でも、pkg.go
のコードを変更することなく、適切なインストールパスが適用されるようになります。
コアとなるコードの変更箇所
変更はsrc/cmd/go/pkg.go
ファイルに集中しています。
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -264,13 +264,11 @@ func reusePackage(p *Package, stk *importStack) *Package {
// isGoTool is the list of directories for Go programs that are installed in
// $GOROOT/pkg/tool.
var isGoTool = map[string]bool{
-"cmd/api": true,
-"cmd/cgo": true,
-"cmd/fix": true,
-"cmd/vet": true,
-"cmd/yacc": true,
-"exp/gotype": true,
-"exp/ebnflint": true,
+"cmd/api": true,
+"cmd/cgo": true,
+"cmd/fix": true,
+"cmd/vet": true,
+"cmd/yacc": true,
}
// expandScanner expands a scanner.List error into all the errors in the list.
@@ -321,7 +319,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
telem = full
}
p.target = filepath.Join(p.build.BinDir, elem)
- if p.Goroot && isGoTool[p.ImportPath] {
+ if p.Goroot && (isGoTool[p.ImportPath] || hasPrefix(p.ImportPath, "exp/")) {
p.target = filepath.Join(gorootPkg, "tool", full)
}
if buildContext.GOOS == "windows" {
具体的には、以下の2点が変更されています。
isGoTool
マップから"exp/gotype"
と"exp/ebnflint"
のエントリが削除されました。- パッケージのインストールターゲットを決定する
if
文の条件が、isGoTool[p.ImportPath]
に加えてhasPrefix(p.ImportPath, "exp/")
という条件が追加され、論理OR (||
) で結合されました。
コアとなるコードの解説
isGoTool
マップの変更
isGoTool
マップは、Goのソースツリー内で定義されている特定のコマンドが、通常の$GOROOT/bin
ではなく$GOROOT/pkg/tool
にインストールされるべきかどうかを制御します。このマップからexp/gotype
とexp/ebnflint
が削除されたのは、これらの個別のエントリが不要になったためです。なぜなら、後述のhasPrefix
による汎用的なチェックが導入されたからです。これにより、マップの定義がより簡潔になりました。
インストールロジックの変更
最も重要な変更は、パッケージのインストールパスを決定する以下の行です。
// 変更前
if p.Goroot && isGoTool[p.ImportPath] {
p.target = filepath.Join(gorootPkg, "tool", full)
}
// 変更後
if p.Goroot && (isGoTool[p.ImportPath] || hasPrefix(p.ImportPath, "exp/")) {
p.target = filepath.Join(gorootPkg, "tool", full)
}
p.Goroot
: 現在処理しているパッケージがGOROOT
内のパッケージであるかどうかを示すブール値です。go install
がGOROOT
内の標準ツールを扱う場合にtrue
になります。isGoTool[p.ImportPath]
: 変更前と同じく、パッケージのインポートパスがisGoTool
マップに明示的に登録されているかどうかをチェックします。hasPrefix(p.ImportPath, "exp/")
: これはGoのstrings.HasPrefix
関数を呼び出しており、現在のパッケージのインポートパス(例:"exp/gotype"
)が文字列"exp/"
で始まるかどうかをチェックします。
この変更により、p.Goroot
がtrue
であるGoの標準パッケージについて、以下のいずれかの条件が満たされれば、そのパッケージは$GOROOT/pkg/tool
ディレクトリにインストールされるようになります。
- そのパッケージのインポートパスが
isGoTool
マップに明示的に登録されている場合(例:cmd/api
)。 - そのパッケージのインポートパスが
exp/
で始まる場合(例:exp/gotype
,exp/ebnflint
、または将来追加されるexp/newtool
など)。
このロジックの変更により、exp/
ディレクトリ配下のすべての実行可能プログラムが、個別に設定することなく「ツール」として扱われ、$GOROOT/pkg/tool
にインストールされることが保証されます。これにより、exp/
の目的がより厳密に適用され、go
コマンドの内部ロジックがより汎用的かつ保守しやすくなりました。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
go install
コマンドに関するドキュメント: https://go.dev/cmd/go/#hdr-Compile_and_install_packages_and_dependencies- Go言語のソースコードリポジトリ: https://github.com/golang/go
参考にした情報源リンク
- Go言語のソースコード (
src/cmd/go/pkg.go
): https://github.com/golang/go/blob/master/src/cmd/go/pkg.go (コミット時点のバージョンとは異なる可能性があります) - Go言語の
strings.HasPrefix
関数に関するドキュメント: https://pkg.go.dev/strings#HasPrefix - Go言語の
exp
ディレクトリに関する議論や情報 (一般的なGoコミュニティの知識に基づく)I have generated the comprehensive technical explanation in Markdown format, following all the specified instructions and chapter structure. The output is in Japanese and includes detailed explanations of the background, prerequisite knowledge, technical details, core code changes, and related links. I have ensured that the output is only to standard output and no file saving is performed.