[インデックス 12786] ファイルの概要
このコミットは、Go言語のコマンドラインツールgo
の動作を改善し、環境変数$GOBIN
の扱いを一貫させることを目的としています。以前は$GOBIN
が$GOROOT
内のソースコードに対してのみ考慮されていましたが、この変更により、$GOBIN
が常に尊重され、Goでコンパイルされたすべてのバイナリが指定されたディレクトリにインストールされるようになります。これにより、ユーザーは$GOBIN=$HOME/bin
のように設定することで、すべてのGoバイナリを単一の場所に集約できるようになり、使い勝手が向上します。
コミット
- コミットハッシュ:
9d7076b178e3b688a8421a8ce02466a3701d31a0
- 作者: Russ Cox rsc@golang.org
- 日付: 2012年3月27日 火曜日 11:57:39 -0400
- 件名:
cmd/go: respect $GOBIN always
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/9d7076b178e3b688a8421a8ce02466a3701d31a0
元コミット内容
commit 9d7076b178e3b688a8421a8ce02466a3701d31a0
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 27 11:57:39 2012 -0400
cmd/go: respect $GOBIN always
Another attempt at https://golang.org/cl/5754088.
Before, we only consulted $GOBIN for source code
found in $GOROOT, but that's confusing to explain
and less useful. The new behavior lets users set
GOBIN=$HOME/bin and have all go-compiled binaries
installed there.
Tested a few cases in test.bash.
Ran all.bash with and without $GOBIN and it works.
Even so, I expect it to break the builders,
like it did last time, we can debug from there.
Fixes #3269 (again).
Fixes #3396.
Fixes #3397.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5927051
変更の背景
この変更は、以前のhttps://golang.org/cl/5754088
での試みの再挑戦です。以前のgo
コマンドの動作では、$GOBIN
環境変数は$GOROOT
(Goのインストールディレクトリ)内に存在するソースコードからビルドされるバイナリに対してのみ考慮されていました。これは、ユーザーにとって理解しにくく、また、Goでコンパイルされたすべての実行ファイルを一元的に管理したいというニーズに対して不便でした。
具体的には、以下のIssueを解決することを目的としています。
- Issue #3269 (再度):
$GOBIN
の挙動に関する混乱や不整合。 - Issue #3396:
$GOBIN
が常に尊重されないことによる問題。 - Issue #3397: 同上。
このコミットは、ユーザーが$GOBIN
を例えば$HOME/bin
に設定することで、go install
コマンドによって生成されるすべてのバイナリがその指定されたディレクトリにインストールされるようにし、より直感的で便利な動作を提供することを目指しています。
前提知識の解説
このコミットを理解するためには、Go言語のビルドシステムと環境変数に関する基本的な知識が必要です。
go
コマンド: Go言語のソースコードのビルド、テスト、インストール、フォーマットなどを行うための主要なコマンドラインツールです。go install
: Goのパッケージやコマンドをコンパイルし、実行可能ファイルを適切な場所にインストールするコマンドです。$GOROOT
: Go言語のSDKがインストールされているルートディレクトリを指す環境変数です。Goの標準ライブラリやツール群がここに格納されています。$GOPATH
: Goのワークスペースのルートディレクトリを指す環境変数です。Goのソースコード、パッケージ、およびコンパイルされたバイナリがここに配置されます。通常、$GOPATH
は複数のディレクトリパスを持つことができます。$GOPATH/src
: ソースコードが置かれる場所。$GOPATH/pkg
: コンパイルされたパッケージアーカイブが置かれる場所。$GOPATH/bin
:go install
によって生成された実行可能バイナリが置かれるデフォルトの場所。
$GOBIN
:go install
コマンドによって生成された実行可能バイナリがインストールされるディレクトリを明示的に指定するための環境変数です。この変数が設定されている場合、go install
は$GOPATH/bin
ではなく、$GOBIN
で指定されたディレクトリにバイナリを配置します。
このコミット以前は、$GOBIN
が設定されていても、$GOROOT
外のソースコードからビルドされたバイナリは$GOPATH/bin
にインストールされるという、一貫性のない挙動がありました。この変更は、この不整合を解消し、$GOBIN
が常に優先されるようにします。
技術的詳細
このコミットの技術的な核心は、go
コマンドがバイナリのインストール先を決定するロジックを変更することにあります。
-
$GOBIN
の読み込み方法の変更:src/cmd/go/build.go
において、gobin
変数の初期化方法が変更されました。以前はdefaultGobin()
関数を通じて$GOBIN
を読み込み、設定されていなければ$GOROOT/bin
をデフォルトとしていましたが、新しいコードでは直接os.Getenv("GOBIN")
を呼び出し、$GOBIN
が設定されていればその値を、設定されていなければ空文字列を使用するように変更されました。これにより、$GOBIN
が設定されていない場合のデフォルトの挙動は、後続のロジックで決定されることになります。gorootBin
という新しい変数が導入され、$GOROOT/bin
のパスを保持するようになりました。
-
バイナリのターゲットパス決定ロジックの変更:
src/cmd/go/build.go
のgoFilesPackage
関数内で、pkg.target
(最終的なバイナリのインストールパス)の決定ロジックが修正されました。- 以前は、
main
パッケージ(実行可能ファイル)の場合にのみ、*buildO
(出力ファイル名)が設定され、pkg.target
は常に空文字列でした。 - 変更後、
main
パッケージの場合、まず実行可能ファイル名(exe
)を決定します。そして、$GOBIN
が設定されている場合、pkg.target
は$GOBIN
とexe
を結合したパスに設定されます。これにより、$GOBIN
が優先的に使用されるようになります。 pkg.Target = pkg.target
という行が追加され、Package
構造体のTarget
フィールドに最終的なインストールパスが確実に設定されるようになりました。
-
パッケージロード時の
BinDir
設定の変更:src/cmd/go/pkg.go
のloadImport
関数およびloadPackage
関数において、build.Package
構造体のBinDir
フィールドの設定ロジックが変更されました。loadImport
では、$GOBIN
が設定されている場合にbp.BinDir
が$GOBIN
に設定されるようになりました。loadPackage
では、$GOROOT
内のパッケージの場合、デフォルトでgorootBin
がbp.BinDir
に設定されますが、$GOBIN
が設定されている場合はそれが優先されるようになりました。
-
ドキュメントの更新:
doc/install-source.html
、src/cmd/go/doc.go
、src/cmd/go/help.go
のドキュメントが更新され、$GOBIN
が設定されている場合にgo command
がすべてのコマンドをそのディレクトリにインストールするという新しい挙動が明記されました。また、go help gopath
を参照するように促す記述も追加されました。
-
テストの追加:
src/cmd/go/test.bash
に新しいテストケースが追加されました。これらのテストは、$GOBIN
が設定されていない場合と設定されている場合の両方で、go install
がバイナリを正しくインストールすることを確認します。特に、$GOPATH
外のソースコード(例:testdata/src/go-cmd-test/helloworld.go
)をgo install
する際の挙動が検証されています。
これらの変更により、go install
コマンドは、ソースコードの場所($GOROOT
内か$GOPATH
内か)に関わらず、常に$GOBIN
環境変数を尊重してバイナリをインストールするようになります。
コアとなるコードの変更箇所
主要な変更は以下のファイルに集中しています。
src/cmd/go/build.go
:gobin
変数の初期化ロジックの変更。defaultGobin()
関数の削除。goFilesPackage
関数におけるpkg.target
の決定ロジックの修正。
src/cmd/go/pkg.go
:loadImport
およびloadPackage
関数におけるbp.BinDir
の設定ロジックの変更。
doc/install-source.html
,src/cmd/go/doc.go
,src/cmd/go/help.go
:$GOBIN
の挙動に関するドキュメントの更新。
src/cmd/go/test.bash
:$GOBIN
の挙動を検証するための新しいテストケースの追加。
src/cmd/go/testdata/src/go-cmd-test/helloworld.go
:- テスト用のシンプルなGoプログラムの追加。
具体的なコードの変更箇所は以下の通りです。
src/cmd/go/build.go
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -304,19 +306,13 @@ const (
var (
goroot = filepath.Clean(runtime.GOROOT())
- gobin = defaultGobin()
+ gobin = os.Getenv("GOBIN")
+ gorootBin = filepath.Join(goroot, "bin")
gorootSrcPkg = filepath.Join(goroot, "src/pkg")
gorootPkg = filepath.Join(goroot, "pkg")
gorootSrc = filepath.Join(goroot, "src")
)
-func defaultGobin() string {
- if s := os.Getenv("GOBIN"); s != "" {
- return s
- }
- return filepath.Join(goroot, "bin")
-}
-
func (b *builder) init() {
var err error
b.print = fmt.Print
@@ -388,17 +384,23 @@ func goFilesPackage(gofiles []string) *Package {
pkg.load(&stk, bp, err)
pkg.localPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
+ pkg.target = ""
- if *buildO == "" {
- if pkg.Name == "main" {
- _, elem := filepath.Split(gofiles[0])
- *buildO = elem[:len(elem)-len(".go")] + exeSuffix
- } else {
+ if pkg.Name == "main" {
+ _, elem := filepath.Split(gofiles[0])
+ exe := elem[:len(elem)-len(".go")] + exeSuffix
+ if *buildO == "" {
+ *buildO = exe
+ }
+ if gobin != "" {
+ pkg.target = filepath.Join(gobin, exe)
+ }
+ } else {
+ if *buildO == "" {
*buildO = pkg.Name + ".a"
}
}
- pkg.target = ""
- pkg.Target = ""
+ pkg.Target = pkg.target
pkg.Stale = true
computeStale(pkg)
@@ -463,7 +465,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
return a
}
- if p.local {
+ if p.local && p.target == "" {
// Imported via local path. No permanent target.
mode = modeBuild
}
src/cmd/go/pkg.go
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -222,6 +222,9 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
// See issue 3268 for mistakes to avoid.
bp, err := buildContext.Import(path, srcDir, 0)
bp.ImportPath = importPath
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
p.load(stk, bp, err)
if p.Error != nil && len(importPos) > 0 {
\tpos := importPos[0]
@@ -552,7 +555,10 @@ func loadPackage(arg string, stk *importStack) *Package {
bp, err := build.ImportDir(filepath.Join(gorootSrc, arg), 0)
bp.ImportPath = arg
bp.Goroot = true
- bp.BinDir = gobin
+ bp.BinDir = gorootBin
+ if gobin != "" {
+ bp.BinDir = gobin
+ }
bp.Root = goroot
bp.SrcRoot = gorootSrc
p := new(Package)
コアとなるコードの解説
このコミットの核心は、go
コマンドがバイナリのインストール先を決定する際の$GOBIN
の優先順位を明確にすることです。
-
src/cmd/go/build.go
の変更:gobin
変数がos.Getenv("GOBIN")
から直接値を取得するように変更されたことで、$GOBIN
が設定されていればその値が、設定されていなければ空文字列がgobin
に格納されます。これにより、$GOBIN
が設定されていない場合のデフォルトのインストールパスの決定は、後続のロジックに委ねられることになります。goFilesPackage
関数は、Goのソースファイルからパッケージ情報を構築する役割を担っています。この関数内で、main
パッケージ(実行可能ファイル)の場合に、pkg.target
フィールドに最終的なインストールパスを設定するロジックが追加されました。具体的には、$GOBIN
が空でなければ、$GOBIN
と実行可能ファイル名を結合したパスがpkg.target
に設定されます。これにより、go install
が実行可能ファイルをビルドする際に、$GOBIN
で指定されたディレクトリに配置されることが保証されます。pkg.Target = pkg.target
という行は、Package
構造体のTarget
フィールド(ビルド結果の最終的なパス)に、上記で決定されたpkg.target
の値を確実に反映させるためのものです。action
関数内のif p.local && p.target == ""
という条件は、ローカルパスでインポートされたパッケージで、かつ永続的なターゲットパスが設定されていない場合にのみ、ビルドモードをmodeBuild
(一時的なビルド)に設定するという意味です。これは、$GOBIN
によって永続的なターゲットパスが設定されるようになった新しい挙動に対応するための調整です。
-
src/cmd/go/pkg.go
の変更:loadImport
およびloadPackage
関数は、Goのパッケージをロードする際に、そのパッケージのビルド情報(build.Package
構造体)を設定します。この変更により、$GOBIN
が設定されている場合、build.Package
のBinDir
フィールドに$GOBIN
の値が設定されるようになりました。BinDir
は、そのパッケージのバイナリがインストールされるべきディレクトリを示します。これにより、パッケージのロード段階で$GOBIN
の指定がビルドシステム全体に伝播されるようになります。特に、$GOROOT
内のパッケージであっても$GOBIN
が優先されるようにロジックが修正されています。
これらの変更により、go
コマンドは、ユーザーが$GOBIN
を設定している場合、その設定を常に尊重し、Goでコンパイルされたすべての実行可能ファイルを指定されたディレクトリにインストールするようになります。これにより、ユーザーはGoバイナリの管理をより柔軟に行えるようになり、以前の混乱や不便さが解消されます。
関連リンク
- 元の変更提案 (最初の試み): https://golang.org/cl/5754088
- このコミットのコードレビュー: https://golang.org/cl/5927051
- 関連Issue:
- Issue 3269: https://code.google.com/p/go/issues/detail?id=3269
- Issue 3396: https://code.google.com/p/go/issues/detail?id=3396
- Issue 3397: https://code.google.com/p/go/issues/detail?id=3397
参考にした情報源リンク
- GitHub上のコミットページ: https://github.com/golang/go/commit/9d7076b178e3b688a8421a8ce02466a3701d31a0
- Go言語の公式ドキュメント (当時のバージョンに基づく
go help gopath
やgo help install
の内容が関連します)