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

[インデックス 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ファイルにおいて、以下の変更が行われました。

  1. import文に"strings"パッケージが追加されました。これは、コマンドライン引数を結合するために使用されます。
  2. 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フラグの意図を正確に反映し、ユーザーが期待するデバッグ情報を提供できるようになりました。

関連リンク

参考にした情報源リンク