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

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

このコミットは、Go言語のコマンドラインツール go のサブコマンドである go run の挙動に関する修正です。具体的には、go run コマンドが go build コマンドと同様にビルドフラグ(buildflags)を適切に尊重するように変更されています。これにより、go run のドキュメントと実装の整合性が取られ、ユーザーが期待する動作に近づきました。

コミット

  • コミットハッシュ: eb2163ffbb9ce586ff01332c41549c8bb28462af
  • 作者: Maxim Pimenov mpimenov@google.com
  • コミット日時: 2012年3月6日 火曜日 09:33:35 -0500
  • 変更ファイル: src/cmd/go/run.go
  • 変更概要: go run コマンドがビルドフラグを尊重するように修正。

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

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

元コミット内容

cmd/go: honour buildflags in go run

Either documentation or implementation
of go run's flags is wrong currently.
This change assumes the documentation
to be right.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5752054

変更の背景

このコミットの背景には、go run コマンドのフラグに関するドキュメントと実際の挙動との間に不一致があったという問題があります。コミットメッセージによると、「go run のフラグに関するドキュメントか実装のどちらかが現在間違っている」と述べられています。この変更は、ドキュメントが正しいという前提に基づき、go rungo build と同様のビルドフラグ(例: -a, -n, -x)を適切に処理するように修正することを目的としています。これにより、ユーザーが go run を使用する際に、go build と一貫したフラグの挙動を期待できるようになります。

前提知識の解説

Go コマンドとビルドフラグ

Go言語には、ソースコードのコンパイル、実行、テスト、パッケージ管理などを行うための統合されたコマンドラインツール go があります。この go コマンドには、様々なサブコマンドが存在します。

  • go run: ソースファイルをコンパイルし、その場で実行するコマンドです。一時的な実行可能ファイルを生成し、実行後に削除します。開発中のスクリプトや簡単なプログラムの実行によく使われます。
  • go build: ソースファイルをコンパイルし、実行可能ファイルを生成するコマンドです。生成された実行可能ファイルは、指定されたディレクトリ(デフォルトではカレントディレクトリ)に保存されます。

これらのコマンドは、ビルドプロセスを制御するための様々な「ビルドフラグ」をサポートしています。ビルドフラグは、コンパイルやリンクの挙動を変更するために使用されます。

一般的なビルドフラグの例:

  • -a: 依存関係にあるパッケージも含め、すべてのパッケージを強制的に再ビルドします。
  • -n: 実行されるコマンド(コンパイル、リンクなど)を表示しますが、実際には実行しません。ドライランとして利用されます。
  • -x: 実行されるコマンドをすべて表示します。デバッグやビルドプロセスの詳細を確認する際に役立ちます。
  • -race: データ競合検出を有効にします。並行処理のバグを見つけるのに非常に有用です。
  • -tags <tags>: ビルドタグを指定します。これにより、特定のタグが指定された場合にのみコンパイルされるコードブロックを定義できます(条件付きコンパイル)。
  • -ldflags <flag...>: リンカに渡すフラグを指定します。バージョン情報などをバイナリに埋め込む際によく使われます。
  • -gcflags <flag...>: コンパイラに渡すフラグを指定します。最適化の無効化などに使われます。

init() 関数と Flag パッケージ

Go言語では、init() 関数はパッケージがインポートされた際に自動的に実行される特別な関数です。通常、プログラムの初期化処理(例: グローバル変数の設定、コマンドラインフラグの登録)に使用されます。

Goの標準ライブラリには、コマンドラインフラグを解析するための flag パッケージがあります。このパッケージを使用すると、プログラムが受け取るコマンドライン引数を簡単に定義し、解析できます。cmdRun.Flag は、go run コマンドに特有のフラグセットを管理するための flag.FlagSet インスタンスであると推測されます。

技術的詳細

このコミットの技術的な核心は、go run コマンドの初期化処理において、個別のビルドフラグ(-a, -n, -x)を手動で登録する代わりに、addBuildFlags という共通のヘルパー関数を呼び出すように変更した点です。

変更前のコードでは、src/cmd/go/run.goinit() 関数内で、以下のように各ビルドフラグが明示的に cmdRun.Flag に登録されていました。

func init() {
    cmdRun.Run = runRun // break init loop

    cmdRun.Flag.BoolVar(&buildA, "a", false, "")
    cmdRun.Flag.BoolVar(&buildN, "n", false, "")
    cmdRun.Flag.BoolVar(&buildX, "x", false, "")
}

これは、go build など他のコマンドでも同様のフラグを登録する必要がある場合、コードの重複や、フラグの追加・変更があった場合のメンテナンスコストの増加につながります。

このコミットでは、これらの個別のフラグ登録を削除し、代わりに addBuildFlags(cmdRun) という一行のコードに置き換えています。

func init() {
    cmdRun.Run = runRun // break init loop

    addBuildFlags(cmdRun)
}

addBuildFlags 関数は、Goコマンドの内部で定義されている共通のヘルパー関数であり、go buildgo install など、ビルドプロセスを伴う他のサブコマンドでも使用されています。この関数は、go コマンド全体で共通して利用されるビルド関連のフラグ(-a, -n, -x, -race, -tags など)を、指定された flag.FlagSet に一括して登録する役割を担っています。

この変更により、以下のメリットが生まれます。

  1. コードの重複排除: 複数のサブコマンドで同じビルドフラグを登録するコードが一本化され、重複がなくなります。
  2. メンテナンス性の向上: 新しいビルドフラグが追加されたり、既存のフラグの挙動が変更されたりした場合でも、addBuildFlags 関数を修正するだけで、関連するすべてのサブコマンドにその変更が反映されます。これにより、一貫性が保たれ、バグの発生リスクが低減します。
  3. ドキュメントと実装の整合性: go rungo build と同じビルドフラグをサポートするというドキュメントの意図が、実装レベルで保証されるようになります。

この修正は、Goコマンドラインツールの設計におけるモジュール化と再利用性の原則に従ったものであり、長期的なコードベースの健全性を向上させるための重要なステップと言えます。

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

src/cmd/go/run.go ファイルの init() 関数内:

--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -26,9 +26,7 @@ See also: go build.
 func init() {
  cmdRun.Run = runRun // break init loop

-	cmdRun.Flag.BoolVar(&buildA, "a", false, "")
-	cmdRun.Flag.BoolVar(&buildN, "n", false, "")
-	cmdRun.Flag.BoolVar(&buildX, "x", false, "")
+	addBuildFlags(cmdRun)
 }

 func printStderr(args ...interface{}) (int, error) {

コアとなるコードの解説

この変更は、go run コマンドの初期化ロジックを簡素化し、他のGoコマンドとの一貫性を高めるものです。

変更前は、go run コマンドがサポートする特定のビルドフラグ(-a, -n, -x)を、cmdRun.Flag.BoolVar を使って個別に登録していました。これは、各フラグに対応するブール型変数(buildA, buildN, buildX)を定義し、それらの変数がコマンドラインでフラグが指定されたかどうかに応じて true/false に設定されるようにするものです。

変更後は、これらの個別のフラグ登録が削除され、代わりに addBuildFlags(cmdRun) という関数呼び出しに置き換えられました。addBuildFlags は、Goコマンドの内部で定義されている共通のユーティリティ関数であり、go buildgo install など、ビルド関連のフラグを必要とする他のGoコマンドでも使用されています。この関数は、cmdRun に関連付けられたフラグセット(cmdRun.Flag)に、Goのビルドシステムで共通的に使用されるすべてのビルドフラグをまとめて登録します。

これにより、go run は、明示的にコードに記述されていなかった他のビルドフラグ(例: -race, -tags など)も自動的にサポートするようになり、go build とのフラグの互換性が向上します。この修正は、コードの重複を減らし、将来的なフラグの追加や変更に対するメンテナンス性を向上させる、より堅牢な設計パターンへの移行を示しています。

関連リンク

参考にした情報源リンク

  • go.dev: go run command and build flags
  • debian.org: go run man page
  • google.com: go run command usage
  • fig.io: Common Go build flags
  • dev.to: Go build flags explained
  • medium.com: Go build flags for race detection and compiler flags
  • stackoverflow.com: Using build tags with go run
  • medium.com: Embedding version information with ldflags
  • golangbridge.org: go run . usage
  • Go言語の公式ドキュメント (go.dev)
  • Go言語のソースコード (GitHub)
  • go help build および go help run コマンドの出力