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

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

このコミットは、Go言語のコマンドラインツールgoに、go build -iという新しいフラグを追加するものです。このフラグは、指定されたパッケージをビルドする際に、そのパッケージが依存するすべてのパッケージも自動的にインストールする機能を提供します。これにより、開発者は依存関係の手動インストールなしに、よりスムーズにビルドプロセスを進めることができるようになります。

コミット

commit bb5a827a4b76ff22fdf34a66b1e8c8d4786438cc
Author: David Crawshaw <david.crawshaw@zentus.com>
Date:   Tue May 6 09:12:15 2014 -0400

    cmd/go: add go build -i
    
    Fixes #7071.
    
    LGTM=iant
    R=golang-codereviews, iant
    CC=golang-codereviews
    https://golang.org/cl/93770044

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

https://github.com/golang/go/commit/bb5a827a4b76ff22fdf34a66b1e8c8d4786438cc

元コミット内容

cmd/go: add go build -i

Fixes #7071.

LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/93770044

変更の背景

この変更は、GoのIssue #7071を解決するために導入されました。当時のgo buildコマンドは、指定されたパッケージをビルドする機能は持っていたものの、そのパッケージが依存する他のパッケージ(依存関係)を自動的にインストールする機能は持っていませんでした。これは、特に大規模なプロジェクトや、多くの依存関係を持つパッケージを扱う際に、開発者が手動で各依存パッケージをgo installする必要があるという不便さを生んでいました。

go installコマンドは、パッケージをビルドしてインストールディレクトリ(通常は$GOPATH/binまたは$GOBIN)に実行可能ファイルを配置し、依存関係もインストールします。しかし、go buildは単にビルドするだけで、インストールは行いません。このため、ビルド対象のパッケージが依存するライブラリがまだインストールされていない場合、ビルドは失敗していました。

go build -iフラグの導入により、go buildコマンドがgo installと同様に依存関係を自動的にインストールするようになり、開発ワークフローが大幅に改善されました。これにより、ユーザーはgo buildを実行するだけで、必要な依存関係がすべて揃った状態でビルドを完了できるようになりました。

前提知識の解説

Goのビルドシステムとパッケージ管理

Go言語は、シンプルで効率的なビルドシステムとパッケージ管理を提供します。

  • パッケージ (Package): Goのコードはパッケージとして組織されます。関連する機能は一つのパッケージにまとめられ、他のパッケージからインポートして利用できます。
  • go build: このコマンドは、Goのソースコードをコンパイルして実行可能ファイルやパッケージアーカイブを生成します。デフォルトでは、現在のディレクトリのパッケージをビルドし、実行可能ファイルを生成します。ライブラリパッケージの場合は、コンパイルされたアーカイブファイル(.aファイル)を$GOPATH/pkgまたは$GOROOT/pkgに配置します。
  • go install: このコマンドは、go buildと同様にパッケージをビルドしますが、それに加えてビルドされた実行可能ファイルを$GOPATH/binまたは$GOBINに、パッケージアーカイブを$GOPATH/pkgまたは$GOROOT/pkgにインストールします。go installは、依存関係も自動的にビルド・インストールする特性があります。
  • 依存関係 (Dependencies): あるパッケージが別のパッケージの機能を利用する場合、そのパッケージは「依存関係」となります。Goのビルドシステムは、これらの依存関係を解決し、必要に応じてビルド・インストールします。
  • $GOPATH: Goのワークスペースのルートディレクトリを指定する環境変数です。Goのソースコード、パッケージ、実行可能ファイルがこのディレクトリ構造内に配置されます。
  • $GOROOT: GoのSDKがインストールされているディレクトリを指定する環境変数です。標準ライブラリのパッケージなどが含まれます。

ビルドモードとインストールモード

Goのビルドシステム内部では、パッケージのビルドやインストールには異なる「モード」が存在します。

  • modeBuild: パッケージをビルドするだけのモード。結果は一時的な場所に置かれるか、指定された出力ファイルに書き出されます。
  • modeInstall: パッケージをビルドし、その結果を永続的なインストールディレクトリ($GOPATH/pkg$GOPATH/binなど)に配置するモード。

このコミットでは、go buildコマンドに-iフラグが追加されることで、ビルド対象のパッケージの依存関係に対してはmodeInstallが適用されるようになります。

技術的詳細

このコミットの主要な変更点は、go buildコマンドに-iフラグを追加し、そのフラグが指定された場合に依存パッケージのビルドモードをmodeInstallに変更することです。

具体的には、以下のファイルが変更されています。

  1. src/cmd/go/build.go:

    • cmdBuildコマンドのUsageLine[-i]オプションが追加され、ヘルプメッセージに-iフラグの説明が追加されました。
    • buildIという新しいブール型変数が導入され、-iフラグの状態を保持します。
    • runBuild関数内で、depModeという変数が導入されました。この変数は、デフォルトではmodeBuildに設定されますが、buildItrue(つまり-iフラグが指定された)の場合にはmodeInstallに設定されます。
    • パッケージの依存関係を処理するb.action関数の呼び出しにおいて、これまでは常にmodeBuildが渡されていた第二引数(依存関係のビルドモード)が、新しく導入されたdepMode変数に置き換えられました。これにより、-iフラグが指定された場合に依存関係がインストールされるようになります。
  2. src/cmd/go/test.bash:

    • go build -iの機能が正しく動作するかを確認するための新しいテストケースが追加されました。このテストは、依存関係を持つ2つのパッケージ(x/y/foox/y/bar)を作成し、go build -i x/y/barを実行してx/y/fooがビルド・インストールされることを確認します。また、2回目の実行ではx/y/fooが再ビルドされないことを確認し、キャッシュが正しく機能していることも検証しています。
  3. src/cmd/go/test.go:

    • testIという変数(go test -iに関連するもの)が削除されました。これは、go testコマンドの-iフラグがgo build-iフラグと統合され、buildI変数で一元的に管理されるようになったためです。
  4. src/cmd/go/testflag.go:

    • testFlagDefnから{name: "i", boolVar: &testI}のエントリが削除され、代わりに{name: "i", boolVar: &buildI}が追加されました。これにより、go testコマンドの-iフラグもbuildI変数にマッピングされ、go build -iと同じロジックが適用されるようになりました。

これらの変更により、go build -iは、ビルド対象のパッケージだけでなく、その依存関係もgo installと同様にビルド・インストールする動作を実現しています。

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

src/cmd/go/build.goにおけるrunBuild関数の変更がこのコミットの核心です。

--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -28,7 +28,7 @@ import (
 )
 
 var cmdBuild = &Command{
-	UsageLine: "build [-o output] [build flags] [packages]",
+	UsageLine: "build [-o output] [-i] [build flags] [packages]",
 	Short:     "compile packages and dependencies",
 	Long: `
 Build compiles the packages named by the import paths,
@@ -50,6 +50,8 @@ derives from the first file name mentioned, such as f1 for 'go build
 f1.go f2.go'; with no files provided ('go build'), the output file
 name is the base name of the containing directory.
 
+The -i flag installs the packages that are dependencies of the target.
+
 The build flags are shared by the build, install, run, and test commands:
 
 	-a
@@ -107,6 +109,8 @@ func init() {
 	cmdBuild.Run = runBuild
 	cmdInstall.Run = runInstall
 
+	cmdBuild.Flag.BoolVar(&buildI, "i", false, "")
+
 	addBuildFlags(cmdBuild)
 	addBuildFlags(cmdInstall)
 }
@@ -117,6 +121,7 @@ var buildN bool               // -n flag
 var buildP = runtime.NumCPU() // -p flag
 var buildV bool               // -v flag
 var buildX bool               // -x flag
+var buildI bool               // -i flag
 var buildO = cmdBuild.Flag.String("o", "", "output file")
 var buildWork bool           // -work flag
 var buildGcflags []string    // -gcflags flag
@@ -290,8 +295,12 @@ func runBuild(cmd *Command, args []string) {
 	}\n
 	a := &action{}
+\tdepMode := modeBuild
+\tif buildI {
+\t\tdepMode = modeInstall
+\t}
 	for _, p := range packages(args) {
-\t\ta.deps = append(a.deps, b.action(modeBuild, modeBuild, p))\n
+\t\ta.deps = append(a.deps, b.action(modeBuild, depMode, p))\n
 	}
 	b.do(a)
 }

コアとなるコードの解説

上記の差分は、go build -iの動作を制御する主要なロジックを示しています。

  1. UsageLineとヘルプメッセージの更新:

    -	UsageLine: "build [-o output] [build flags] [packages]",
    +	UsageLine: "build [-o output] [-i] [build flags] [packages]",
    ...
    +The -i flag installs the packages that are dependencies of the target.
    

    これは、go buildコマンドの利用方法を示す文字列と、-iフラグの簡単な説明を追加しています。ユーザーがgo help buildを実行した際に、この新しいオプションが表示されるようになります。

  2. buildI変数の導入とフラグの登録:

    +var buildI bool               // -i flag
    ...
    +	cmdBuild.Flag.BoolVar(&buildI, "i", false, "")
    

    buildIというグローバルなブール変数が宣言され、-iフラグがコマンドラインで指定されたかどうかを追跡します。cmdBuild.Flag.BoolVarは、コマンドライン引数を解析し、-iフラグが存在すればbuildItrueに設定する役割を担います。

  3. depModeの導入と条件分岐:

    +	depMode := modeBuild
    +	if buildI {
    +		depMode = modeInstall
    +	}
    

    これがこのコミットの最も重要な部分です。

    • depModeという新しい変数が導入され、デフォルト値としてmodeBuild(ビルドのみ)が設定されます。
    • if buildIの条件文により、もし-iフラグが指定されてbuildItrueであれば、depModemodeInstall(ビルドとインストール)に上書きされます。
  4. b.actionへのdepModeの適用:

    -	a.deps = append(a.deps, b.action(modeBuild, modeBuild, p))
    +	a.deps = append(a.deps, b.action(modeBuild, depMode, p))
    

    b.action関数は、Goのビルドシステム内でパッケージのビルドアクションを定義するものです。この関数は複数の引数を取り、そのうちの2番目の引数は「依存関係のビルドモード」を指定します。

    • 変更前は、依存関係も常にmodeBuildで処理されていました。
    • 変更後は、新しく計算されたdepModeがこの引数に渡されます。これにより、-iフラグが指定された場合には、ビルド対象のパッケージの依存関係がmodeInstallで処理され、自動的にインストールされるようになります。

この一連の変更により、go build -iは、ビルド対象のパッケージの依存関係を自動的にインストールするという、ユーザーが求めていた機能を実現しています。

関連リンク

  • Go CL: https://golang.org/cl/93770044
  • Go Issue #7071 (直接のリンクは見つかりませんでしたが、コミットメッセージで参照されています)

参考にした情報源リンク

  • Go CL 93770044 の内容 (Web Fetchによる取得)
  • Go言語の公式ドキュメント (go build, go install コマンドに関する一般的な知識)
  • Go言語のパッケージ管理に関する一般的な知識
  • Go言語のビルドシステムに関する一般的な知識
  • GitHubのコミット履歴
  • Go言語のIssueトラッカーの一般的な構造に関する知識 (Issue #7071の背景を推測するため)