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

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

このコミットは、Go言語のyaccツールに関連するunits.yファイルのコメント更新と、$GOROOT環境変数が設定されていない場合のより適切なエラーメッセージの提供を目的としています。また、Makefileにクリーンアップターゲットを追加しています。

コミット

commit bdca78e1a76cd97a20d45d5f6990b52533154aee
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Sun Feb 26 01:36:26 2012 +0800

    cmd/yacc/units.y: update comment, give better error messages when $GOROOT not set
    
    R=r, golang-dev
    CC=golang-dev
    https://golang.org/cl/5698062

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

https://github.com/golang/go/commit/bdca78e1a76cd97a20d45d5f6990b52533154aee

元コミット内容

cmd/yacc/units.y: update comment, give better error messages when $GOROOT not set

このコミットは、cmd/yacc/units.yファイル内のコメントを更新し、$GOROOT環境変数が設定されていない場合に、より分かりやすいエラーメッセージを表示するように改善します。

変更の背景

この変更の背景には、主に以下の2点があります。

  1. Goツールチェインの進化への対応: 2012年当時のGo言語のビルドシステムは、現在とは異なるコマンド(例: 6g, 6l)を使用していました。このコミットは、units.yファイルのコメントにある使用例を、より新しいgo buildコマンドに更新することで、ドキュメントの正確性を保ち、ユーザーが最新のGoツールチェインでyaccプログラムをビルドする際の混乱を避けることを目的としています。
  2. ユーザーエクスペリエンスの向上: units.yで生成されるプログラムは、$GOROOT環境変数に依存してデータファイル(units.txt)のパスを決定していました。しかし、$GOROOTが設定されていない場合、プログラムは無効なパスを構築し、ユーザーに不親切なエラー(または単にファイルが見つからないというエラー)を返していました。このコミットは、$GOROOTが設定されていない場合に、より明確なエラーメッセージを標準エラー出力に表示し、プログラムを終了させることで、デバッグの労力を減らし、ユーザーエクスペリエンスを向上させます。

前提知識の解説

  • Yacc (Yet Another Compiler Compiler): Yaccは、プログラミング言語の構文解析器(パーサー)を生成するためのツールです。文法規則を記述したファイル(通常は.y拡張子)を入力として受け取り、その文法を解析するためのC言語(またはGo言語など)のソースコードを生成します。Go言語のcmd/yaccは、Go言語で記述されたパーサーを生成するためのYaccの実装です。
  • units.y: このファイルは、Go言語のyaccツールの使用例として提供されている文法定義ファイルです。単位変換(例: インチからセンチメートル)を行うプログラムのパーサーを生成するために使用されます。
  • $GOROOT: Go言語のインストールディレクトリを示す環境変数です。Goの標準ライブラリやツールがこのディレクトリに配置されています。Goプログラムが標準ライブラリのファイルや、Goのインストールパスに依存するリソース(このケースではunits.txtのようなデータファイル)を探す際に利用されます。
  • go build: Go言語のソースコードをコンパイルして実行可能ファイルを生成するためのコマンドです。以前のGoのバージョンでは、6g(コンパイラ)や6l(リンカ)といったアーキテクチャ固有のコマンドが使われていましたが、go buildはこれらを抽象化し、よりシンプルにビルドを行えるようにしました。
  • os.Getenv(): Go言語の標準ライブラリosパッケージに含まれる関数で、指定された環境変数の値を取得します。
  • fmt.Fprintf(os.Stderr, ...): Go言語の標準ライブラリfmtパッケージに含まれる関数で、指定されたio.Writer(この場合は標準エラー出力os.Stderr)にフォーマットされた文字列を出力します。
  • os.Exit(1): Go言語の標準ライブラリosパッケージに含まれる関数で、プログラムを終了させます。引数に1を指定すると、通常はエラー終了を示します。

技術的詳細

このコミットは、主にsrc/cmd/yacc/units.y内のmain関数におけるデータファイルパスの決定ロジックと、src/cmd/yacc/Makefileのビルドスクリプトに焦点を当てています。

src/cmd/yacc/units.yの変更点

  1. コメントの更新:

    • 古いGoツールチェインのコマンド(6g y.go6l y.6./6.out $GOROOT/src/cmd/yacc/units)が、新しいgo buildコマンド(go build -o units y.go./units $GOROOT/src/cmd/yacc/units.txt)に置き換えられました。これにより、ドキュメントが現在のGo開発環境に即したものになりました。また、データファイル名がunitsからunits.txtに修正されています。
  2. $GOROOTのチェックとエラーハンドリングの改善:

    • 変更前:
      file = os.Getenv("GOROOT") + "/src/cmd/yacc/units.txt"
      
      このコードでは、$GOROOTが設定されていなくても、file変数には/src/cmd/yacc/units.txtというパスが設定されていました。これは絶対パスではないため、ファイルオープン時にエラーが発生しても、その原因が$GOROOTの未設定にあることが分かりにくいという問題がありました。
    • 変更後:
      if dir := os.Getenv("GOROOT"); dir != "" {
          file = dir + "/src/cmd/yacc/units.txt"
      }
      if flag.NArg() > 0 {
          file = flag.Arg(0)
      } else if file == "" {
          fmt.Fprintf(os.Stderr, "can not find data file units.txt; provide it as argument or set $GOROOT\\n")
          os.Exit(1)
      }
      
      この変更により、$GOROOTが設定されている場合にのみ、その値を使用してunits.txtのパスを構築するようになりました。 さらに重要なのは、else if file == ""という新しい条件分岐が追加された点です。これは、以下の両方の条件が満たされた場合に実行されます。
      • $GOROOTが設定されていない。
      • コマンドライン引数としてデータファイルのパスが提供されていない。 この場合、プログラムは標準エラー出力に「can not find data file units.txt; provide it as argument or set $GOROOT」という明確なエラーメッセージを出力し、終了コード1でプログラムを終了します。これにより、ユーザーは問題の原因と解決策をすぐに理解できるようになりました。

src/cmd/yacc/Makefileの変更点

  1. cleanターゲットの追加:
    • ビルドプロセスで生成される中間ファイルや最終的な実行可能ファイル(y.go, y.output, units)を削除するためのcleanターゲットが追加されました。これは、開発者がビルド環境をクリーンな状態に戻すための標準的な方法であり、開発ワークフローの利便性を向上させます。

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

src/cmd/yacc/units.y

--- a/src/cmd/yacc/units.y
+++ b/src/cmd/yacc/units.y
@@ -15,9 +15,8 @@
 // example of a Go yacc program
 // usage is
 //	go tool yacc -p "units_" units.y (produces y.go)
-//	6g y.go
-//	6l y.6
-//	./6.out $GOROOT/src/cmd/yacc/units
+//	go build -o units y.go
+//	./units $GOROOT/src/cmd/yacc/units.txt
 //	you have: c
 //	you want: furlongs/fortnight
 //		* 1.8026178e+12
@@ -288,9 +287,14 @@ func main() {
  
 	flag.Parse()
  
-	file = os.Getenv("GOROOT") + "/src/cmd/yacc/units.txt"
+	if dir := os.Getenv("GOROOT"); dir != "" {
+		file = dir + "/src/cmd/yacc/units.txt"
+	}
 	if flag.NArg() > 0 {
 		file = flag.Arg(0)
+	} else if file == "" {
+		fmt.Fprintf(os.Stderr, "can not find data file units.txt; provide it as argument or set $GOROOT\\n")
+		os.Exit(1)
 	}
  
 	f, err := os.Open(file)

src/cmd/yacc/Makefile

--- a/src/cmd/yacc/Makefile
+++ b/src/cmd/yacc/Makefile
@@ -5,3 +5,6 @@
 units: yacc.go units.y
 	go run yacc.go -p units_ units.y
 	go build -o units y.go
+\
+clean:
+\trm -f y.go y.output units

コアとなるコードの解説

src/cmd/yacc/units.ymain関数内の変更

この変更の核心は、main関数内でunits.txtデータファイルのパスを決定し、そのファイルを開く前のロジックにあります。

  1. $GOROOTの条件付き使用: if dir := os.Getenv("GOROOT"); dir != ""という行は、$GOROOT環境変数の値を取得し、それが空文字列でない場合にのみ、その値を変数dirに代入し、units.txtのパスを構築します。これにより、$GOROOTが設定されていない場合に、無効なパスが生成されるのを防ぎます。

  2. コマンドライン引数の優先: if flag.NArg() > 0 { file = flag.Arg(0) }という行は、プログラムがコマンドライン引数を受け取った場合、その引数をデータファイルのパスとして優先的に使用することを示しています。これは既存の動作であり、変更されていません。

  3. 改善されたエラーハンドリング: else if file == ""という新しいブロックが追加されました。このブロックは、以下のシナリオで実行されます。

    • $GOROOTが設定されていない(最初のifブロックがスキップされる)。
    • コマンドライン引数も提供されていない(2番目のifブロックがスキップされる)。 この場合、file変数は初期値(空文字列)のままです。この状態は、プログラムがunits.txtを見つけるための有効なパスを持っていないことを意味します。そこで、fmt.Fprintf(os.Stderr, ...)を使って、ユーザーに「units.txtデータファイルが見つかりません。引数として提供するか、$GOROOTを設定してください」という明確なエラーメッセージを標準エラー出力に表示します。そして、os.Exit(1)を呼び出して、プログラムがエラー状態であることを示しながら終了します。これにより、ユーザーは問題の原因と解決策を即座に理解できます。

src/cmd/yacc/Makefilecleanターゲット

clean:という新しいターゲットが追加され、その下にrm -f y.go y.output unitsというコマンドが記述されています。

  • clean: これは、make cleanコマンドを実行したときに実行されるターゲットの名前です。
  • rm -f: ファイルを削除するコマンドです。-fオプションは、存在しないファイルを無視し、確認プロンプトを表示しないようにします。
  • y.go: yaccツールによって生成されるGoソースファイルです。
  • y.output: yaccツールがデバッグ情報として生成する可能性のあるファイルです。
  • units: go buildコマンドによって生成される最終的な実行可能ファイルです。

このターゲットの追加により、開発者はビルドによって生成されたファイルを簡単に削除し、クリーンな状態から再ビルドできるようになります。

関連リンク

参考にした情報源リンク