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

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

このコミットは、Goコマンドラインツール(cmd/go)における多数のバグ修正と機能改善を目的としています。特に、ビルドシステム、パッケージ管理(go get)、Cgoの統合、およびコマンドライン引数の処理に関する広範な変更が含まれています。最も重要な変更点の一つは、go buildgo runだけでなく、go listgo fixgo vetgo testといった他のGoコマンドも、単一のパッケージを指定する方法として.goファイルのリストを受け入れるようになったことです。これにより、Goツールの柔軟性と使いやすさが向上しました。

コミット

Author: Russ Cox rsc@golang.org Date: Thu Mar 1 12:12:22 2012 -0500 Commit Hash: b03a5f66e8f8a6b36c9d67e82d2edc9b3d4076ba

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

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

元コミット内容

cmd/go: fixes
* Install tools into tool dir always
  (Fixes issue 3049.  Fixes issue 2868.  Fixes issue 2925.)
* Make packages depend on compiler, linker (Fixes issue 3036.)
* Do not recompile packages across roots (Fixes issue 3149.)
* Allow use of binary-only packages (Fixes issue 2775.)
* Avoid duplicate cgo dependencies (Fixes issue 3001.)
* Show less in go get -x.  (Fixes issue 2926.)
* Do not force repo root for existing checkout (Fixes issue 2969.)
* Show full syntax error list always (Fixes issue 2811.)
* Clean arguments before processing (Fixes issue 3034.)
* Add flags for compiler, linker arguments (Fixes issue 2996.)
* Pass flags in make.bash (Fixes issue 3091.)
* Unify build flags, defined in one place.
* Clean up error messages (Fixes issue 3075.  Fixes issue 2923.)
* Support local import paths (Fixes issue 3118.)
* Allow top-level package outside $GOPATH (Fixes issue 3009.)

In addition to these fixes, all commands now take a list of
go files as a way to specify a single package, just as go build and
go run always have.  This means you can:

        go list -json x.go
        go fix x.go
        go vet x.go
        go test x_test.go

Preliminary tests in test.bash.
Mainly testing things that the ordinary build does not.
I don't mind if the script doesn't run on Windows.

I expect that gccgo support is now broken, and I hope that
people will feel free to file issues and/or send CLs to fix it.  :-)

R=golang-dev, dsymonds, r, rogpeppe
CC=golang-dev
https://golang.org/cl/5708054

変更の背景

このコミットは、Go開発初期におけるgoコマンドの成熟と安定化を目的としています。当時のgoコマンドはまだ発展途上にあり、ユーザーからのフィードバックやバグ報告が多数寄せられていました。このコミットで修正された主な問題は以下の通りです。

  • ツールのインストールパスの不整合 (Issue 3049, 2868, 2925): go installでビルドされたツールが常に適切なtoolディレクトリにインストールされるように修正されました。以前は、ツールのインストール場所が不安定で、ユーザーが期待するパスに配置されないことがありました。
  • パッケージの依存関係の不備 (Issue 3036): パッケージがコンパイラやリンカに適切に依存するように変更されました。これにより、ビルドの整合性が向上し、不必要な再ビルドが減少しました。
  • 異なるルート間での再コンパイル (Issue 3149): $GOROOT$GOPATHのような異なるルート間でパッケージが不必要に再コンパイルされる問題が修正されました。これにより、ビルド時間が短縮され、効率が向上しました。
  • バイナリオンリーパッケージのサポート (Issue 2775): ソースコードが提供されていないバイナリオンリーのパッケージを使用できるようになりました。これは、プロプライエタリなライブラリや配布形式をサポートするために重要でした。
  • Cgoの依存関係の重複 (Issue 3001): Cgoを使用する際に、依存関係が重複してビルドされる問題が修正されました。これにより、ビルドの効率が向上し、潜在的なエラーが減少しました。
  • go get -xの冗長性 (Issue 2926): go get -xコマンドの出力が冗長すぎたため、より簡潔になるように調整されました。-xフラグは詳細な実行ステップを表示しますが、過度な情報はかえって可読性を損ねます。
  • 既存のチェックアウトに対するリポジトリルートの強制 (Issue 2969): go getが既存のチェックアウトに対して不必要にリポジトリルートを強制する問題が修正されました。これにより、ユーザーが手動で管理しているリポジトリの扱いが改善されました。
  • 構文エラーリストの表示 (Issue 2811): 構文エラーが発生した際に、完全なエラーリストが常に表示されるようになりました。これにより、デバッグが容易になりました。
  • 引数のクリーンアップ (Issue 3034): コマンドライン引数が処理前に適切にクリーンアップされるようになりました。これにより、予期せぬ引数による問題が回避されます。
  • コンパイラ・リンカ引数用フラグの追加 (Issue 2996, 3091): コンパイラ(5g, 6g, 8g)やリンカ(5l, 6l, 8l)に引数を渡すための新しいフラグ(-gcflags, -ldflags, -gccgoflags)が追加されました。これにより、ビルドプロセスのカスタマイズ性が向上しました。また、これらのフラグがmake.bashスクリプトでも適切に扱われるようになりました。
  • ビルドフラグの統一: 複数のコマンドで共通して使用されるビルドフラグが、一元的に定義・管理されるようになりました。これにより、コードの重複が減り、保守性が向上しました。
  • エラーメッセージの改善 (Issue 3075, 2923): エラーメッセージがより明確で分かりやすくなるように改善されました。
  • ローカルインポートパスのサポート (Issue 3118): ./../で始まるローカルなインポートパスが適切にサポートされるようになりました。これにより、プロジェクト内のモジュール間の依存関係の指定がより柔軟になりました。
  • $GOPATH外のトップレベルパッケージの許可 (Issue 3009): $GOPATHの外部にあるトップレベルのパッケージもGoコマンドで扱えるようになりました。これは、特定のプロジェクト構造や開発ワークフローにおいて有用です。
  • Goファイルのリストを引数として受け入れる機能の拡張: go buildgo runだけでなく、go list, go fix, go vet, go testといった他のGoコマンドも、単一のパッケージを指定する方法として.goファイルのリストを受け入れるようになりました。これにより、特定のファイルに対して直接コマンドを実行できる柔軟性が提供され、開発者の利便性が大幅に向上しました。

これらの変更は、Goのビルドシステムとコマンドラインツールの堅牢性、効率性、および使いやすさを向上させる上で重要なステップでした。

前提知識の解説

このコミットの変更内容を理解するためには、以下のGo言語およびGoツールの基本的な概念を理解しておく必要があります。

  • Goワークスペースと環境変数 (GOPATH, GOROOT):

    • GOROOT: Goのインストールディレクトリを指します。Goの標準ライブラリのソースコードやツールチェイン(コンパイラ、リンカなど)がここに格納されています。
    • GOPATH: Goのワークスペースのルートディレクトリを指します。ユーザーが開発するGoプロジェクトのソースコード、コンパイル済みパッケージ、実行可能ファイルがここに配置されます。通常、srcpkgbinの3つのサブディレクトリを持ちます。
      • src: ソースコードが置かれます。
      • pkg: コンパイル済みのパッケージアーカイブが置かれます。
      • bin: 実行可能ファイルが置かれます。
    • Goのビルドシステムは、これらの環境変数に基づいてパッケージを検索し、ビルドします。
  • Goパッケージとインポートパス:

    • Goのコードはパッケージに分割されます。パッケージは、関連する機能の集合をカプセル化したものです。
    • インポートパス: パッケージを一意に識別するための文字列です。例えば、"fmt"は標準ライブラリのフォーマットパッケージを、"github.com/user/repo/mypkg"はGitHub上のリポジトリにあるパッケージを指します。
    • ローカルインポートパス: ./../で始まるパスで、現在のディレクトリからの相対パスでパッケージを指定します。
  • goコマンド:

    • Go言語のビルド、テスト、依存関係管理などを行うための主要なコマンドラインツールです。
    • go build: ソースコードをコンパイルして実行可能ファイルやパッケージアーカイブを生成します。
    • go install: go buildと同様にコンパイルを行いますが、生成された実行可能ファイルやパッケージアーカイブを$GOPATH/bin$GOPATH/pkg(または$GOROOT/bin, $GOROOT/pkg)にインストールします。
    • go get: リモートリポジトリからGoパッケージのソースコードをダウンロードし、必要に応じてビルド・インストールします。
    • go test: パッケージのテストを実行します。
    • go fix: 古いGoのコードを新しいGoのバージョンに合わせて自動的に修正します。
    • go vet: Goのソースコードを静的に解析し、潜在的なバグや疑わしい構造を報告します。
    • go list: 指定されたパッケージの情報を表示します。
    • go run: 指定されたGoソースファイルをコンパイルし、実行します。
  • Goツールチェイン (5g, 6g, 8g, 5l, 6l, 8l):

    • Goの初期のバージョンでは、異なるアーキテクチャ(例: 5はARM、6はamd64、8は386)に対応するコンパイラ(g)とリンカ(l)が個別のコマンドとして存在しました。例えば、6gはamd64アーキテクチャ用のGoコンパイラ、6lはamd64アーキテクチャ用のGoリンカです。
    • これらのツールは、Goのソースコードを機械語に変換し、実行可能ファイルを生成する役割を担います。
  • gccgo:

    • Go言語のフロントエンドを持つGCCコンパイラです。Goの標準ツールチェインとは異なる実装であり、C/C++コードとの連携がより容易な場合があります。このコミットでは、gccgoのサポートが一時的に壊れる可能性が示唆されています。
  • Cgo:

    • GoプログラムからC言語のコードを呼び出すためのGoの機能です。Cgoを使用すると、GoとCの間の相互運用が可能になります。Cgoを使用するパッケージは、Cコンパイラ(通常はGCC)とリンカを必要とします。
  • ビルドタグ (Build Tags):

    • Goのソースファイルに特定のコメント(例: // +build linux,amd64)を記述することで、そのファイルを特定の環境(OS、アーキテクチャなど)でのみビルド対象に含めるように制御するメカニズムです。これにより、プラットフォーム固有のコードを管理できます。
  • make.bash:

    • Goのソースコードをビルドするためのシェルスクリプトです。Goのツールチェイン自体をビルドする際に使用されます。

これらの概念を理解することで、コミットがGoのビルドシステムと開発ワークフローに与える影響をより深く把握できます。

技術的詳細

このコミットは、Goコマンドの内部構造とビルドロジックに多岐にわたる変更を加えています。主要な技術的変更点は以下の通りです。

  1. ビルドフラグの統一と拡張:

    • src/cmd/go/build.gosrc/cmd/go/install.gosrc/cmd/go/run.gosrc/cmd/go/test.gosrc/cmd/go/doc.goなどのファイルで、go buildgo installgo rungo testコマンドが共有するビルドフラグ(-a, -n, -p, -v, -work, -x)がaddBuildFlags関数によって一元的に管理されるようになりました。
    • 新たに、コンパイラ引数(-gcflags)、リンカ引数(-ldflags)、gccgoコンパイラ/リンカ引数(-gccgoflags)、ビルドタグ(-tags)を指定するためのフラグが追加されました。これらのフラグはstringsFlag型(flag.Varインターフェースを実装)によって処理され、複数の引数をスペース区切りで受け取ることができます。
    • これにより、ユーザーはGoのビルドプロセスをより細かく制御できるようになり、特定のコンパイラオプションやリンカオプションを簡単に渡せるようになりました。
  2. Goファイルのリストをパッケージ引数として受け入れる機能の拡張:

    • 以前はgo buildgo runのみが.goファイルのリストを引数として受け入れていましたが、このコミットによりgo list, go fix, go vet, go testなどの他のコマンドも同様に.goファイルのリストを引数として受け入れるようになりました。
    • この機能はgoFilesPackage関数(src/cmd/go/build.go)によって実装されています。この関数は、指定された.goファイルのリストから「合成された」単一のパッケージを作成します。
    • 具体的には、build.ContextReadDirフィールドをオーバーライドし、指定されたファイルのみが存在する仮想的なディレクトリをシミュレートします。これにより、Goのビルドシステムはこれらのファイルを単一のパッケージとして扱います。
    • この変更は、src/cmd/go/main.gopackagesForBuild関数や、各コマンドのUsageLineの更新に反映されています。
  3. ビルドパスと環境変数の管理の改善:

    • builder構造体からgoarch, goos, arch, exeなどのフィールドが削除され、グローバル変数goarch, goos, archChar, exeSuffixとして定義されました。これにより、ビルド環境に関する情報が一元化され、並列ビルド時の状態管理が簡素化されました。
    • GOROOTGOBINのパス解決ロジックがsrc/cmd/go/build.goinit関数とdefaultGobin関数に移動し、より堅牢になりました。
    • build.Path(GoのソースツリーとGOPATHのリスト)の代わりに、buildContext.SrcDirs()buildContext.GOPATHが使用されるようになり、GoのビルドパッケージのAPIに準拠するようになりました。
  4. Cgoおよびツールチェインの統合の改善:

    • toolchainインターフェースが拡張され、compiler()linker()メソッドが追加されました。これにより、Goツールチェイン(5g/6g/8gなど)とgccgoの両方で、使用するコンパイラとリンカを抽象化して指定できるようになりました。
    • goToolchaingccgoToolchainの実装が、新しいビルドフラグ(-gcflags, -ldflags, -gccgoflags)を考慮するように更新されました。
    • Cgoの処理において、pkg-configの利用が改善され、Cgo関連のフラグ(CgoCFLAGS, CgoLDFLAGS, CgoPkgConfig)がPackage構造体から直接参照されるようになりました。
    • cgo関数内のb.goos != toolGOOSチェックにより、クロスコンパイル時にCgoが使用できないことが明示的にチェックされるようになりました。
  5. エラー処理と出力の改善:

    • PackageError構造体のError()メソッドが変更され、エラーメッセージのフォーマットが改善されました。特に、Posフィールド(ファイル名と行番号)がエラーメッセージに含まれるようになりました。
    • builder.showOutput関数がshortPathヘルパー関数を使用するようになり、出力されるパスが現在の作業ディレクトリからの相対パスで表示されるようになり、可読性が向上しました。
    • builder.run関数にshortenDir引数が追加され、コマンド実行時の出力ディレクトリ表示を制御できるようになりました。
  6. パッケージ情報のロードとキャッシュの改善:

    • loadPackage関数がloadImportにリネームされ、build.Context.ImportAPIを使用するように変更されました。これにより、Goのビルドパッケージが提供するより高レベルなパッケージロード機能を利用するようになりました。
    • パッケージキャッシュのキーが、インポートパスだけでなく、ローカルパス(絶対パスまたは相対パス)も考慮するように変更されました。これにより、同じ物理ディレクトリを指す異なるパスからのインポートが適切にキャッシュされるようになりました。
    • Package構造体のフィールドにJSONタグが追加され、go list -jsonコマンドの出力がより正確になりました。

これらの変更は、Goのビルドシステムをよりモジュール化し、堅牢にし、将来の拡張に対応できるようにするための重要なステップでした。特に、ビルドフラグの統一と.goファイルリストの引数としてのサポートは、開発者の生産性向上に大きく貢献しました。

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

このコミットでは、Goコマンドのビルドシステムとパッケージ管理に関連する多数のファイルが変更されています。主要な変更ファイルとその概要は以下の通りです。

  • src/cmd/go/build.go:

    • cmdBuildUsageLineが簡潔になり、ビルドフラグの統一が反映されました。
    • addBuildFlags関数が、共通のビルドフラグと新しいコンパイラ/リンカフラグ(-gcflags, -ldflags, -gccgoflags, -tags)を追加するように変更されました。
    • stringsFlag型が追加され、スペース区切りの文字列をフラグとして受け入れるようになりました。
    • runBuild関数が、.goファイルリストをパッケージ引数として処理するためにgoFilesPackageを使用するように変更されました。
    • builder構造体からビルド環境関連のフィールド(goarch, goos, arch, exe, gcflags)が削除され、グローバル変数に移行しました。
    • goFilesPackage関数が大幅に改修され、指定された.goファイルから合成パッケージを作成するロジックが実装されました。
    • builder.actionbuilder.buildbuilder.installbuilder.includeArgsbuilder.copyFilebuilder.runなどのメソッドが、新しいビルド環境変数やパス解決ロジックを使用するように更新されました。
    • shortPathヘルパー関数が追加され、出力パスの短縮に利用されるようになりました。
  • src/cmd/go/clean.go:

    • cmdCleanUsageLine[importpath...]から[packages]に変更され、パッケージリストの概念が統一されました。
  • src/cmd/go/doc.go:

    • go helpのトピックリストからimportpathが削除され、packagesが追加されました。
    • 各コマンドのUsageLineLong説明が更新され、新しいビルドフラグやパッケージリストの概念が反映されました。
    • go testのヘルプメッセージが大幅に更新され、テストバイナリのフラグとgo test自身のフラグが明確に区別されました。
    • Example関数のドキュメントが更新され、Output:コメントの形式が明確化されました。
  • src/cmd/go/fix.go:

    • cmdFixUsageLine[importpath...]から[packages]に変更されました。
  • src/cmd/go/fmt.go:

    • cmdFmtUsageLine[importpath...]から[packages]に変更されました。
    • cmdDocUsageLineも同様に変更されました。
    • runDoc関数に、command-line argumentsとして指定されたパッケージファイルリストをgo docが受け入れないようにするチェックが追加されました。
  • src/cmd/go/get.go:

    • cmdGetUsageLine[importpath...]から[packages]に変更されました。
    • downloadPackage関数が、既存のチェックアウトに対するリポジトリルートの強制を避けるロジックを含むように変更されました。
    • build.Pathの代わりにbuildContext.GOPATHが使用されるようになりました。
  • src/cmd/go/help.go:

    • helpImportpathhelpPackagesにリネームされ、パッケージリストの概念に関するヘルプメッセージが更新されました。特に、.goファイルのリストを単一のパッケージとして扱う特殊なケースが説明されました。
  • src/cmd/go/list.go:

    • cmdListUsageLine[importpath...]から[packages]に変更されました。
  • src/cmd/go/main.go:

    • commandsリストからhelpImportpathが削除され、helpPackagesが追加されました。
    • importPaths関数が、Windowsパスの正規化やローカルインポートパスの処理を改善するように変更されました。
    • allPackages関数とallPackagesInFS関数が、build.ScanDirの代わりにbuild.ImportDirを使用するように更新されました。
    • isLocalPathヘルパー関数が削除されました(build.IsLocalImportに置き換えられました)。
  • src/cmd/go/pkg.go:

    • Package構造体にJSONタグが追加され、Rootフィールドが追加されました。
    • copyBuildヘルパー関数が追加され、build.Packageの情報をPackage構造体にコピーするようになりました。
    • PackageErrorError()メソッドが変更され、エラーメッセージのフォーマットが改善されました。
    • loadPackage関数がloadImportにリネームされ、build.Context.ImportAPIを使用するように大幅に改修されました。
    • パッケージキャッシュのキーが、インポートパスだけでなく、ローカルパスも考慮するように変更されました。
    • scanPackage関数が削除されました(loadImportに統合されました)。
  • src/cmd/go/run.go:

    • cmdRunUsageLineが簡潔になり、ビルドフラグの統一が反映されました。
  • src/cmd/go/test.bash:

    • 新しいテストスクリプトが追加され、このコミットで導入された機能(特に.goファイルリストを引数として渡す機能)のテストが行われました。
  • src/cmd/go/test.go:

    • cmdTestUsageLineが簡潔になり、ビルドフラグの統一が反映されました。
  • src/cmd/go/vcs.go:

    • downloadPackage関数が、既存のチェックアウトの処理を改善するように変更されました。
  • src/cmd/go/vet.go:

    • cmdVetUsageLine[importpath...]から[packages]に変更されました。
  • src/make.bash:

    • ビルドフラグの渡し方が変更され、新しいフラグ(-gcflags, -ldflags, -gccgoflags)がサポートされるようになりました。

これらの変更は、Goコマンドの内部アーキテクチャを近代化し、より柔軟で堅牢なビルドシステムを構築するための基盤を築きました。

コアとなるコードの解説

このコミットの核心的な変更は、Goコマンドが.goファイルのリストを単一のパッケージとして扱う能力を拡張した点と、ビルドフラグの統一です。ここでは、その中心となるコード変更をいくつかピックアップして解説します。

1. goFilesPackage 関数の変更 (src/cmd/go/build.go)

この関数は、コマンドラインで指定された.goファイルのリストから、Goのビルドシステムが認識できるPackage構造体を生成する役割を担います。以前はgo buildgo run専用でしたが、このコミットで汎用化されました。

変更前 (抜粋):

func goFilesPackage(gofiles []string, target string) *Package {
	// ...
	ctxt := buildContext
	ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dir, nil }
	pwd, _ := os.Getwd()
	var stk importStack
	pkg := scanPackage(&ctxt, &build.Tree{Path: "."}, "<command line>", "<command line>", pwd+"/.", &stk, true)
	// ...
}

変更後 (抜粋):

func goFilesPackage(gofiles []string) *Package {
	// ...
	var stk importStack
	ctxt := buildContext
	ctxt.UseAllFiles = true

	// Synthesize fake "directory" that only shows the named files,
	// to make it look like this is a standard package or
	// command directory.  So that local imports resolve
	// consistently, the files must all be in the same directory.
	var dirent []os.FileInfo
	var dir string
	for _, file := range gofiles {
		fi, err := os.Stat(file)
		// ... error handling ...
		dir1, _ := filepath.Split(file)
		if dir == "" {
			dir = dir1
		} else if dir != dir1 {
			fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
		}
		dirent = append(dirent, fi)
	}
	ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }

	if !filepath.IsAbs(dir) {
		dir = filepath.Join(cwd, dir)
	}

	bp, err := ctxt.ImportDir(dir, 0)
	pkg := new(Package)
	pkg.load(&stk, bp, err)

	pkg.ImportPath = "command-line arguments"
	if *buildO == "" {
		if pkg.Name == "main" {
			_, elem := filepath.Split(gofiles[0])
			*buildO = elem[:len(elem)-len(".go")]
		} else {
			*buildO = pkg.Name + ".a"
		}
	}
	pkg.target = ""
	pkg.Target = ""
	pkg.Stale = true

	computeStale([]*Package{pkg})
	return pkg
}

解説: 変更後のgoFilesPackageは、以下の点で大きく改善されています。

  • build.Context.ReadDirの利用: build.ContextReadDirフィールドをカスタム関数でオーバーライドすることで、Goのビルドシステムがファイルシステムを読み込む際に、指定された.goファイルのみが存在するかのように振る舞わせています。これにより、実際のディレクトリ構造に関わらず、コマンドラインで指定されたファイル群を単一のパッケージとして認識させることが可能になります。
  • 単一ディレクトリ制約: 指定された.goファイルがすべて同じディレクトリにあることを強制します。これは、ローカルインポート(./../)の解決を整合性のあるものにするためです。
  • build.Context.ImportDirの利用: go/buildパッケージのImportDir関数を使用して、指定されたディレクトリ(仮想的なものを含む)からパッケージ情報をロードします。これにより、Goのビルドパッケージが提供する堅牢なパッケージ解析ロジックを活用できます。
  • 出力ファイル名の自動決定: mainパッケージの場合、最初の.goファイル名から実行可能ファイル名を自動的に決定します。
  • pkg.Stale = true: 合成されたパッケージは常に再ビルドが必要であるとマークされます。

この変更により、go list x.goのように、特定のファイルに対してGoコマンドを実行する際の柔軟性が大幅に向上しました。

2. addBuildFlags 関数の変更 (src/cmd/go/build.go)

この関数は、go buildgo installgo rungo testなどのコマンドに共通のビルドフラグを追加します。

変更前 (抜粋):

func addBuildFlags(cmd *Command) {
	cmd.Flag.BoolVar(&buildA, "a", false, "")
	cmd.Flag.BoolVar(&buildN, "n", false, "")
	cmd.Flag.BoolVar(&buildP, "p", false, "") // This was a bool, not int
	cmd.Flag.BoolVar(&buildV, "v", false, "")
	cmd.Flag.BoolVar(&buildX, "x", false, "")
	cmd.Flag.BoolVar(&buildWork, "work", false, "")
	// ... -t flag for build tags ...
}

変更後 (抜粋):

func addBuildFlags(cmd *Command) {
	cmd.Flag.BoolVar(&buildA, "a", false, "")
	cmd.Flag.BoolVar(&buildN, "n", false, "")
	cmd.Flag.IntVar(&buildP, "p", runtime.NumCPU(), "") // Now an int
	cmd.Flag.BoolVar(&buildV, "v", false, "")
	cmd.Flag.BoolVar(&buildX, "x", false, "")
	cmd.Flag.BoolVar(&buildWork, "work", false, "")
	cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
	cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
	cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
	cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
}

解説:

  • -pフラグの型変更: 並列ビルド数を指定する-pフラグが、ブール値から整数値(runtime.NumCPU()がデフォルト値)に変更されました。これにより、並列度を明示的に制御できるようになりました。
  • 新しいビルドフラグの追加:
    • -gcflags: Goコンパイラ(5g, 6g, 8g)に渡す引数を指定します。
    • -ldflags: Goリンカ(5l, 6l, 8l)に渡す引数を指定します。
    • -gccgoflags: gccgoコンパイラ/リンカに渡す引数を指定します。
    • -tags: ビルドタグを指定します。
  • stringsFlag型の導入: これらの新しいフラグはstringsFlagというカスタム型を使用しています。この型はflag.Valueインターフェースを実装しており、コマンドラインからスペース区切りの文字列リストを受け取ることができます。これにより、複数のコンパイラ/リンカオプションを単一のフラグで指定できるようになりました。

この変更により、Goのビルドプロセスに対するユーザーの制御が大幅に強化され、より複雑なビルドシナリオに対応できるようになりました。

3. toolchain インターフェースの変更 (src/cmd/go/build.go)

Goのビルドシステムは、異なるツールチェイン(標準のGoツールチェインとgccgo)を抽象化するためにtoolchainインターフェースを使用しています。

変更前 (抜粋):

type toolchain interface {
	gc(b *builder, p *Package, obj string, importArgs []string, gofiles []string) (ofile string, err error)
	cc(b *builder, p *Package, objdir, ofile, cfile string) error
	asm(b *builder, p *Package, obj, ofile, sfile string) error
	pkgpath(basedir string, p *Package) string
	pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
	ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
}

変更後 (抜粋):

type toolchain interface {
	// ... existing methods ...
	compiler() string
	linker() string
}

解説: toolchainインターフェースにcompiler()linker()メソッドが追加されました。これにより、各ツールチェインの実装(goToolchaingccgoToolchain)は、自身が使用するコンパイラとリンカのコマンド名を返す責任を持つようになりました。この抽象化により、ビルドロジックは特定のコンパイラ/リンカのパスに依存することなく、より汎用的に記述できるようになりました。

例えば、goToolchaincompiler()tool(archChar + "g")を返し、gccgoToolchaincompiler()gccgoBinを返します。これにより、ビルドプロセスは現在アクティブなツールチェインに応じて適切なコマンドを呼び出すことができます。

これらの変更は、Goのビルドシステムの柔軟性と拡張性を高め、将来のツールチェインの追加や変更に容易に対応できるようにするための重要な基盤となりました。

関連リンク

参考にした情報源リンク