[インデックス 11297] ファイルの概要
このコミットは、Go言語の公式ツールチェーンの一部であるgo
コマンドのrun
サブコマンドに関連する変更です。具体的には、src/cmd/go/run.go
ファイルが修正されており、go run
コマンドが-n
(ドライラン)および-x
(実行コマンド表示)フラグを正しく処理するように改善されています。このファイルは、Goソースファイルをコンパイルして実行するgo run
コマンドのロジックを実装しています。
コミット
go run
コマンドが-n
および-x
フラグを正しく処理するように修正。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c088ebef16c35106771535581a53a262b7c9200ea
元コミット内容
go run: correctly handle -n and -x flags
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5557069
変更の背景
go run
コマンドは、指定されたGoソースファイルをコンパイルし、その結果生成されたバイナリを実行する便利なツールです。しかし、このコミット以前は、go run
コマンドに-n
(ドライラン、実行されるコマンドを表示するが実行しない)や-x
(実行されるコマンドを表示する)といったフラグを渡した場合、その挙動が期待通りではありませんでした。特に、コンパイルされたバイナリを実行する段階で、これらのフラグが適切に考慮されていなかったと考えられます。
開発者がビルドプロセスや実行プロセスをデバッグしたり、どのようなコマンドが内部的に実行されているかを確認したりする際に、-n
や-x
フラグは非常に重要です。この修正は、go run
がこれらのフラグの意図を完全に尊重し、ユーザーに正確な情報を提供できるようにするために行われました。これにより、go run
の透明性とデバッグ可能性が向上します。
前提知識の解説
go run
コマンド: Go言語のソースファイルを一時的にコンパイルし、その場で実行するためのコマンドです。通常、単一のGoファイルや小さなプログラムのテスト、実行に用いられます。内部的には、まずソースコードをビルドし、その後に生成された実行可能ファイルを起動します。go build
コマンドのフラグ:-n
: "dry run" フラグ。ビルドや実行の際に、実際にコマンドを実行する代わりに、実行されるであろうコマンドを表示します。これは、ビルドプロセスがどのように進行するかを事前に確認するのに役立ちます。-x
: "print commands" フラグ。ビルドや実行の際に、実際に実行されるすべてのコマンドを表示します。これは、ビルドシステムが何をしているかを詳細に追跡するのに役立ちます。
- Goツールチェーンの内部構造:
go
コマンドは、cmd/go
パッケージに実装されており、様々なサブコマンド(build
,run
,test
など)がそれぞれ独立したロジックを持っています。これらのサブコマンドは、共通のbuilder
構造体やaction
構造体などを利用して、ビルドや実行のタスクを管理しています。 builder
構造体とrunProgram
メソッド:cmd/go
パッケージ内で、builder
構造体はビルドプロセス全体を管理する役割を担っています。runProgram
メソッドは、既にコンパイルされたプログラム(バイナリ)を実行するための具体的なロジックを含んでいます。
技術的詳細
go run
コマンドは、まずGoソースファイルを一時ディレクトリにコンパイルし、その後に生成されたバイナリを実行します。このコミット以前は、コンパイルステップでは-n
や-x
フラグが考慮されていたかもしれませんが、最終的に生成されたバイナリを実行する段階(runProgram
メソッド内)では、これらのフラグが無視されていました。
この修正の核心は、runProgram
メソッド内でbuildN
(-n
フラグが指定されたかを示す内部変数)またはbuildX
(-x
フラグが指定されたかを示す内部変数)が真である場合に、実行されるコマンドをb.showcmd
メソッドを使って表示するようにした点です。
b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
:b.showcmd
は、go
コマンドが内部的に実行するシェルコマンドをユーザーに表示するためのヘルパーメソッドです。a.deps[0].target
は、実行されるバイナリのパスを指します。a.args
は、そのバイナリに渡される引数のスライスです。strings.Join(a.args, " ")
は、引数のスライスをスペースで結合して単一の文字列にし、シェルコマンドとして表示できるようにします。
if buildN { return nil }
:- もし
-n
フラグ(ドライラン)が指定されている場合、コマンドは表示されるものの、実際の実行は行われません。runProgram
メソッドはここで早期にnil
を返して終了し、バイナリの起動をスキップします。これにより、-n
フラグの「実行しない」という意図が完全に尊重されます。
- もし
- これらの変更は、
runProgram
メソッドの冒頭に追加されており、実際のプログラム実行ロジック(run(a.deps[0].target, a.args)
)の前に評価されます。これにより、フラグのチェックと表示/スキップが適切に行われるようになります。
コアとなるコードの変更箇所
src/cmd/go/run.go
ファイルにおいて、以下の変更が行われました。
import
文に"strings"
パッケージが追加されました。これは、コマンドライン引数を結合するために使用されます。runProgram
メソッドの冒頭に、-n
または-x
フラグが指定された場合の処理ロジックが追加されました。
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -4,7 +4,9 @@
package main
-import ()
+import (
+ "strings"
+)
var cmdRun = &Command{
UsageLine: "run [-a] [-n] [-x] gofiles... [-- arguments...]",
@@ -42,6 +44,12 @@ func runRun(cmd *Command, args []string) {
// been compiled. We ignore exit status.
func (b *builder) runProgram(a *action) error {
+\tif buildN || buildX {
+\t\tb.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
+\t\tif buildN {
+\t\t\treturn nil
+\t\t}\
+\t}\
run(a.deps[0].target, a.args)
return nil
}
コアとなるコードの解説
追加されたコードブロックは以下の通りです。
if buildN || buildX {
b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
if buildN {
return nil
}
}
if buildN || buildX { ... }
: この条件文は、グローバル変数buildN
(-n
フラグが指定された場合に真)またはbuildX
(-x
フラグが指定された場合に真)のいずれかが真である場合に、内部の処理を実行することを示しています。b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
:b.showcmd
は、builder
構造体のメソッドで、Goツールが実行しようとしているコマンドを標準出力に表示するために使用されます。- 第一引数の
""
は、コマンドのカテゴリを示すプレフィックスですが、ここでは空文字列が渡されています。 - 第二引数の
"%s %s"
は、フォーマット文字列です。 - 第三引数の
a.deps[0].target
は、go run
によってコンパイルされた実行可能ファイルのパス(例:/tmp/go-build.../a.out
)です。 - 第四引数の
strings.Join(a.args, " ")
は、go run
コマンドに渡された追加の引数(--
以降の引数)をスペースで結合した文字列です。例えば、go run main.go -- arg1 arg2
の場合、a.args
は["arg1", "arg2"]
となり、strings.Join
によって"arg1 arg2"
となります。 - この行により、
-x
フラグが指定されていれば、実際に実行されるバイナリとその引数が表示されます。
if buildN { return nil }
:- この条件文は、もし
-n
フラグ(ドライラン)が指定されている場合、つまりbuildN
が真である場合に実行されます。 return nil
は、runProgram
メソッドの実行をここで終了させ、エラーがないことを示します。これにより、run
関数(実際のプログラム実行を行う関数)が呼び出されるのを防ぎ、プログラムが実行されない「ドライラン」の挙動を実現します。
- この条件文は、もし
この変更により、go run
コマンドは-n
および-x
フラグの意図を正確に反映し、ユーザーが期待するデバッグ情報を提供できるようになりました。
関連リンク
- Go Change-List: https://go-review.googlesource.com/c/go/+/5557069
参考にした情報源リンク
- Go Change-List 5557069: https://go-review.googlesource.com/c/go/+/5557069
- Go Command Documentation (go run, go build flags): https://pkg.go.dev/cmd/go (一般的なGoコマンドのドキュメントとして参照)