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

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

このコミットは、Goコマンドラインツールにおけるgo install x.goコマンドの挙動を修正するものです。具体的には、GOBIN環境変数が設定されていない場合に、コマンドラインで指定された.goファイル(例: go install main.go)のインストール先が見つからないというエラーメッセージを改善し、より適切なエラーハンドリングを提供する変更です。

コミット

commit 159c2b7e46f0b8293f1eed66ebec70ca845ac591
Author: Russ Cox <rsc@golang.org>
Date:   Tue Sep 10 14:41:07 2013 -0400

    cmd/go: fix error for 'go install x.go' when GOBIN is not set
    
    Fixes #6191.
    Fixes #5426.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/13234052

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

https://github.com/golang/go/commit/159c2b7e46f0b8293f1eed66ebec70ca845ac591

元コミット内容

cmd/go: fix error for 'go install x.go' when GOBIN is not set

このコミットは、GOBIN環境変数が設定されていない状態でgo install x.goのように特定の.goファイルを指定してインストールしようとした際に発生するエラーメッセージを修正することを目的としています。

変更の背景

この変更は、GoのIssue #6191と #5426を修正するために行われました。

  • Issue #6191: このIssueは、GOBINが設定されていない場合にgo install foo.goを実行すると、go install: no install location for directory /path/to/foo.go outside GOPATHという誤解を招くエラーメッセージが表示されることを指摘していました。本来は、コマンドラインで指定されたファイルに対するインストール先がないことを明確に伝えるべきでした。
  • Issue #5426: このIssueも同様に、go installが特定の.goファイルを引数として受け取った際に、GOBINが設定されていない場合の挙動に関するものでした。ユーザーは、go installがパッケージ名ではなくファイル名を引数として受け取った場合に、どこに実行可能ファイルがインストールされるべきかについて混乱していました。

これらのIssueは、go installコマンドがパッケージパス(例: go install github.com/user/repo/cmd/myprog)と直接ファイルパス(例: go install main.go)の両方を受け入れるというGoの設計に起因するものでした。パッケージパスの場合、GOPATH/binまたはGOBINにインストールされますが、ファイルパスの場合の挙動が不明確であり、特にGOBINが設定されていない場合に適切なエラーメッセージが表示されないという問題がありました。

このコミットは、この曖昧さを解消し、ユーザーがより分かりやすいエラーメッセージを受け取れるようにすることで、開発体験を向上させることを目指しています。

前提知識の解説

このコミットを理解するためには、以下のGoの概念とコマンドに関する知識が必要です。

  • go installコマンド: go installはGoのビルドツールチェーンの一部であり、Goのパッケージをコンパイルし、その結果生成される実行可能ファイルやライブラリを標準のインストール場所に配置するために使用されます。

    • パッケージのインストール: go install <package_path>のようにパッケージパスを指定すると、そのパッケージがコンパイルされ、実行可能ファイル(mainパッケージの場合)は$GOBINまたは$GOPATH/binに、ライブラリ(非mainパッケージの場合)は$GOPATH/pkgにインストールされます。
    • ファイルのインストール: go install <file.go>のように直接.goファイルを指定することもできます。この場合、指定されたファイルが属するディレクトリが一時的なパッケージとして扱われ、コンパイルされます。生成された実行可能ファイルは通常$GOBINまたは$GOPATH/binにインストールされますが、GOBINが設定されていない場合はインストール先が不明確になるという問題がありました。
  • GOPATH環境変数: GOPATHは、Goのワークスペースのルートディレクトリを指定する環境変数です。Goのソースコード、コンパイルされたパッケージ、および実行可能ファイルは、このGOPATHの構造に従って配置されます。 一般的なGOPATHの構造は以下の通りです。

    • $GOPATH/src: ソースコードが配置されます。
    • $GOPATH/pkg: コンパイルされたパッケージアーカイブが配置されます。
    • $GOPATH/bin: go installによって生成された実行可能ファイルが配置されます。
  • GOBIN環境変数: GOBINは、go installコマンドによって生成された実行可能ファイルを配置するディレクトリを明示的に指定するための環境変数です。GOBINが設定されている場合、go installは常に指定されたGOBINディレクトリに実行可能ファイルをインストールします。GOBINが設定されていない場合、デフォルトで$GOPATH/binにインストールされます。

  • パッケージの解決とビルドプロセス: Goのビルドプロセスでは、ソースファイルがどのパッケージに属するか、そのパッケージがどこにインストールされるべきかを決定します。go installは、この解決プロセスの一部として、最終的な出力ファイルの配置場所を決定します。

このコミットは、特にGOBINが設定されていない状況で、go installに直接.goファイルを渡した場合のインストール先の決定ロジックと、それに関連するエラーメッセージの改善に焦点を当てています。

技術的詳細

このコミットの技術的な核心は、go installコマンドが、コマンドラインで直接指定された.goファイル(例: go install main.go)と、インポートパスで指定されたパッケージ(例: go install github.com/user/repo)を区別し、それぞれに対して適切なインストール場所のチェックとエラーメッセージを生成するように変更された点にあります。

変更は主に以下の3つのファイルで行われています。

  1. src/cmd/go/pkg.go: Package構造体に新しいフィールドcmdline boolが追加されました。このフィールドは、そのPackageがコマンドラインで直接指定された.goファイルから生成されたものであるかどうかを示すフラグとして機能します。

  2. src/cmd/go/build.go:

    • goFilesPackage関数内で、Package構造体のcmdlineフィールドがtrueに設定されるようになりました。これは、goFilesPackageがコマンドラインで指定された.goファイル群からPackageを構築する際に呼び出されるためです。
    • runInstall関数内で、インストール場所のチェックロジックが変更されました。以前は、p.Target == ""(インストール先が未定義)かつ!p.Standard || p.ImportPath != "unsafe"(標準パッケージやunsafeパッケージではない)場合に、p.ConflictDir != ""(GOPATH外のディレクトリで、かつGOPATH内の別のパッケージと競合している)かどうかでエラーメッセージを分岐していました。 このコミットでは、このチェックの前にp.cmdlinetrueであるかどうかの条件が追加されました。
      • もしp.cmdlinetrueであれば、つまりコマンドラインで.goファイルが指定された場合、GOBINが設定されていないことによるインストール先の不足を明示するエラーメッセージ「go install: no install location for .go files listed on command line (GOBIN not set)」が表示されるようになりました。
      • p.cmdlinefalseの場合(通常のパッケージインストールの場合)は、以前と同様のロジックが適用され、GOPATH外のディレクトリや競合するディレクトリに関するエラーメッセージが表示されます。
  3. src/cmd/go/test.bash: テストスクリプトが更新され、GOBINが設定されていない状態でgo install testdata/src/go-cmd-test/helloworld.goを実行した場合に、期待される新しいエラーメッセージ「no install location for .go files listed on command line」が正しく出力されることを検証するテストが追加されました。これにより、修正が意図通りに機能していることが確認されます。

この変更により、go installコマンドは、ユーザーが意図したインストール方法(パッケージ名 vs. ファイル名)をより正確に判断し、それに応じた適切なエラーメッセージを提供できるようになりました。これは、Goツールのユーザーフレンドリーさを向上させる重要な改善です。

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

src/cmd/go/build.go

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -311,7 +311,9 @@ func runInstall(cmd *Command, args []string) {
 
 	for _, p := range pkgs {
 		if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
-			if p.ConflictDir != "" {
+			if p.cmdline {
+				errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
+			} else if p.ConflictDir != "" {
 				errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
 			} else {
 				errorf("go install: no install location for directory %s outside GOPATH", p.Dir)
@@ -486,6 +488,7 @@ func goFilesPackage(gofiles []string) *Package {
 	bp, err := ctxt.ImportDir(dir, 0)
 	pkg := new(Package)
 	pkg.local = true
+	pkg.cmdline = true
 	pkg.load(&stk, bp, err)
 	pkg.localPrefix = dirToImportPath(dir)
 	pkg.ImportPath = "command-line-arguments"

src/cmd/go/pkg.go

--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -82,6 +82,7 @@ type Package struct {
 	fake         bool                 // synthesized package
 	forceBuild   bool                 // this package must be rebuilt
 	forceLibrary bool                 // this package is a library (even if named "main")
+	cmdline      bool                 // defined by files listed on command line
 	local        bool                 // imported via local path (./ or ../)
 	localPrefix  string               // interpret ./ and ../ imports relative to this prefix
 	exeName      string               // desired name for temporary executable

src/cmd/go/test.bash

--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -150,11 +150,16 @@ fi
 
 # Without $GOBIN set, installing a program outside $GOPATH should fail
 # (there is nowhere to install it).
-TEST install without destination
-if ./testgo install testdata/src/go-cmd-test/helloworld.go; then
+TEST install without destination fails
+if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
 	echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
 	ok=false
+elif ! grep 'no install location for .go files listed on command line' testdata/err; then
+	echo "wrong error:"
+	cat testdata/err
+	ok=false
 fi
+rm -f testdata/err
 
 # With $GOBIN set, should install there.
 TEST install to GOBIN '(command-line package)'

コアとなるコードの解説

src/cmd/go/pkg.go の変更

Package構造体は、Goのビルドシステムが扱うパッケージのメタデータを保持します。ここに追加されたcmdline boolフィールドは、このPackageインスタンスが、go install main.goのようにコマンドラインで直接.goファイルが指定されたことによって生成されたものであるかを識別するためのフラグです。これにより、Goツールはパッケージのソースがどこにあるかだけでなく、そのパッケージがどのように指定されたか(インポートパスか、直接ファイルか)というコンテキストを保持できるようになります。

src/cmd/go/build.go の変更

  1. goFilesPackage関数: この関数は、コマンドラインで指定された一連の.goファイルからPackage構造体を構築する際に呼び出されます。変更点として、pkg.cmdline = trueが追加されました。これにより、コマンドラインで指定されたファイルから生成されたPackageインスタンスには、cmdlineフラグが立てられるようになります。

  2. runInstall関数: この関数はgo installコマンドの主要なロジックを含んでいます。特に、インストール先の決定とエラーハンドリングを担当します。 変更されたif文の条件は以下のようになっています。

    if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
        if p.cmdline {
            errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
        } else if p.ConflictDir != "" {
            errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
        } else {
            errorf("go install: no install location for directory %s outside GOPATH", p.Dir)
        }
    }
    
    • p.Target == ""は、パッケージのビルドターゲット(実行可能ファイルのパスなど)がまだ決定されていないことを意味します。
    • (!p.Standard || p.ImportPath != "unsafe")は、標準ライブラリやunsafeパッケージではないことを確認します。これらのパッケージは特別な扱いを受けるため、通常はインストールされません。
    • if p.cmdline: ここが今回の変更の核心です。もしp.cmdlinetrueであれば、それはユーザーがgo install main.goのように直接.goファイルを指定したことを意味します。この場合、GOBINが設定されていないと実行可能ファイルのインストール先が不明確になるため、「go install: no install location for .go files listed on command line (GOBIN not set)」という、より具体的で分かりやすいエラーメッセージが表示されます。このメッセージは、ユーザーにGOBINを設定するか、GOPATH内で作業することを促します。
    • else if p.ConflictDir != "": p.cmdlinefalseの場合(つまり、通常のパッケージインストールの場合)に、GOPATH内の別のパッケージと競合しているディレクトリからのインストールを試みた場合に表示されるエラーメッセージです。
    • else: 上記のいずれにも該当しない場合(例えば、GOPATH外のディレクトリにあるパッケージをインストールしようとした場合)に表示される一般的なエラーメッセージです。

このロジックの変更により、go installは、ユーザーがコマンドラインで.goファイルを直接指定した場合に、より的確なエラーメッセージを提供できるようになり、ユーザーの混乱を減らすことができます。

src/cmd/go/test.bash の変更

テストスクリプトの変更は、この修正が正しく機能していることを確認するためのものです。 以前のテストは単にgo install testdata/src/go-cmd-test/helloworld.goが失敗することだけを検証していましたが、新しいテストでは、エラー出力が期待される新しいエラーメッセージ「no install location for .go files listed on command line」を含んでいることをgrepコマンドで確認しています。これにより、エラーメッセージの正確性も保証されます。

関連リンク

参考にした情報源リンク

  • Go Issue #6191: go install foo.go fails with misleading error when GOBIN not set (おそらくGoのIssueトラッカーで検索可能)
  • Go Issue #5426: go install with file argument and no GOBIN (おそらくGoのIssueトラッカーで検索可能)
  • Go Modules Reference: https://go.dev/doc/modules/ (Go Modules導入後の情報も含まれるが、GOPATH/GOBINの概念は共通)
  • The Go Programming Language Specification: https://go.dev/ref/spec
  • Go Command Documentation: go help install (ローカル環境で実行可能)

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

このコミットは、Goコマンドラインツールにおけるgo install x.goコマンドの挙動を修正するものです。具体的には、GOBIN環境変数が設定されていない場合に、コマンドラインで指定された.goファイル(例: go install main.go)のインストール先が見つからないというエラーメッセージを改善し、より適切なエラーハンドリングを提供する変更です。

コミット

commit 159c2b7e46f0b8293f1eed66ebec70ca845ac591
Author: Russ Cox <rsc@golang.org>
Date:   Tue Sep 10 14:41:07 2013 -0400

    cmd/go: fix error for 'go install x.go' when GOBIN is not set
    
    Fixes #6191.
    Fixes #5426.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/13234052

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

https://github.com/golang/go/commit/159c2b7e46f0b8293f1eed66ebec70ca845ac591

元コミット内容

cmd/go: fix error for 'go install x.go' when GOBIN is not set

このコミットは、GOBIN環境変数が設定されていない状態でgo install x.goのように特定の.goファイルを指定してインストールしようとした際に発生するエラーメッセージを修正することを目的としています。

変更の背景

この変更は、GoのIssue #6191と #5426を修正するために行われました。

  • Issue #6191: このIssueは、GOBINが設定されていない場合にgo install foo.goを実行すると、go install: no install location for directory /path/to/foo.go outside GOPATHという誤解を招くエラーメッセージが表示されることを指摘していました。本来は、コマンドラインで指定されたファイルに対するインストール先がないことを明確に伝えるべきでした。
  • Issue #5426: このIssueも同様に、go installが特定の.goファイルを引数として受け取った際に、GOBINが設定されていない場合の挙動に関するものでした。ユーザーは、go installがパッケージ名ではなくファイル名を引数として受け取った場合に、どこに実行可能ファイルがインストールされるべきかについて混乱していました。

これらのIssueは、go installコマンドがパッケージパス(例: go install github.com/user/repo/cmd/myprog)と直接ファイルパス(例: go install main.go)の両方を受け入れるというGoの設計に起因するものでした。パッケージパスの場合、GOPATH/binまたはGOBINにインストールされますが、ファイルパスの場合の挙動が不明確であり、特にGOBINが設定されていない場合に適切なエラーメッセージが表示されないという問題がありました。

このコミットは、この曖昧さを解消し、ユーザーがより分かりやすいエラーメッセージを受け取れるようにすることで、開発体験を向上させることを目指しています。

前提知識の解説

このコミットを理解するためには、以下のGoの概念とコマンドに関する知識が必要です。

  • go installコマンド: go installはGoのビルドツールチェーンの一部であり、Goのパッケージをコンパイルし、その結果生成される実行可能ファイルやライブラリを標準のインストール場所に配置するために使用されます。

    • パッケージのインストール: go install <package_path>のようにパッケージパスを指定すると、そのパッケージがコンパイルされ、実行可能ファイル(mainパッケージの場合)は$GOBINまたは$GOPATH/binに、ライブラリ(非mainパッケージの場合)は$GOPATH/pkgにインストールされます。
    • ファイルのインストール: go install <file.go>のように直接.goファイルを指定することもできます。この場合、指定されたファイルが属するディレクトリが一時的なパッケージとして扱われ、コンパイルされます。生成された実行可能ファイルは通常$GOBINまたは$GOPATH/binにインストールされますが、GOBINが設定されていない場合はインストール先が不明確になるという問題がありました。
  • GOPATH環境変数: GOPATHは、Goのワークスペースのルートディレクトリを指定する環境変数です。Goのソースコード、コンパイルされたパッケージ、および実行可能ファイルは、このGOPATHの構造に従って配置されます。 一般的なGOPATHの構造は以下の通りです。

    • $GOPATH/src: ソースコードが配置されます。
    • $GOPATH/pkg: コンパイルされたパッケージアーカイブが配置されます。
    • $GOPATH/bin: go installによって生成された実行可能ファイルが配置されます。
  • GOBIN環境変数: GOBINは、go installコマンドによって生成された実行可能ファイルを配置するディレクトリを明示的に指定するための環境変数です。GOBINが設定されている場合、go installは常に指定されたGOBINディレクトリに実行可能ファイルをインストールします。GOBINが設定されていない場合、デフォルトで$GOPATH/binにインストールされます。

  • パッケージの解決とビルドプロセス: Goのビルドプロセスでは、ソースファイルがどのパッケージに属するか、そのパッケージがどこにインストールされるべきかを決定します。go installは、この解決プロセスの一部として、最終的な出力ファイルの配置場所を決定します。

このコミットは、特にGOBINが設定されていない状況で、go installに直接.goファイルを渡した場合のインストール先の決定ロジックと、それに関連するエラーメッセージの改善に焦点を当てています。

技術的詳細

このコミットの技術的な核心は、go installコマンドが、コマンドラインで直接指定された.goファイル(例: go install main.go)と、インポートパスで指定されたパッケージ(例: go install github.com/user/repo)を区別し、それぞれに対して適切なインストール場所のチェックとエラーメッセージを生成するように変更された点にあります。

変更は主に以下の3つのファイルで行われています。

  1. src/cmd/go/pkg.go: Package構造体に新しいフィールドcmdline boolが追加されました。このフィールドは、そのPackageがコマンドラインで直接指定された.goファイルから生成されたものであるかどうかを示すフラグとして機能します。

  2. src/cmd/go/build.go:

    • goFilesPackage関数内で、Package構造体のcmdlineフィールドがtrueに設定されるようになりました。これは、goFilesPackageがコマンドラインで指定された.goファイル群からPackageを構築する際に呼び出されるためです。
    • runInstall関数内で、インストール場所のチェックロジックが変更されました。以前は、p.Target == ""(インストール先が未定義)かつ!p.Standard || p.ImportPath != "unsafe"(標準パッケージやunsafeパッケージではない)場合に、p.ConflictDir != ""(GOPATH外のディレクトリで、かつGOPATH内の別のパッケージと競合している)かどうかでエラーメッセージを分岐していました。 このコミットでは、このチェックの前にp.cmdlinetrueであるかどうかの条件が追加されました。
      • もしp.cmdlinetrueであれば、つまりコマンドラインで.goファイルが指定された場合、GOBINが設定されていないことによるインストール先の不足を明示するエラーメッセージ「go install: no install location for .go files listed on command line (GOBIN not set)」が表示されるようになりました。
      • p.cmdlinefalseの場合(通常のパッケージインストールの場合)は、以前と同様のロジックが適用され、GOPATH外のディレクトリや競合するディレクトリに関するエラーメッセージが表示されます。
  3. src/cmd/go/test.bash: テストスクリプトが更新され、GOBINが設定されていない状態でgo install testdata/src/go-cmd-test/helloworld.goを実行した場合に、期待される新しいエラーメッセージ「no install location for .go files listed on command line」が正しく出力されることを検証するテストが追加されました。これにより、修正が意図通りに機能していることが確認されます。

この変更により、go installコマンドは、ユーザーが意図したインストール方法(パッケージ名 vs. ファイル名)をより正確に判断し、それに応じた適切なエラーメッセージを提供できるようになりました。これは、Goツールのユーザーフレンドリーさを向上させる重要な改善です。

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

src/cmd/go/build.go

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -311,7 +311,9 @@ func runInstall(cmd *Command, args []string) {
 
 	for _, p := range pkgs {
 		if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
-			if p.ConflictDir != "" {
+			if p.cmdline {
+				errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
+			} else if p.ConflictDir != "" {
 				errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
 			} else {
 				errorf("go install: no install location for directory %s outside GOPATH", p.Dir)
@@ -486,6 +488,7 @@ func goFilesPackage(gofiles []string) *Package {
 	bp, err := ctxt.ImportDir(dir, 0)
 	pkg := new(Package)
 	pkg.local = true
+	pkg.cmdline = true
 	pkg.load(&stk, bp, err)
 	pkg.localPrefix = dirToImportPath(dir)
 	pkg.ImportPath = "command-line-arguments"

src/cmd/go/pkg.go

--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -82,6 +82,7 @@ type Package struct {
 	fake         bool                 // synthesized package
 	forceBuild   bool                 // this package must be rebuilt
 	forceLibrary bool                 // this package is a library (even if named "main")
+	cmdline      bool                 // defined by files listed on command line
 	local        bool                 // imported via local path (./ or ../)
 	localPrefix  string               // interpret ./ and ../ imports relative to this prefix
 	exeName      string               // desired name for temporary executable

src/cmd/go/test.bash

--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -150,11 +150,16 @@ fi
 
 # Without $GOBIN set, installing a program outside $GOPATH should fail
 # (there is nowhere to install it).
-TEST install without destination
-if ./testgo install testdata/src/go-cmd-test/helloworld.go; then
+TEST install without destination fails
+if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
 	echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
 	ok=false
+elif ! grep 'no install location for .go files listed on command line' testdata/err; then
+	echo "wrong error:"
+	cat testdata/err
+	ok=false
 fi
+rm -f testdata/err
 
 # With $GOBIN set, should install there.
 TEST install to GOBIN '(command-line package)'

コアとなるコードの解説

src/cmd/go/pkg.go の変更

Package構造体は、Goのビルドシステムが扱うパッケージのメタデータを保持します。ここに追加されたcmdline boolフィールドは、このPackageインスタンスが、go install main.goのようにコマンドラインで直接.goファイルが指定されたことによって生成されたものであるかを識別するためのフラグです。これにより、Goツールはパッケージのソースがどこにあるかだけでなく、そのパッケージがどのように指定されたか(インポートパスか、直接ファイルか)というコンテキストを保持できるようになります。

src/cmd/go/build.go の変更

  1. goFilesPackage関数: この関数は、コマンドラインで指定された一連の.goファイルからPackage構造体を構築する際に呼び出されます。変更点として、pkg.cmdline = trueが追加されました。これにより、コマンドラインで指定されたファイルから生成されたPackageインスタンスには、cmdlineフラグが立てられるようになります。

  2. runInstall関数: この関数はgo installコマンドの主要なロジックを含んでいます。特に、インストール先の決定とエラーハンドリングを担当します。 変更されたif文の条件は以下のようになっています。

    if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
        if p.cmdline {
            errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
        } else if p.ConflictDir != "" {
            errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
        } else {
            errorf("go install: no install location for directory %s outside GOPATH", p.Dir)
        }
    }
    
    • p.Target == ""は、パッケージのビルドターゲット(実行可能ファイルのパスなど)がまだ決定されていないことを意味します。
    • (!p.Standard || p.ImportPath != "unsafe")は、標準ライブラリやunsafeパッケージではないことを確認します。これらのパッケージは特別な扱いを受けるため、通常はインストールされません。
    • if p.cmdline: ここが今回の変更の核心です。もしp.cmdlinetrueであれば、それはユーザーがgo install main.goのように直接.goファイルを指定したことを意味します。この場合、GOBINが設定されていないと実行可能ファイルのインストール先が不明確になるため、「go install: no install location for .go files listed on command line (GOBIN not set)」という、より具体的で分かりやすいエラーメッセージが表示されます。このメッセージは、ユーザーにGOBINを設定するか、GOPATH内で作業することを促します。
    • else if p.ConflictDir != "": p.cmdlinefalseの場合(つまり、通常のパッケージインストールの場合)に、GOPATH内の別のパッケージと競合しているディレクトリからのインストールを試みた場合に表示されるエラーメッセージです。
    • else: 上記のいずれにも該当しない場合(例えば、GOPATH外のディレクトリにあるパッケージをインストールしようとした場合)に表示される一般的なエラーメッセージです。

このロジックの変更により、go installは、ユーザーがコマンドラインで.goファイルを直接指定した場合に、より的確なエラーメッセージを提供できるようになり、ユーザーの混乱を減らすことができます。

src/cmd/go/test.bash の変更

テストスクリプトの変更は、この修正が正しく機能していることを確認するためのものです。 以前のテストは単にgo install testdata/src/go-cmd-test/helloworld.goが失敗することだけを検証していましたが、新しいテストでは、エラー出力が期待される新しいエラーメッセージ「no install location for .go files listed on command line」を含んでいることをgrepコマンドで確認しています。これにより、エラーメッセージの正確性も保証されます。

関連リンク

参考にした情報源リンク

  • Go Issue #6191: (Web検索では直接的なリンクが見つかりませんでした)
  • Go Issue #5426: (Web検索では直接的なリンクが見つかりませんでした)
  • Go Modules Reference: https://go.dev/doc/modules/ (Go Modules導入後の情報も含まれるが、GOPATH/GOBINの概念は共通)
  • The Go Programming Language Specification: https://go.dev/ref/spec
  • Go Command Documentation: go help install (ローカル環境で実行可能)