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

[インデックス 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)には "" という空の引数が明示的に渡されることになります。

例えば、$G6g$D/$F.gomain.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 $gofiles6g 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 シェルスクリプトが正しく機能するようになりました。これは、シェルスクリプトにおける変数のクォーティングの重要性を示す典型的な例です。特に、コマンドライン引数として渡される可能性のある変数については、その内容が空である可能性を考慮し、適切なクォーティング戦略を選択する必要があります。

関連リンク

参考にした情報源リンク