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

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

コミット

commit 7c2bfa4f2cd591c618353bc3099678b0db6e8750
Author: Bobby Powers <bobbypowers@gmail.com>
Date:   Thu Feb 16 13:31:46 2012 -0500

    dist: add clang specific -Wno options
    
    Clang 3.1 has more warnings enabled by default than GCC.
    Combined with -Werror, they cause the build to fail
    unnecessarily.  if the name of our compiler ends in "clang",
    add the necessary extra -Wno options.  Ideally we would add
    these flags unconditionally, as GCC is supposed to ignore
    unknown -Wno flags, but apple's llvm-gcc doesn't.
    
    Fixes #2878.
    
    R=rsc, dave
    CC=golang-dev
    https://golang.org/cl/5673055

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

https://github.com/golang/go/commit/7c2bfa4f2cd591c618353bc3099678b0db6e8750

元コミット内容

dist: add clang specific -Wno options

このコミットは、Go言語のビルドシステムにおいて、Clangコンパイラに特化した警告抑制オプション(-Wno)を追加するものです。

変更の背景

この変更の背景には、当時のClang 3.1コンパイラがGCC(GNU Compiler Collection)と比較して、デフォルトでより多くの警告を有効にしていたという問題があります。Go言語のビルドプロセスでは、しばしば-Werrorというコンパイラフラグが使用されます。このフラグは、コンパイラの警告をエラーとして扱い、警告が発生した場合にはビルドを失敗させるようにします。

Clang 3.1のデフォルトの警告設定と-Werrorの組み合わせにより、Goのビルドが不必要に失敗する事態が発生していました。これは、コード自体に問題がないにもかかわらず、コンパイラの警告設定の違いによってビルドが中断されるという非効率な状況を生み出していました。

特に、Appleのllvm-gccというコンパイラが、未知の-Wnoフラグを無視しないという特性も問題の一因でした。理想的には、-Wnoフラグはコンパイラが認識しない場合でも無視されるべきですが、llvm-gccはそのように動作しなかったため、Clangに特化した警告抑制オプションを条件付きで追加する必要がありました。

この問題は、GoのIssue #2878として報告され、このコミットによって解決されました。

前提知識の解説

Clang

Clangは、C、C++、Objective-C、Objective-C++言語のコンパイラフロントエンドです。LLVMプロジェクトの一部として開発されており、高速なコンパイル、優れた診断機能、モジュール性などが特徴です。特に、警告メッセージが非常に分かりやすいことで知られています。

GCC (GNU Compiler Collection)

GCCは、GNUプロジェクトによって開発されているコンパイラ群です。C、C++、Objective-C、Fortran、Ada、Goなど、多くのプログラミング言語をサポートしています。長年にわたり、Unix系システムにおける標準的なコンパイラとして広く利用されてきました。

-Werror コンパイラフラグ

-Werrorは、コンパイラに渡されるオプションの一つで、すべてのコンパイラ警告をエラーとして扱うように指示します。このフラグが有効な場合、コードに警告があるだけでコンパイルが失敗します。これは、コード品質を高く保ち、潜在的な問題を早期に発見するために使用されることが多いです。しかし、異なるコンパイラやバージョン間で警告の厳しさが異なる場合、ビルドの互換性問題を引き起こす可能性があります。

-Wno- コンパイラフラグ

-Wno-は、特定の警告を抑制するためのコンパイラフラグです。例えば、-Wno-unused-variableは未使用変数の警告を抑制します。これにより、開発者は特定の警告がコードの意図的な部分である場合や、一時的に無視したい場合に、ビルドを中断せずに作業を進めることができます。

Go言語の dist ツール

Go言語のソースコードには、src/cmd/distというディレクトリが存在します。このdistツールは、Go言語自身のビルドプロセスを管理するための内部ツールです。Goのコンパイラ、リンカ、標準ライブラリなどをビルドし、インストールする役割を担っています。Goのビルドシステムは、C言語で書かれた部分(特に初期のブートストラップコンパイラやビルドツール)とGo言語で書かれた部分が混在しており、distツールはそのC言語部分のビルドも調整します。

src/cmd/dist/build.c ファイル

src/cmd/dist/build.cは、Go言語のdistツールの一部であり、C言語で書かれたソースファイルです。このファイルは、GoのビルドプロセスにおけるCコードのコンパイルオプションや、ビルド対象のディレクトリ構造などを定義・管理しています。このコミットでは、このファイル内のコンパイラ引数を設定するロジックが変更されています。

技術的詳細

このコミットの技術的な核心は、Go言語のビルドプロセスにおいて、使用されているCコンパイラがClangであるかどうかを検出し、Clangの場合にのみ特定の警告抑制オプションを追加するという点です。

具体的には、src/cmd/dist/build.cファイル内で、コンパイラの実行ファイル名(gccargs.p[0]に格納されていると推測される)に"clang"という文字列が含まれているかどうかをxstrstr関数でチェックしています。xstrstrは、Goの内部ツールで使われる文字列検索関数で、C標準ライブラリのstrstrに相当します。

もしコンパイラ名に"clang"が含まれていれば、以下の2つの警告抑制オプションがvadd関数(可変引数リストに要素を追加するGo内部ツール用の関数)を使ってコンパイラ引数リストに追加されます。

  1. -Wno-dangling-else: この警告は、if文とelse文の対応が曖昧な場合に発生します。例えば、ネストされたif文でelseがどのifに対応するかが不明瞭な場合に警告されます。Clangはこのようなケースに対してGCCよりも厳しく警告を出すことがあります。
  2. -Wno-unused-value: この警告は、式の結果が使用されていない場合に発生します。例えば、関数が値を返すにもかかわらず、その戻り値が変数に代入されたり、他の式で使用されたりしない場合に警告されます。これもClangがより積極的に警告する傾向があります。

コミットメッセージにあるように、理想的にはこれらのフラグは無条件に追加されるべきでした。なぜなら、GCCのような他のコンパイラは、通常、認識しない-Wnoフラグを無視するように設計されているからです。しかし、Appleのllvm-gccがこの理想的な動作をせず、未知の-Wnoフラグでビルドが失敗する可能性があったため、Clangに特化した条件付きの追加が必要とされました。

この変更により、Clang 3.1を使用した場合でも、Goのビルドが不必要な警告によって中断されることなく、正常に完了するようになりました。

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

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -582,8 +582,12 @@ install(char *dir)
 		splitfields(&gccargs, bstr(&b));
 		for(i=0; i<nelem(proto_gccargs); i++)
 			vadd(&gccargs, proto_gccargs[i]);
+		if(xstrstr(gccargs.p[0], "clang") != nil) {
+			vadd(&gccargs, "-Wno-dangling-else");
+			vadd(&gccargs, "-Wno-unused-value");
+		}
 	}
-	
+
 	islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
 	ispkg = hasprefix(dir, "pkg");
 	isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo");

コアとなるコードの解説

変更はsrc/cmd/dist/build.cファイルのinstall関数内で行われています。

  1. if(xstrstr(gccargs.p[0], "clang") != nil):

    • gccargs.p[0]は、コンパイラの実行ファイル名(例: gcc, clang, llvm-gccなど)を指す文字列であると推測されます。
    • xstrstrは、第一引数の文字列内に第二引数の文字列が含まれているかを検索する関数です。
    • != nilは、xstrstrが文字列を見つけた場合に非NULL値を返すため、"clang"という文字列がコンパイラ名に含まれているかどうかをチェックしています。
    • この条件文により、現在使用されているコンパイラがClangベースである場合にのみ、以下のコードブロックが実行されるようになります。
  2. vadd(&gccargs, "-Wno-dangling-else");:

    • vaddは、gccargsという引数リストに新しい要素を追加するGo内部ツール用の関数です。
    • ここで、-Wno-dangling-elseというコンパイラフラグが追加されます。このフラグは、elseがどのifに対応するか曖昧な場合に発生する警告を抑制します。Clangはこのような構造に対して厳しく警告を出す傾向があります。
  3. vadd(&gccargs, "-Wno-unused-value");:

    • 同様に、-Wno-unused-valueというコンパイラフラグが追加されます。このフラグは、式の結果が使用されていない場合に発生する警告を抑制します。例えば、戻り値を持つ関数を呼び出しても、その戻り値をどこにも代入しない場合に警告されます。

これらの変更により、Clangコンパイラを使用した場合にのみ、Goのビルドが不必要に失敗する原因となっていた特定の警告が抑制され、ビルドが正常に完了するようになります。また、コードの整形(空行の追加)も行われています。

関連リンク

  • Go Issue #2878: このコミットが修正した問題のトラッキングイシュー。
    • https://golang.org/issue/2878 (ただし、このリンクは現在のGoのイシュートラッカーでは見つからない可能性があります。古いイシュートラッカーの形式かもしれません。)
  • Go CL 5673055: このコミットに対応するGoのコードレビュー(Change List)。
    • https://golang.org/cl/5673055 (こちらも現在のGoのCLシステムでは見つからない可能性があります。古いCLの形式かもしれません。)

参考にした情報源リンク

  • Clang Compiler User's Manual: Clangの警告オプションに関する一般的な情報。
  • GCC Command Options: GCCの警告オプションに関する一般的な情報。
  • Go言語のソースコード構造に関する一般的な知識。