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

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

このコミットは、Go言語の初期のテストスクリプトである src/cmd/gotest/gotest に対する変更です。主な目的は、テスト実行時に使用するGoコンパイラとリンカの指定を、環境変数 $GC$GL を介して柔軟に行えるようにすることです。これにより、標準のGoコンパイラ(gcツールチェーン)だけでなく、gccgoのような代替コンパイラとの互換性を向上させ、テスト環境のポータビリティを高めています。

コミット

Go言語のテスト実行スクリプト gotest において、コンパイラ (6g) およびリンカ (6l) の直接指定を、環境変数 $GC および $GL を使用するように変更しました。これにより、gccgo との互換性を確保し、テスト実行環境の柔軟性とポータビリティを向上させています。また、テストファイルの検索方法も改善され、より堅牢なテスト実行が可能になっています。

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

https://github.com/golang/go/commit/8c5bc7e93adae7546b4f1520d1b20f18ebe95d88

元コミット内容

use $GC, $GL in gotest, to match gccgo's gotest.

use $GC in all_test.go for portability.

R=r
DELTA=19  (12 added, 0 deleted, 7 changed)
OCL=23305
CL=23325

変更の背景

Go言語の初期段階では、複数のコンパイラ実装が存在していました。主なものとして、Goチームが開発していた公式のコンパイラ(後にgcツールチェーンとして知られるようになるもの)と、GCCをバックエンドとするgccgoがありました。

gotestスクリプトは、Goのテストを実行するための重要なツールでしたが、特定のコンパイラ(この場合は6g6l)にハードコードされていました。これは、異なるコンパイラ環境(特にgccgo)でテストを実行しようとすると問題を引き起こしました。gccgoも独自のテスト実行メカニズムを持っていましたが、gotestスクリプトが6g/6lに依存しているため、互換性がありませんでした。

このコミットの背景には、Goのテストインフラをより汎用的にし、異なるコンパイラ実装間でのポータビリティを確保するという目的がありました。環境変数 $GC$GL を導入することで、ユーザーやビルドシステムが使用するコンパイラとリンカを柔軟に指定できるようになり、gccgoのような代替コンパイラでも同じgotestスクリプトを利用してテストを実行できるようになりました。

また、テストファイルの検出ロジックも改善されています。以前は *test.go というシェルグロブパターンに依存していましたが、これは環境によっては期待通りに動作しない可能性がありました。ls *_test.go を使用することで、より堅牢なファイル検出を実現し、テスト実行の信頼性を高めています。

前提知識の解説

  • gotest: Go言語のテストを実行するためのスクリプトまたはコマンドです。Goの標準ライブラリやユーザーが作成したパッケージのテストを自動化するために使用されます。Go 1.0以降では go test コマンドがこの役割を担っていますが、このコミットが作成された時期(2009年)はGoの初期段階であり、gotestというスクリプトが直接使われていました。
  • $GC$GL: これらはGoのビルドシステムやテストスクリプトで使用される環境変数です。
    • $GC: Goコンパイラへのパスまたはコマンドを指定します。例えば、6ggo tool compileなどがこれに該当します。
    • $GL: Goリンカへのパスまたはコマンドを指定します。例えば、6lgo tool linkなどがこれに該当します。 これらの環境変数を使用することで、特定のコンパイラやリンカに依存せず、柔軟にツールチェーンを切り替えることが可能になります。
  • 6g6l: Go言語の初期のコンパイラとリンカの名称です。
    • 6g: 64ビットアーキテクチャ(amd64)向けのGoコンパイラです。Goソースコードをコンパイルしてオブジェクトファイルを生成します。
    • 6l: 64ビットアーキテクチャ(amd64)向けのGoリンカです。オブジェクトファイルをリンクして実行可能ファイルを生成します。 これらはGo言語がまだC言語で書かれていた時代のツールチェーンの一部であり、Go 1.5以降ではGo自身で書かれた新しいコンパイラとリンカに置き換えられ、go buildgo runといった統一されたコマンドの裏側で動作するようになりました。
  • gccgo: Go言語の代替コンパイラの一つで、GCC(GNU Compiler Collection)をバックエンドとして利用しています。gccgoは、GoのコードをGCCの最適化パイプラインを通してコンパイルできるため、特定の環境や最適化要件において選択肢となることがあります。標準のGoコンパイラ(gc)とは異なる実装であるため、互換性の問題が発生することがありました。
  • _test.go: Go言語におけるテストファイルの命名規則です。Goのテストフレームワークは、ファイル名が _test.go で終わるファイルをテストコードとして認識します。例えば、my_package.go のテストは my_package_test.go というファイルに記述されます。go test コマンドは、これらのファイルを自動的に検出し、コンパイルしてテストを実行します。

技術的詳細

このコミットの技術的な核心は、gotestスクリプトがコンパイラとリンカを呼び出す方法を、ハードコードされたコマンド名から環境変数への参照に切り替えた点にあります。

  1. 環境変数の導入とデフォルト値の設定:

    --- a/src/cmd/gotest/gotest
    +++ b/src/cmd/gotest/gotest
    @@ -8,6 +8,11 @@
     # tests.
     # If files are named on the command line, use them instead of test*.go.
    
    +O=6
    +GC=${GC:-${O}g}\
    +GL=${GL:-${O}l}\
    +export GC GL
    +
     gofiles=""
     loop=true
     while $loop; do
    

    この部分では、Oという変数を6に設定しています。これは、当時のGoツールチェーンがターゲットアーキテクチャ(例: 64ビットは6、32ビットは8)に基づいてコンパイラやリンカのファイル名を決定していた名残です。 そして、GCGLという環境変数を定義しています。${GC:-${O}g} の構文は、シェルスクリプトにおけるパラメータ展開の一種で、「もしGCが設定されていなければ、${O}g(つまり6g)をデフォルト値として使用する」という意味です。GLについても同様に${O}l(つまり6l)がデフォルト値となります。 export GC GL により、これらの変数がサブプロセスにも引き継がれるようにしています。これにより、gotestスクリプト内で実行されるコンパイルやリンクのコマンドが、これらの環境変数の値を使用するようになります。

  2. テストファイルの検出ロジックの改善:

    --- a/src/cmd/gotest/gotest
    +++ b/src/cmd/gotest/gotest
    @@ -27,20 +32,27 @@ done
    
     case "x$gofiles" in
     x)
    -	gofiles=$(echo *test.go)
    +	gofiles=$(ls *_test.go 2>/dev/null)
    +esac
    +
    +case "x$gofiles" in
    +x)
    +	echo 'no test files found' 1>&2
    +	exit 1
     esac
    

    以前は gofiles=$(echo *test.go) を使用していましたが、これはシェルによっては期待通りに動作しない場合がありました。新しい gofiles=$(ls *_test.go 2>/dev/null) は、ls コマンドを使用して _test.go で終わるファイルを明示的にリストアップし、エラー出力を抑制しています。これにより、テストファイルの検出がより堅牢になりました。 さらに、gofiles が空の場合(テストファイルが見つからない場合)にエラーメッセージを出力して終了するロジックが追加され、スクリプトの堅牢性が向上しています。

  3. コンパイラ/リンカの呼び出しの変更:

    --- a/src/cmd/gotest/gotest
    +++ b/src/cmd/gotest/gotest
    @@ -46,14 +58,14 @@
     # to build any test-only dependencies.
     sed -n 's/^\/\/ gotest: //p' $gofiles | sh
    
     for i in $gofiles
     do
    -	6g $i
    +	$GC $i
     done
    
     set -e
    @@ -84,6 +96,6 @@ trap "rm -f _testmain.go _testmain.6" 0 1 2 3 14 15
     	echo '}'\
     }>_testmain.go
    
    -6g _testmain.go
    -6l _testmain.6
    -./6.out "$@"\
    +$GC _testmain.go
    +$GL _testmain.$O\
    +./$O.out "$@"\
    

    この部分が最も重要な変更点です。

    • sed -n 's/^\/\/ gotest: //p' $gofiles | sh の行は、Goソースファイル内の // gotest: で始まるコメント行を抽出し、それをシェルコマンドとして実行するものです。これにより、テスト固有のビルド依存関係を処理できます。この行自体は変更されていませんが、このコマンドが実行する内容(例えば 6g foo.go のようなもの)も、このコミットの変更によって $GC foo.go のように環境変数を使用する形に移行することが意図されています。
    • for i in $gofiles; do 6g $i; donefor i in $gofiles; do $GC $i; done に変更されました。これにより、各テストファイルをコンパイルする際に、ハードコードされた6gではなく、$GC環境変数の値が使用されます。
    • 6g _testmain.go$GC _testmain.go に、6l _testmain.6$GL _testmain.$O に変更されました。_testmain.go はテストのエントリポイントとなる一時的なGoファイルで、これをコンパイル・リンクする際にも環境変数が使用されるようになりました。_testmain.$O は、_testmain.6 のように、アーキテクチャを示すO変数の値がファイル名に組み込まれることを示しています。
    • 最後に、生成された実行可能ファイルの実行も ./6.out から ./$O.out に変更され、アーキテクチャに依存しない呼び出しになっています。

これらの変更により、gotestスクリプトは、GCGL環境変数を設定することで、標準のgcツールチェーン(6g/6l)だけでなく、gccgoのような代替コンパイラでもシームレスに動作するようになりました。

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

diff --git a/src/cmd/gotest/gotest b/src/cmd/gotest/gotest
index d95201ad87..f292034cbd 100755
--- a/src/cmd/gotest/gotest
+++ b/src/cmd/gotest/gotest
@@ -8,6 +8,11 @@
 # tests.
 # If files are named on the command line, use them instead of test*.go.\
 \
+O=6
+GC=${GC:-${O}g}\
+GL=${GL:-${O}l}\
+export GC GL
+\
 gofiles=""
 loop=true
 while $loop; do
@@ -27,20 +32,27 @@ done
 \
 case "x$gofiles" in
 x)
-\tgofiles=$(echo *test.go)
+\tgofiles=$(ls *_test.go 2>/dev/null)
+esac
+\
+case "x$gofiles" in
+x)
+\techo 'no test files found' 1>&2
+\texit 1
 esac
 \
 ofiles=$(echo $gofiles | sed 's/\.go/.6/g')
 files=$(echo $gofiles | sed 's/\.go//g')
 \
+\
 # Run any commands given in sources, like
-#   // gotest: 6g foo.go
+#   // gotest: $GC foo.go
 # to build any test-only dependencies. \
 sed -n 's/^\/\/ gotest: //p' $gofiles | sh
 \
 for i in $gofiles
 do
-\t6g $i
+\t$GC $i
 done
 \
 set -e
@@ -84,6 +96,6 @@ trap "rm -f _testmain.go _testmain.6" 0 1 2 3 14 15
 \techo '}'\
 }>_testmain.go
 \
-6g _testmain.go
-6l _testmain.6
-./6.out "$@"\
+$GC _testmain.go
+$GL _testmain.$O\
+./$O.out "$@"\

コアとなるコードの解説

  • 追加された行 (+ で始まる行):
    • O=6: アーキテクチャを示す変数O6(64ビット)に設定しています。
    • GC=${GC:-${O}g}: 環境変数GCが設定されていなければ、デフォルトで6g(64ビットGoコンパイラ)を使用するように設定します。
    • GL=${GL:-${O}l}: 環境変数GLが設定されていなければ、デフォルトで6l(64ビットGoリンカ)を使用するように設定します。
    • export GC GL: 定義したGCGLを環境変数としてエクスポートし、スクリプト内で実行されるサブプロセス(コンパイラやリンカの呼び出し)から参照できるようにします。
    • gofiles=$(ls *_test.go 2>/dev/null): テストファイルを検出する際に、echo *test.go の代わりに ls *_test.go を使用するように変更し、より堅牢なファイル検出を実現しています。2>/dev/null はエラー出力を抑制します。
    • case "x$gofiles" in x) echo 'no test files found' 1>&2; exit 1 esac: テストファイルが見つからなかった場合に、エラーメッセージを出力してスクリプトを終了するロジックを追加しています。
  • 変更された行 (- で始まり、その後に + で始まる行が続く):
    • - gofiles=$(echo *test.go) から + gofiles=$(ls *_test.go 2>/dev/null): 前述の通り、テストファイルの検出方法を変更しています。
    • - 6g $i から + $GC $i: 各テストファイルをコンパイルする際に、ハードコードされた6gコマンドの代わりに、環境変数$GCの値を使用するように変更しています。
    • - 6g _testmain.go から + $GC _testmain.go: テストのエントリポイントとなる_testmain.goファイルをコンパイルする際に、$GCを使用するように変更しています。
    • - 6l _testmain.6 から + $GL _testmain.$O: コンパイルされた_testmain.6ファイルをリンクする際に、ハードコードされた6lコマンドの代わりに、環境変数$GLの値を使用するように変更しています。また、出力ファイル名も_testmain.$Oとすることで、O変数の値(この場合は6)がファイル名に反映されるようにしています。
    • - ./6.out "$@" から + ./$O.out "$@": 最終的に生成されたテスト実行可能ファイルを呼び出す際に、ハードコードされた./6.outではなく、./$O.outを使用するように変更し、アーキテクチャの柔軟性を高めています。

これらの変更により、gotestスクリプトは、特定のコンパイラやリンカに依存せず、環境変数を通じて柔軟にツールチェーンを切り替えられるようになりました。

関連リンク

参考にした情報源リンク

  • Go 6g 6l compilers early history - Web search results
  • Go test file naming conventions _test.go - Web search results
  • golang gotest $GC $GL gccgo - Web search results (特に、$GCgccgoの違い、_test.goの命名規則に関する情報)