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

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

このコミットは、Go言語のビルドシステム (cmd/dist) とGoコマンド (cmd/go) において、コンパイラの警告設定を強化し、特にClangコンパイラからのエラー出力の可読性を向上させることを目的としています。具体的には、GCCおよびClang使用時の警告フラグを追加し、Clangのエラーメッセージに含まれるASCIIアート(キャレット診断)やエスケープコードを無効化する設定が導入されています。これにより、コンパイル時の潜在的な問題をより早期に発見しやすくするとともに、Clangのエラーメッセージがターミナル上でより見やすくなるように改善されています。

コミット

commit c485b5891273c62af8e2342c72edf717966d97b7
Author: Russ Cox <rsc@golang.org>
Date:   Fri Jul 19 19:36:15 2013 -0400

    cmd/dist, cmd/go: enable more warnings, make clang errors legible
    
    This does not change the default compiler on OS X to clang.
    It appears that for now we can keep using gcc as long as we
    enable a few more warning settings that are on-by-default
    elsewhere.
    
    R=golang-dev, bradfitz, dave
    CC=golang-dev
    https://golang.org/cl/11610044

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

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

元コミット内容

cmd/dist, cmd/go: より多くの警告を有効にし、Clangのエラーを読みやすくする。

これはOS X上のデフォルトコンパイラをClangに変更するものではない。 今のところ、他の場所でデフォルトで有効になっているいくつかの警告設定を有効にする限り、GCCを使い続けることができるようだ。

変更の背景

このコミットの背景には、Go言語のビルドプロセスにおけるコンパイラの利用状況と、それに関連する警告およびエラーメッセージの取り扱いに関する課題がありました。

  1. コンパイラの警告の強化: Goプロジェクトでは、コードの品質と堅牢性を高めるために、コンパイラが提供する警告を最大限に活用することが望ましいとされています。しかし、当時の設定では、他の環境でデフォルトで有効になっている一部の重要な警告がGoのビルドプロセスでは有効になっていませんでした。特に、GCCを使用している環境において、より多くの潜在的な問題をコンパイル時に検出できるように、警告レベルを引き上げる必要がありました。
  2. Clangエラーメッセージの可読性改善: OS X(現在のmacOS)では、Clangが主要なC/C++/Objective-Cコンパイラとして広く利用されています。Clangは非常に詳細な診断メッセージを出力することで知られていますが、その中にはASCIIアート(キャレット診断)やターミナルのエスケープコードが含まれることがあり、これらが一部の環境やツールで正しく表示されず、エラーメッセージの可読性を損なう問題がありました。特に、CI/CD環境や特定のターミナルエミュレータでは、これらの特殊な表示が文字化けしたり、余計な情報として認識されたりすることがありました。
  3. OS Xでのデフォルトコンパイラ: コミットメッセージにも明記されているように、この変更はOS XのデフォルトコンパイラをClangに変更するものではありませんでした。当時のGoのビルドシステムはGCCを主要なコンパイラとして想定しており、Clangへの完全な移行はまだ行われていませんでした。しかし、Clangが利用される可能性を考慮し、その出力の扱いを改善する必要がありました。

これらの課題に対処するため、このコミットでは、Goのビルドシステムが使用するコンパイラフラグを調整し、より多くの警告を有効にするとともに、Clangのエラーメッセージの表示を改善する変更が導入されました。

前提知識の解説

このコミットを理解するためには、以下の技術的な概念について知っておく必要があります。

  1. cmd/dist: Go言語のソースコードからGoツールチェイン自体をビルドするためのツールです。Goのブートストラッププロセスにおいて中心的な役割を担います。C言語で書かれており、Goのコンパイラやリンカなどのツールを構築する際に、Cコンパイラ(GCCやClangなど)を呼び出します。このツールがCコンパイラに渡すフラグを制御することで、Goツールチェインのビルド時の警告設定やエラー表示に影響を与えます。

  2. cmd/go: Go言語のユーザーが日常的に使用するコマンドラインツールです。Goのソースコードのコンパイル、テスト、パッケージ管理、実行など、Go開発のほとんどの側面を管理します。go buildなどのコマンドが内部でCgo(GoとC/C++の相互運用機能)を使用する場合、Cコンパイラを呼び出すことがあります。この際にも、cmd/goがCコンパイラに渡すフラグが重要になります。

  3. GCC (GNU Compiler Collection): GNUプロジェクトによって開発された、C、C++、Objective-C、Fortran、Ada、Goなどのプログラミング言語をサポートするコンパイラ群です。Go言語の初期のビルドシステムでは、CコードのコンパイルにGCCが広く利用されていました。

  4. Clang: LLVMプロジェクトの一部として開発されているC、C++、Objective-C、Objective-C++コンパイラのフロントエンドです。GCCと比較して、より高速なコンパイル、優れた診断メッセージ、モジュール性などの特徴を持ちます。OS X/macOSでは、Xcodeのデフォルトコンパイラとして採用されています。

  5. コンパイラの警告フラグ: C/C++コンパイラには、コードの潜在的な問題(バグではないが、疑わしい挙動や非推奨の構文など)を開発者に警告するための様々なオプションがあります。

    • -Wextra: 多くの有用な警告を有効にするメタフラグです。例えば、未使用の変数、初期化されていない変数、一部の型変換の問題などを警告します。
    • -Wunused: 未使用の変数、関数、引数などに関する警告を有効にします。
    • -Wuninitialized: 初期化されていない変数を使用した場合に警告します。これは未定義動作につながる可能性があるため、非常に重要な警告です。
    • -Wno-sign-compare: 符号付き整数と符号なし整数の比較に関する警告を無効にします。これは意図的な場合もあるため、無効にされることがあります。
    • -Wno-missing-braces: 初期化子リストの波括弧が不足している場合の警告を無効にします。
    • -Wno-parentheses: 括弧の不足に関する警告を無効にします。
    • -Wno-unknown-pragmas: 未知のプラグマに関する警告を無効にします。
    • -Wno-switch: switch文に関する警告を無効にします。
    • -Wno-comment: コメントに関する警告を無効にします。
    • -Wno-missing-field-initializers: 構造体や配列の初期化子で全てのフィールドが明示的に初期化されていない場合の警告を無効にします。
    • -Werror: 全ての警告をエラーとして扱い、警告が発生した場合はコンパイルを停止させます。これはCI/CD環境などでコード品質を厳しく保つためによく使用されます。
  6. Clangの診断メッセージとASCIIアート (Caret Diagnostics): Clangは、エラーや警告が発生したコードの正確な位置を、キャレット(^)やチルダ(~)などのASCII文字を使って視覚的に示す「キャレット診断」と呼ばれる機能を持ちます。これにより、問題の箇所が一目で分かりやすくなります。しかし、一部のターミナルやログ出力システムでは、これらの特殊文字が正しく解釈されず、表示が崩れることがあります。

  7. エスケープコード (ANSI Escape Codes): ターミナル上でテキストの色、スタイル(太字、下線など)、カーソル位置などを制御するために使用される特殊な文字シーケンスです。Clangなどのコンパイラは、エラーメッセージの可読性を高めるために、これらのエスケープコードを使用してテキストを色付けすることがあります。しかし、これもまた、エスケープコードを解釈できない環境では文字化けの原因となります。

  8. TERM 環境変数: 現在のターミナルの種類(例: xterm, vt100, screen)を示す環境変数です。多くのプログラムは、この変数の値に基づいて、ターミナル固有の機能(エスケープコードの使用など)を有効にするかどうかを決定します。TERM=dumbを設定すると、プログラムは「ダムターミナル」(非常に基本的な機能しか持たないターミナル)で実行されていると認識し、色付けやカーソル制御などの高度なターミナル機能を無効にすることがあります。これは、ログファイルへの出力や、エスケープコードを解釈できない環境での実行時に役立ちます。

技術的詳細

このコミットは、GoのビルドシステムとGoコマンドがCコンパイラを呼び出す際の挙動を、以下の技術的な変更によって改善しています。

  1. src/cmd/dist/build.c における警告フラグの追加: cmd/distはGoツールチェインをビルドする際にCコンパイラ(主にGCC)を使用します。このファイルでは、Cコンパイラに渡されるデフォルトの引数リストである proto_gccargs に、以下の警告フラグが追加されました。

    • -Wextra: 広範な追加警告を有効にします。これにより、未使用の変数や初期化されていない変数など、より多くの潜在的な問題が検出されるようになります。
    • -Wunused: 未使用のコード要素(変数、関数、引数など)に関する警告を有効にします。
    • -Wuninitialized: 初期化されていない変数の使用に関する警告を有効にします。これは未定義動作につながる可能性のある重大な問題です。
    • -Wno-missing-field-initializers: 構造体や配列の初期化子で全てのフィールドが明示的に初期化されていない場合の警告を無効にします。これは、Goのコードベースで意図的に部分的な初期化が行われる場合があるため、ノイズを減らす目的で無効にされています。

    これらのフラグの追加により、Goツールチェイン自体のCコードのコンパイル時に、より厳格なコード品質チェックが適用されるようになりました。

  2. src/cmd/dist/build.c および src/cmd/go/build.go におけるClang診断の無効化: Clangコンパイラが使用される場合、そのエラーメッセージに含まれるASCIIアート(キャレット診断)や、一部の環境で問題となる可能性のある特殊な表示を無効にするためのフラグが追加されました。

    • -fno-caret-diagnostics: このフラグはClangに、エラーメッセージ中のキャレット(^)やチルダ(~)による視覚的な診断表示を抑制するよう指示します。これにより、ログファイルや基本的なターミナルでの表示がよりクリーンになります。 このフラグは、src/cmd/dist/build.cinstall 関数内でClangが検出された場合に gccargs に追加され、また src/cmd/go/build.goccompilerCmd 関数内でコンパイラがClangであると判断された場合にも追加されます。
  3. src/cmd/dist/unix.c および src/cmd/go/env.go における TERM=dumb の設定: Clangのエラーメッセージがターミナルエスケープコードを使用して色付けされることを防ぐため、TERM 環境変数を dumb に設定する変更が導入されました。

    • setenv("TERM", "dumb", 1); (src/cmd/dist/unix.c): cmd/dist が実行される際に、この環境変数が設定されます。これにより、cmd/dist が呼び出すCコンパイラ(特にClang)は、非常に基本的なターミナルで実行されていると認識し、色付けなどの高度なターミナル機能を抑制するようになります。
    • {"TERM", "dumb"} (src/cmd/go/env.go): cmd/go が内部でCコンパイラを呼び出す際に使用する環境変数リストにも TERM=dumb が追加されました。これにより、go build などがCgoコードをコンパイルする際にClangが使用された場合でも、同様にエラーメッセージの可読性が向上します。

これらの変更は、Goのビルドシステムが使用するCコンパイラ(GCCとClangの両方)の出力をより制御し、開発者にとってより有用で読みやすい情報を提供することを目的としています。特に、Clangのエラーメッセージの整形は、異なる環境での一貫した表示を保証するために重要です。

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

このコミットによる変更は、以下の4つのファイルにわたっています。

  1. src/cmd/dist/build.c:

    • proto_gccargs 配列に、新しい警告フラグ (-Wextra, -Wunused, -Wuninitialized, -Wno-missing-field-initializers) が追加されました。
    • install 関数内で、clang が検出された場合に -fno-caret-diagnostics フラグが gccargs に追加されるようになりました。
  2. src/cmd/dist/unix.c:

    • main 関数内で、setenv("TERM", "dumb", 1); が追加され、TERM 環境変数が dumb に設定されるようになりました。
  3. src/cmd/go/build.go:

    • ccompilerCmd 関数内で、コンパイラがClangであると判断された場合に、-fno-caret-diagnostics フラグがコンパイラ引数に追加されるようになりました。既存の -Qunused-arguments の追加ロジックの前に挿入されています。
  4. src/cmd/go/env.go:

    • mkEnv 関数で生成される環境変数リストに、{"TERM", "dumb"} が追加されました。

コアとなるコードの解説

src/cmd/dist/build.c

 // ...
 static char *proto_gccargs[] = {
 	// native Plan 9 compilers don't like non-standard prototypes
 	// so let gcc catch them.
 	"-Wstrict-prototypes",
+	"-Wextra",
+	"-Wunused",
+	"-Wuninitialized",
 	"-Wno-sign-compare",
 	"-Wno-missing-braces",
 	"-Wno-parentheses",
 	"-Wno-unknown-pragmas",
 	"-Wno-switch",
 	"-Wno-comment",
+	"-Wno-missing-field-initializers",
 	"-Werror",
 	"-fno-common",
 	"-ggdb",
 // ...
 static char *proto_gccargs[] = {
 	// native Plan 9 compilers don't like non-standard prototypes
 	// so let gcc catch them.
 	"-Wstrict-prototypes",
+	"-Wextra", // 追加: 広範な追加警告を有効化
+	"-Wunused", // 追加: 未使用のコードに関する警告を有効化
+	"-Wuninitialized", // 追加: 未初期化変数の使用に関する警告を有効化
 	"-Wno-sign-compare",
 	"-Wno-missing-braces",
 	"-Wno-parentheses",
 	"-Wno-unknown-pragmas",
 	"-Wno-switch",
 	"-Wno-comment",
+	"-Wno-missing-field-initializers", // 追加: フィールド初期化子の不足に関する警告を無効化
 	"-Werror",
 	"-fno-common",
 	"-ggdb",
 // ...
 install(char *dir)
 {
 // ...
 		if(clang) {
+			// disable ASCII art in clang errors, if possible
+			vadd(&gccargs, "-fno-caret-diagnostics"); // Clangのキャレット診断を無効化
 			// clang is too smart about unused command-line arguments
 			vadd(&gccargs, "-Qunused-arguments");
 		}

proto_gccargs は、cmd/dist がCコンパイラ(主にGCC)を呼び出す際に常に渡されるデフォルトの引数リストです。ここに -Wextra, -Wunused, -Wuninitialized が追加されたことで、GoツールチェインのCコードコンパイル時に、より多くの潜在的なコード品質問題が警告されるようになりました。-Wno-missing-field-initializers は、特定の警告を抑制するために追加されています。 また、install 関数内で clang が使用されていると判断された場合、-fno-caret-diagnostics が追加されます。これはClang特有のオプションで、エラーメッセージ中の視覚的なキャレット診断(ASCIIアート)を無効にし、よりプレーンなテキスト出力を強制します。

src/cmd/dist/unix.c

 // ...
 main(int argc, char **argv)
 {
 	setvbuf(stdout, nil, _IOLBF, 0);
 	setvbuf(stderr, nil, _IOLBF, 0);
 
+	setenv("TERM", "dumb", 1); // disable escape codes in clang errors
+
 	binit(&b);
 	
 	slash = "/";

main 関数の冒頭で setenv("TERM", "dumb", 1); が呼び出されています。これは、cmd/dist プロセスとその子プロセス(Cコンパイラなど)に対して TERM 環境変数を dumb に設定します。TERM=dumb は、ターミナルが非常に基本的な機能しか持たないことを示し、Clangなどのコンパイラがエラーメッセージに色付けや特殊な書式設定のためのエスケープコードを使用するのを抑制します。これにより、ログファイルや非対話型環境でのClangエラーの可読性が向上します。

src/cmd/go/build.go

 // ...
 func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 // ...
 	if strings.Contains(a[0], "clang") {
+		// disable ASCII art in clang errors, if possible
+		a = append(a, "-fno-caret-diagnostics") // Clangのキャレット診断を無効化
+		// clang is too smart about command-line arguments
 		a = append(a, "-Qunused-arguments")
 	}
 // ...

ccompilerCmd 関数は、cmd/go がCgoコードをコンパイルするためにCコンパイラを呼び出す際に、そのコマンドライン引数を構築します。コンパイラがClangであると検出された場合(strings.Contains(a[0], "clang"))、-fno-caret-diagnostics フラグが追加されます。これは cmd/dist/build.c と同様に、ClangのエラーメッセージからASCIIアートを削除し、可読性を高めるためのものです。

src/cmd/go/env.go

 // ...
 func mkEnv() []envVar {
 	return []envVar{
 		{"GORACE", os.Getenv("GORACE")},
 		{"GOROOT", goroot},
 		{"GOTOOLDIR", toolDir},
+
+		// disable escape codes in clang errors
+		{"TERM", "dumb"}, // Clangのエラーにおけるエスケープコードを無効化
 	}
 // ...

mkEnv 関数は、cmd/go が実行される際に設定される環境変数リストを生成します。このリストに {"TERM", "dumb"} が追加されたことで、cmd/go が起動する全ての子プロセス(Cコンパイラを含む)に対して TERM=dumb が適用されるようになります。これは cmd/dist/unix.c で行われた変更と同様に、Clangのエラーメッセージからエスケープコードによる色付けなどを抑制し、出力の可読性を向上させる効果があります。

関連リンク

参考にした情報源リンク