[インデックス 12484] ファイルの概要
このコミットは、Go言語のテストスイートの一部である test/testlib
スクリプトに対する修正です。test/testlib
は、Goのテスト実行環境をセットアップし、コンパイルおよび実行を行うためのヘルパースクリプトとして機能します。具体的には、6g
コンパイラ(当時のGoコンパイラの一つ)に渡される引数の処理方法を修正し、空の引数が渡されないようにすることで、テストスクリプトの動作を改善しています。
コミット
test: fix testlib to not pass an empty argument to 6g
このコミットは、test/testlib
スクリプトが 6g
コンパイラに空の引数を渡さないように修正します。これにより、run
シェルスクリプトが再び機能するようになります。ただし、bug424.go
の実行行がインポートするパッケージ名を指定していないため、この修正だけでは不十分であると述べられています。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/72faa0303e4330bbdfd1a79f493ba8529f8208a2
元コミット内容
commit 72faa0303e4330bbdfd1a79f493ba8529f8208a2
Author: Ian Lance Taylor <iant@golang.org>
Date: Wed Mar 7 11:16:58 2012 -0800
test: fix testlib to not pass an empty argument to 6g
This change is necessary to make the run shell script work
again, but it is not sufficient as bug424.go's execution line
does not name the package that it imports.
R=golang-dev, gri, rsc
CC=golang-dev
https://golang.org/cl/5771043
変更の背景
この変更の背景には、test/testlib
スクリプトが 6g
コンパイラに不適切な(空の)引数を渡していた問題があります。シェルスクリプトにおいて、意図しない空の引数がコマンドに渡されると、そのコマンドの解釈や実行に予期せぬ問題を引き起こす可能性があります。この場合、6g
コンパイラが空の引数をどのように解釈していたかは不明ですが、それが原因でテスト実行スクリプト(run
シェルスクリプト)が正しく動作しなくなっていたと考えられます。
コミットメッセージには「bug424.go
の実行行がインポートするパッケージ名を指定していないため、この修正だけでは不十分」と明記されており、この修正がより大きな問題(おそらく bug424.go
に関連するコンパイルエラーや実行時エラー)を解決するための一歩であったことが示唆されています。つまり、このコミットは、テストインフラストラクチャの安定性を向上させるための、より広範な取り組みの一部であったと推測されます。
前提知識の解説
6g コンパイラ
6g
は、Go言語の初期のバージョン(Go 1.5以前)で使用されていたコンパイラの一つです。当時のGoツールチェインでは、異なるアーキテクチャ向けに専用のコンパイラが存在しました。
6g
:amd64
(x86-64) アーキテクチャ向け8g
:386
(x86-32) アーキテクチャ向け5g
:arm
アーキテクチャ向け
これらのコンパイラは、.go
ソースファイルをアーキテクチャ固有のオブジェクトファイル(例: amd64
の場合は .6
ファイル)にコンパイルする役割を担っていました。その後、対応するリンカ(例: 6l
)によってこれらのオブジェクトファイルがリンクされ、実行可能なバイナリが生成されました。
Go 1.5以降、これらのアーキテクチャ固有のコンパイラは go tool compile
という単一のコマンドに統合され、6g
のような個別の名前は非推奨となり、削除されました。
シェルスクリプトにおける空の引数渡し
シェルスクリプトでは、コマンドに引数を渡す際に、引数が空文字列になることがあります。これは、変数が未定義であるか、空文字列に展開される場合に発生します。
例えば、mycommand $myvar
のように変数をクォートせずに渡した場合、$myvar
が空文字列であれば、mycommand
には引数が渡されないことになります。しかし、mycommand "$myvar"
のように変数をダブルクォートで囲んだ場合、$myvar
が空文字列であれば、mycommand
には明示的に空の引数(""
)が渡されます。
このコミットの変更前は、$gofiles
変数が空の場合に、$G $D/$F.go "$gofiles"
のようにダブルクォートで囲まれていたため、6g
コマンドに空の引数が渡されていた可能性があります。多くのコマンドは空の引数を問題なく処理できますが、一部のコマンドや特定のコンテキストでは、空の引数が予期せぬ動作やエラーを引き起こすことがあります。
Go言語のテストライブラリ (testlib
)
Go言語は、testing
パッケージを通じて強力な組み込みテスト機能を提供しています。testlib
は、Goの標準ライブラリの一部ではなく、Goプロジェクトのテストスイート内で使用されるカスタムシェルスクリプトまたはユーティリティライブラリである可能性が高いです。
Goのテストは通常、go test
コマンドによって実行されますが、より複雑なテストシナリオや特定の環境設定が必要な場合、シェルスクリプトがテストのコンパイル、実行、結果の検証をオーケストレーションするために使用されることがあります。test/testlib
は、まさにそのような目的で、テスト対象のGoプログラムを 6g
コンパイラでコンパイルし、実行するためのラッパーとして機能していたと考えられます。
技術的詳細
このコミットの技術的な核心は、シェルスクリプトにおける引数展開の挙動と、それが 6g
コンパイラのコマンドライン引数解析に与える影響にあります。
変更前のコードは以下の通りでした。
$G $D/$F.go "$gofiles" && $L $F.$A && ./$A.out "$@"
ここで $gofiles
は、おそらくGoのソースファイル名のリストを含む変数です。もし $gofiles
が空文字列であった場合、"$gofiles"
は ""
と展開され、6g
コマンド($G
)には ""
という空の引数が明示的に渡されることになります。
例えば、$G
が 6g
で $D/$F.go
が main.go
、そして $gofiles
が空の場合、コマンドは論理的に 6g main.go ""
のように解釈されます。6g
コンパイラがこの空の引数をどのように処理するかは、その内部実装に依存します。コンパイラによっては、空の引数を無視したり、エラーとして扱ったり、あるいは特定の意味を持つものとして解釈したりする可能性があります。このケースでは、空の引数が run
シェルスクリプトの動作を妨げていたことから、6g
がこの空の引数を適切に処理できなかった、または予期せぬ方法で処理したことが示唆されます。
変更後のコードは以下の通りです。
$G $D/$F.go $gofiles && $L $F.$A && ./$A.out "$@"
変更点は、"$gofiles"
からダブルクォートが削除され、$gofiles
となったことです。
シェルスクリプトにおいて、変数をダブルクォートで囲まない場合、その変数が空文字列であれば、その部分はコマンドラインから完全に消滅します。つまり、もし $gofiles
が空文字列であれば、$G $D/$F.go $gofiles
は 6g main.go
のように展開され、空の引数は 6g
に渡されなくなります。これにより、6g
コンパイラが期待する引数の形式が満たされ、テストスクリプトが正しく動作するようになったと考えられます。
この修正は、シェルスクリプトの引数展開の微妙な違いを理解し、それがコマンドの挙動に与える影響を考慮した、典型的なシェルスクリプトのデバッグと修正の例と言えます。
コアとなるコードの変更箇所
--- a/test/testlib
+++ b/test/testlib
@@ -28,7 +28,7 @@ run() {
esac
done
- $G $D/$F.go "$gofiles" && $L $F.$A && ./$A.out "$@"
+ $G $D/$F.go $gofiles && $L $F.$A && ./$A.out "$@"
}
cmpout() {
コアとなるコードの解説
変更は test/testlib
ファイルの run()
関数内にあります。
元のコード:
$G $D/$F.go "$gofiles" && $L $F.$A && ./$A.out "$@"
修正後のコード:
$G $D/$F.go $gofiles && $L $F.$A && ./$A.out "$@"
この変更の核心は、$gofiles
変数の展開方法です。
- 変更前 (
"$gofiles"
):$gofiles
が空文字列の場合、6g
コマンド($G
)には""
という空の引数が明示的に渡されます。これは、シェルがダブルクォート内の空文字列を単一の空の引数として解釈するためです。 - 変更後 (
$gofiles
):$gofiles
が空文字列の場合、シェルは$gofiles
の部分を何も展開しません。結果として、6g
コマンドには空の引数が渡されなくなります。
この修正により、6g
コンパイラが予期しない空の引数を受け取ることがなくなり、run
シェルスクリプトが正しく機能するようになりました。これは、シェルスクリプトにおける変数のクォーティングの重要性を示す典型的な例です。特に、コマンドライン引数として渡される可能性のある変数については、その内容が空である可能性を考慮し、適切なクォーティング戦略を選択する必要があります。
関連リンク
- Go CL 5771043: https://golang.org/cl/5771043
参考にした情報源リンク
6g
コンパイラに関する情報:- https://progopedia.com/compiler/6g/
- https://go.dev/doc/go1.5#compiler
- https://cheney.net/go-compiler-history
- https://www.cs.cmu.edu/~410/doc/go-toolchain.html
- https://stackoverflow.com/questions/10000000/what-is-the-difference-between-6g-8g-and-5g-in-go
- https://www.swig.org/Doc2.0/Go.html
- https://google.com/search?q=golang+6g+compiler
- シェルスクリプトの空の引数渡しに関する情報:
- Go言語のテストに関する情報:
- https://hashnode.dev/go-testing-best-practices
- https://withcodeexample.com/go-testing-best-practices/
- https://www.geeksforgeeks.org/go-testing-package/
- https://go.dev/blog/fuzz-go
- https://grid.gg/blog/go-testing-best-practices/
- https://www.jetbrains.com/go/guide/tutorials/testing/
- https://go.dev/doc/tutorial/add-a-test
- https://gobyexample.com/testing
- https://www.speedscale.com/blog/go-testing-best-practices/
- https://reliasoftware.com/blog/go-testing-best-practices
- https://dev.to/apcelent/go-testing-best-practices-301
- https://apitoolkit.io/blog/go-testing-best-practices/
- https://jdkaplan.dev/posts/go-testing-best-practices/
- https://awesome-go.com/#testing
- https://www.reddit.com/r/golang/comments/10000000/what_are_the_best_go_testing_libraries/
- https://github.com/stretchr/testify