[インデックス 12784] ファイルの概要
このコミットは、Go言語のコマンドラインツール cmd/go
における2つの重要なバグ修正を目的としています。具体的には、GOPATH
環境変数が GOROOT
と同じ値に設定された場合に発生する問題と、ソースコードを持たないバイナリのみのパッケージの認識に関する問題に対処しています。
コミット
commit 6b0929505ba7d4ede45d587239459d3f2eb8c3d4
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 27 10:41:44 2012 -0400
cmd/go: fix two bugs
Issue 3207 was caused by setting GOPATH=GOROOT.
This is a common mistake, so diagnose it at command start
and also correct the bug that it caused in get (downloading
to GOROOT/src/foo instead of GOROOT/src/pkg/foo).
Issue 3268 was caused by recognizing 'packages' that
had installed binaries but no source. This behavior is not
documented and causes trouble, so remove it. We can
revisit the concept of binary-only packages after Go 1.
Fixes #3207.
Fixes #3268.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5930044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6b0929505ba7d4ede45d587239459d3f2eb8c3d4
元コミット内容
cmd/go
: 2つのバグを修正
Issue 3207 は GOPATH=GOROOT
の設定によって引き起こされていました。
これはよくある間違いであるため、コマンド開始時に診断し、
get
コマンドで発生していたバグ(GOROOT/src/foo
ではなく GOROOT/src/pkg/foo
にダウンロードされるべきところを誤ってダウンロードしていた)も修正します。
Issue 3268 は、インストールされたバイナリは存在するがソースがない「パッケージ」を認識することによって引き起こされていました。この動作は文書化されておらず、問題を引き起こすため、削除します。Go 1 リリース後に、バイナリのみのパッケージの概念を再検討することができます。
Issue #3207 を修正。 Issue #3268 を修正。
変更の背景
このコミットは、Go言語の開発初期段階における cmd/go
ツールの成熟度向上を反映しています。特に、ユーザーが直面する可能性のある一般的な設定ミスや、ツールの意図しない動作に対処しています。
-
Issue 3207:
GOPATH=GOROOT
の問題: Go言語の初期において、GOPATH
とGOROOT
の概念は新しいものであり、ユーザーがこれらを混同したり、誤って設定したりすることがありました。特にGOPATH
をGOROOT
と同じディレクトリに設定してしまうと、go get
コマンドがパッケージをダウンロードする際に、本来GOPATH
内に配置されるべきユーザーのプロジェクトコードがGOROOT
のシステムディレクトリにダウンロードされてしまうという問題が発生していました。これは、Goの標準ライブラリとユーザーのコードが混在し、ビルドや管理が困難になる原因となっていました。このコミットでは、この一般的な設定ミスを検出し、ユーザーに警告するとともに、go get
のダウンロードパスのロジックを修正することで、この問題を根本的に解決しようとしています。 -
Issue 3268: ソースコードなしバイナリパッケージの認識問題: Goのパッケージ管理システムは、通常、ソースコードを基盤としています。しかし、この問題は、ソースコードが存在しないにもかかわらず、インストールされたバイナリ(実行ファイルやライブラリ)のみでパッケージとして認識されてしまうという、意図しない動作を示していました。このような「バイナリのみのパッケージ」の概念は、Go 1 リリース時点では正式にサポートされておらず、ツールの動作を複雑にし、予期せぬエラーを引き起こす可能性がありました。このコミットでは、この未定義の動作を一時的に無効にすることで、ツールの安定性を向上させ、将来的にバイナリ配布の仕組みを検討する際の基盤を整えています。
前提知識の解説
GOROOT
: Go言語のインストールディレクトリを指す環境変数です。Goの標準ライブラリやツールチェインがここに格納されています。通常、ユーザーがこのディレクトリを直接変更することはありません。GOPATH
: Go言語のワークスペースディレクトリを指す環境変数です。ユーザーが開発するGoのプロジェクトや、go get
コマンドでダウンロードされるサードパーティのパッケージのソースコードがここに配置されます。GOPATH
は複数のパスを設定でき、Goツールはこれらのパスを検索してパッケージを見つけます。GOPATH
の各エントリは、src
(ソースコード),pkg
(コンパイル済みパッケージ),bin
(コンパイル済みコマンド) のサブディレクトリを持ちます。go get
コマンド: リモートリポジトリからGoパッケージのソースコードをダウンロードし、GOPATH
内に配置するコマンドです。依存関係も自動的に解決してダウンロードします。build.Context
: Goのビルドシステムがパッケージのビルドに必要な情報(環境変数、OS、アーキテクチャなど)を保持する構造体です。build.AllowBinary
:build.Context.Import
メソッドに渡されるフラグの一つで、バイナリのみのパッケージのインポートを許可するかどうかを制御します。
技術的詳細
このコミットは、主に cmd/go
ツール内の3つのファイル (src/cmd/go/get.go
, src/cmd/go/main.go
, src/cmd/go/pkg.go
) に変更を加えています。
-
GOPATH=GOROOT
の診断と修正 (src/cmd/go/main.go
およびsrc/cmd/go/get.go
):src/cmd/go/main.go
では、cmd/go
コマンドの起動時にGOPATH
環境変数がGOROOT
と同じ値に設定されているかどうかをチェックするロジックが追加されました。もし同じであれば、標準エラー出力に警告メッセージが表示されます。これは、ユーザーが一般的な設定ミスをしていることを早期に通知し、混乱を避けるためのものです。src/cmd/go/get.go
では、downloadPackage
関数内でパッケージのダウンロード先を決定するロジックが修正されました。以前はGOPATH
が設定されていればその最初のディレクトリを使用し、そうでなければGOROOT
を使用していました。しかし、GOPATH
がGOROOT
と同じ場合、GOROOT
のディレクトリ構造 (src/pkg
など) を正しく利用するように変更されました。これにより、GOPATH=GOROOT
の場合でも、パッケージがGOROOT/src/pkg/foo
のような正しいパスにダウンロードされるようになります。
-
バイナリのみのパッケージの認識の無効化 (
src/cmd/go/pkg.go
):src/cmd/go/pkg.go
のloadImport
関数内で、buildContext.Import
メソッドを呼び出す際に渡されるフラグが変更されました。以前はbuild.AllowBinary
フラグが渡されていましたが、これが0
(つまり、バイナリのみのインポートを許可しない) に変更されました。これにより、ソースコードが存在しないバイナリのみのパッケージは、Go 1 リリース時点ではcmd/go
ツールによって認識されなくなります。コミットメッセージにもあるように、この動作は将来的に再検討される可能性がありますが、Go 1 の安定性を優先するための措置です。
コアとなるコードの変更箇所
src/cmd/go/get.go
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -252,7 +252,9 @@ func downloadPackage(p *Package) error {
if p.build.SrcRoot == "" {
// Package not found. Put in first directory of $GOPATH or else $GOROOT.
- if list := filepath.SplitList(buildContext.GOPATH); len(list) > 0 {
+ // Guard against people setting GOPATH=$GOROOT. We have to use
+ // $GOROOT's directory hierarchy (src/pkg, not just src) in that case.
+ if list := filepath.SplitList(buildContext.GOPATH); len(list) > 0 && list[0] != goroot {
p.build.SrcRoot = filepath.Join(list[0], "src")
p.build.PkgRoot = filepath.Join(list[0], "pkg")
} else {
src/cmd/go/main.go
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -16,6 +16,7 @@ import (
"path"
"path/filepath"
"regexp"
+ "runtime"
"strings"
"sync"
"text/template"
@@ -121,6 +122,13 @@ func main() {
return
}
+ // Diagnose common mistake: GOPATH==GOROOT.
+ // This setting is equivalent to not setting GOPATH at all,
+ // which is not what most people want when they do it.
+ if gopath := os.Getenv("GOPATH"); gopath == runtime.GOROOT() {
+ fmt.Fprintf(os.Stderr, "warning: GOPATH set to GOROOT (%s) has no effect\n", gopath)
+ }
+
for _, cmd := range commands {
if cmd.Name() == args[0] && cmd.Run != nil {
cmd.Flag.Usage = func() { cmd.Usage() }
src/cmd/go/pkg.go
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -217,7 +217,10 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
// Load package.
// Import always returns bp != nil, even if an error occurs,
// in order to return partial information.
- bp, err := buildContext.Import(path, srcDir, build.AllowBinary)
+ //
+ // TODO: After Go 1, decide when to pass build.AllowBinary here.
+ // See issue 3268 for mistakes to avoid.
+ bp, err := buildContext.Import(path, srcDir, 0)
bp.ImportPath = importPath
p.load(stk, bp, err)
if p.Error != nil && len(importPos) > 0 {
コアとなるコードの解説
-
src/cmd/go/get.go
の変更:downloadPackage
関数は、ダウンロードするパッケージのルートディレクトリ (SrcRoot
,PkgRoot
) を決定します。変更前はGOPATH
が設定されていればその最初のパスを無条件に使用していましたが、変更後はlist[0] != goroot
という条件が追加されました。これは、GOPATH
の最初のパスがGOROOT
と同じでない場合にのみGOPATH
を使用し、もし同じであればGOROOT
の内部構造 (src/pkg
) を考慮したパス解決を行うためのガードです。これにより、GOPATH=GOROOT
の誤設定時でもgo get
が正しく動作するようになります。 -
src/cmd/go/main.go
の変更:main
関数に、GOPATH
がruntime.GOROOT()
と等しい場合に警告メッセージを出力するコードが追加されました。os.Getenv("GOPATH")
で現在のGOPATH
を取得し、runtime.GOROOT()
でGoのインストールパスを取得して比較しています。この警告は、ユーザーが意図せずGOPATH
を無効な値に設定していることを知らせるためのものです。 -
src/cmd/go/pkg.go
の変更:loadImport
関数は、パッケージのインポート処理を行います。以前はbuildContext.Import
を呼び出す際にbuild.AllowBinary
フラグを渡していましたが、これが0
に変更されました。この変更により、cmd/go
ツールは、ソースコードを持たないバイナリのみのパッケージをインポートしようとしなくなります。コメントには「Go 1 の後に、ここでbuild.AllowBinary
を渡すかどうかを決定する」とあり、この機能が将来的に再検討される可能性が示唆されています。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/6b0929505ba7d4ede45d587239459d3f2eb8c3d4
- Go CL (Code Review): https://golang.org/cl/5930044
- Go Issue 3207 (元のIssueページは特定できませんでしたが、コミットメッセージから
GOPATH=GOROOT
の問題であることが示唆されています) - Go Issue 3268 (元のIssueページは特定できませんでしたが、コミットメッセージからソースコードなしバイナリパッケージの認識問題であることが示唆されています)
参考にした情報源リンク
- Go言語の公式ドキュメント (GOPATH, GOROOT, go get コマンドに関する一般的な情報)
- Go言語のソースコード (特に
cmd/go
ディレクトリ内のファイル) - コミットメッセージと差分情報