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

[インデックス 10058] gotest: use $GCFLAGS like make does

コミット

コミットハッシュ: 35b2bfc8daa9ebeabfae8106e39b223c137f523a
作成者: Russ Cox rsc@golang.org
コミット日時: 2011年10月19日 13:10:23 -0400
コミットメッセージ: gotest: use $GCFLAGS like make does

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

https://github.com/golang/go/commit/35b2bfc8daa9ebeabfae8106e39b223c137f523a

元コミット内容

gotest: use $GCFLAGS like make does

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/5297044

変更ファイル: src/cmd/gotest/gotest.go
変更内容: 8行追加、6行挿入、2行削除

変更の背景

このコミットは、2011年10月に行われたGoの初期開発段階における重要な変更です。当時のGoは現在のgo testコマンドが導入される前で、gotestという独立したコマンドが存在していました。この変更の背景には以下の要因があります:

  1. 統一性の確保: Makefileベースのビルドシステムとgotestコマンドの間でコンパイラフラグの扱いを統一する必要がありました
  2. 開発者体験の改善: 開発者がコンパイラフラグを環境変数として設定できるようにすることで、テスト実行時の柔軟性を向上させました
  3. ビルドシステムの進化: Go 1.0リリース前の段階で、ビルドツールチェーンの機能を統合・標準化する取り組みの一環でした

前提知識の解説

2011年当時のGoのビルドシステム

2011年のGoは現在とは大きく異なるビルドシステムを使用していました:

  • Makefileベースのビルド: プロジェクトのビルドはMakefileを使用して行われていました
  • 独立したコマンド群: gotest6g6lなど、個別のコマンドが存在していました
  • 環境変数による設定: GCFLAGSLDFLAGSなどの環境変数でコンパイラオプションを制御していました

gotestコマンドについて

gotestは現在のgo testの前身となるコマンドで、以下の特徴がありました:

  • テストファイルを自動検出し、_testmain.goというファイルを生成
  • Makefileシステムと連携してテストを実行
  • コンパイラフラグの指定が限定的だった

GCFLAGS環境変数

GCFLAGSは Go コンパイラ(gc)に渡すフラグを指定する環境変数で、以下のような用途がありました:

  • デバッグ情報の生成制御(-N -l
  • 最適化レベルの調整
  • アセンブリ出力の制御(-S
  • インライン化の制御(-m

技術的詳細

変更前のコード構造

変更前のgotestコマンドは、コンパイラフラグをハードコーディングしていました:

XGC = []string{gc, "-I", "_test", "-o", "_xtest_." + O}
GC = []string{gc, "-I", "_test", "_testmain.go"}

このアプローチには以下の問題がありました:

  1. 柔軟性の欠如: 開発者が追加のコンパイラフラグを指定できませんでした
  2. Makefileとの非互換性: Makefileで設定したGCFLAGSgotestに反映されませんでした
  3. デバッグの困難さ: テスト実行時にデバッグフラグを動的に追加できませんでした

変更後の実装詳細

新しい実装では、GCFLAGS環境変数を読み取り、それをコンパイラフラグに追加する仕組みが導入されました:

var gcflags []string
if gf := strings.TrimSpace(os.Getenv("GCFLAGS")); gf != "" {
    gcflags = strings.Fields(gf)
}
XGC = append([]string{gc, "-I", "_test", "-o", "_xtest_." + O}, gcflags...)
GC = append(append([]string{gc, "-I", "_test"}, gcflags...), "_testmain.go")

処理フローの詳細

  1. 環境変数の読み取り: os.Getenv("GCFLAGS")で環境変数を取得
  2. 文字列の正規化: strings.TrimSpace()で前後の空白を除去
  3. フラグの分割: strings.Fields()でスペース区切りの文字列をスライスに分割
  4. フラグの統合: append()を使って既存のフラグと統合

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

変更されたファイル: src/cmd/gotest/gotest.go

行153-158の変更:

- XGC = []string{gc, "-I", "_test", "-o", "_xtest_." + O}
- GC = []string{gc, "-I", "_test", "_testmain.go"}
+ var gcflags []string
+ if gf := strings.TrimSpace(os.Getenv("GCFLAGS")); gf != "" {
+     gcflags = strings.Fields(gf)
+ }
+ XGC = append([]string{gc, "-I", "_test", "-o", "_xtest_." + O}, gcflags...)
+ GC = append(append([]string{gc, "-I", "_test"}, gcflags...), "_testmain.go")

変更箇所の詳細解説

  1. XGCフラグの構築:

    • XGCは外部テストパッケージのコンパイル用フラグ
    • 基本フラグ [gc, "-I", "_test", "-o", "_xtest_." + O]gcflags を追加
  2. GCフラグの構築:

    • GCはメインテストファイルのコンパイル用フラグ
    • 二重のappendにより、基本フラグとgcflags、そして_testmain.goを統合
  3. エラーハンドリング:

    • 空のGCFLAGS環境変数の場合は何も追加しない
    • strings.TrimSpace()により、不正な空白文字を除去

コアとなるコードの解説

環境変数処理の実装

if gf := strings.TrimSpace(os.Getenv("GCFLAGS")); gf != "" {
    gcflags = strings.Fields(gf)
}

この部分は以下の処理を行います:

  1. 短縮変数宣言: gf := で一時変数を宣言
  2. 環境変数取得: os.Getenv("GCFLAGS")でGCFLAGS環境変数を取得
  3. 空白除去: strings.TrimSpace()で前後の空白を除去
  4. 空文字チェック: 空文字でない場合のみ処理を続行
  5. フィールド分割: strings.Fields()でスペース区切りの文字列をスライスに分割

フラグ統合の実装

XGC = append([]string{gc, "-I", "_test", "-o", "_xtest_." + O}, gcflags...)

この行では:

  1. 基本フラグ: []string{gc, "-I", "_test", "-o", "_xtest_." + O}
  2. 可変引数展開: gcflags...gcflagsスライスを展開
  3. スライス結合: append()で両方のスライスを結合

二重append処理

GC = append(append([]string{gc, "-I", "_test"}, gcflags...), "_testmain.go")

この複雑な構造は以下の理由によります:

  1. 内側のappend: 基本フラグにgcflagsを追加
  2. 外側のappend: 結果に_testmain.goを最後に追加
  3. 順序の保証: コンパイラフラグが_testmain.goより前に来ることを保証

関連リンク

参考にした情報源リンク