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

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

このコミットは、GoコンパイラのビルドプロセスにおけるGCCの警告フラグの扱いを修正するものです。具体的には、-Wuninitialized警告フラグが-O(最適化)フラグと同時に設定されていない場合に、一部のGCCバージョン(特にOS X 10.6上のGCC)でビルドエラーが発生する問題を解決します。

コミット

commit 4271dd4550311c05bb3523865bb123645033c265
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Wed Mar 26 14:20:18 2014 -0400

    cmd/dist: set -Wuninitialized only when -O is also set.
    GCC on OS X 10.6 doesn't support -Wuninitialized without -O.
    Fixes #7492.
    
    LGTM=iant
    R=golang-codereviews, dave, iant
    CC=golang-codereviews
    https://golang.org/cl/72360045

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

https://github.com/golang/go/commit/4271dd4550311c05bb3523865bb123645033c265

元コミット内容

cmd/dist: set -Wuninitialized only when -O is also set. GCC on OS X 10.6 doesn't support -Wuninitialized without -O. Fixes #7492.

変更の背景

Goコンパイラのビルドシステム(cmd/dist)は、CコードのコンパイルにGCCを使用しています。GCCには、コンパイル時に様々な警告を有効にするためのフラグが用意されており、その一つに-Wuninitializedがあります。このフラグは、初期化されていない変数を使用した場合に警告を発するためのものです。

しかし、一部の古いGCCバージョン、特にOS X 10.6に搭載されているGCCでは、-Wuninitializedフラグが単独で指定された場合、つまり-O(最適化)フラグが同時に指定されていない場合に、正しく機能しない、あるいはコンパイルエラーを引き起こすという問題がありました。これは、未初期化変数の検出が、コンパイラの最適化パスで行われるデータフロー解析に依存しているためです。最適化が有効になっていない場合、コンパイラは未初期化変数を確実に検出するための十分な情報を収集できないことがあります。

この問題は、Goのビルドプロセスが特定の環境(OS X 10.6)で失敗する原因となっていました。コミットメッセージにあるFixes #7492は、この問題がGoのIssueトラッカーで報告され、このコミットによって解決されたことを示しています。

前提知識の解説

  • GCC (GNU Compiler Collection): C、C++、Goなど、様々なプログラミング言語をコンパイルするためのコンパイラ群です。Goの初期のビルドシステムでは、Go言語で書かれたコードをCに変換し、それをGCCでコンパイルするという方式が取られていました。
  • コンパイラ警告フラグ: コンパイラは、コードの潜在的な問題(バグにつながる可能性のある記述、非推奨の機能の使用など)を開発者に知らせるために警告を発します。これらの警告は、特定のフラグ(例: -Wall, -Wextra, -Wuninitialized)をコンパイラに渡すことで有効にできます。
  • -Wuninitialized: GCCの警告フラグの一つで、初期化されていない変数が使用された場合に警告を発します。これにより、未定義の動作を引き起こす可能性のあるバグを早期に発見できます。
  • -O (Optimization Flags): GCCの最適化フラグで、-O1, -O2, -O3, -Osなどがあります。これらのフラグは、コンパイラに生成されるコードのパフォーマンスを向上させるための様々な最適化を適用するよう指示します。最適化プロセスでは、コードのデータフロー解析など、より詳細な分析が行われるため、-Wuninitializedのような警告の検出精度が向上することがあります。
  • cmd/dist: Goのソースコードをビルドするためのツールです。Goのコンパイラや標準ライブラリなどを構築する役割を担っています。
  • proto_gccargs[]proto_gccargs2[]: src/cmd/dist/build.cファイル内で定義されている、GCCに渡されるデフォルトのコンパイル引数(フラグ)の配列です。proto_gccargsは常に適用される基本的なフラグを含み、proto_gccargs2は特定の条件(例: ユーザーのCFLAGS環境変数が-Oを含まない場合)で追加されるフラグを含みます。

技術的詳細

このコミットの技術的な核心は、GCCの-Wuninitialized警告フラグの依存関係を正しく管理することにあります。

従来のsrc/cmd/dist/build.cでは、-Wuninitializedproto_gccargs[]という配列に直接含まれていました。この配列に含まれるフラグは、Goのビルドプロセスにおいて常にGCCに渡されます。しかし、前述の通り、一部のGCCバージョンでは-Oフラグなしで-Wuninitializedを使用すると問題が発生します。

このコミットでは、この問題を解決するために、-Wuninitializedフラグをproto_gccargs[]から削除し、proto_gccargs2[]に移動しました。proto_gccargs2[]は、ユーザーがCFLAGS環境変数で-Oフラグを指定していない場合にのみ追加されるように設計されています。

これにより、以下の挙動が実現されます。

  1. ユーザーがCFLAGS-Oを指定している場合: proto_gccargs[]に含まれる基本的なフラグと、ユーザーが指定したCFLAGSが適用されます。この場合、-WuninitializedはユーザーのCFLAGSに含まれる-Oフラグと共存するため、問題なく機能します。
  2. ユーザーがCFLAGS-Oを指定していない場合: proto_gccargs[]に含まれる基本的なフラグに加えて、proto_gccargs2[]に含まれるフラグが追加されます。proto_gccargs2[]には-Wuninitializedと、デフォルトの最適化レベルである-O2(またはNetBSD ARM環境では-O1)が含まれています。これにより、-Wuninitializedが常に-Oフラグと同時に適用されることが保証され、OS X 10.6のような環境でのビルドエラーが回避されます。

この変更は、Goのビルドシステムがより堅牢になり、様々なGCCバージョンや環境下での互換性を向上させることを目的としています。

また、コミットの差分には、NetBSD ARM環境におけるGCC 4.5.4の最適化に関する既知の問題(gc/mparith3.cの誤最適化)に対する回避策として、-O1フラグを明示的に指定するコメントとコードが含まれています。これは、このコミットとは直接関係ありませんが、build.cがGCCの特定の挙動に対応している例として示されています。

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

変更はsrc/cmd/dist/build.cファイルに集中しています。

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -457,7 +457,6 @@ static char *proto_gccargs[] = {
 	"-Wstrict-prototypes",
 	"-Wextra",
 	"-Wunused",
-	"-Wuninitialized",
 	"-Wno-sign-compare",
 	"-Wno-missing-braces",
 	"-Wno-parentheses",
@@ -469,17 +468,19 @@ static char *proto_gccargs[] = {
 	"-fno-common",
 	"-ggdb",
 	"-pipe",
-#if defined(__NetBSD__) && defined(__arm__)\n-\t// GCC 4.5.4 (NetBSD nb1 20120916) on ARM is known to mis-optimize gc/mparith3.c\n-\t// Fix available at http://patchwork.ozlabs.org/patch/64562/.\n-\t"-O1",\n-#endif
 };
 
 // gccargs2 is the second part of gccargs.
 // it is used if the environment isn't defining CFLAGS.
 static char *proto_gccargs2[] = {
+\t// on older versions of GCC, -Wuninitialized is not supported
+\t// without -O, so put it here together with -O settings in case
+\t// the user's $CFLAGS doesn't include -O.
+\t"-Wuninitialized",
 #if defined(__NetBSD__) && defined(__arm__)\n+\t// GCC 4.5.4 (NetBSD nb1 20120916) on ARM is known to mis-optimize gc/mparith3.c\n+\t// Fix available at http://patchwork.ozlabs.org/patch/64562/.\n+\t"-O1",\n #else
 \t"-O2",
 #endif

コアとなるコードの解説

  1. -Wuninitializedの削除 (proto_gccargs[]から): static char *proto_gccargs[]の定義から、-Wuninitializedの行が削除されています。これは、この警告フラグが常に適用されるべきではない、という判断に基づいています。

  2. -Wuninitializedの追加 (proto_gccargs2[]へ): static char *proto_gccargs2[]の定義に、-Wuninitializedの行が追加されています。この配列は、ユーザーがCFLAGS環境変数で独自のコンパイルフラグを指定していない場合に、追加でGCCに渡されるフラグを含みます。 重要なのは、proto_gccargs2[]には、デフォルトの最適化フラグである-O2(またはNetBSD ARM環境では-O1)も含まれている点です。これにより、proto_gccargs2[]が適用される際には、-Wuninitializedが常に最適化フラグと同時に使用されることが保証されます。

この変更により、Goのビルドシステムは、-Wuninitialized-Oなしでは正しく機能しないGCCのバージョン(特にOS X 10.6)でも、安定して動作するようになります。ユーザーがCFLAGS-Oを指定している場合は、その設定が優先され、指定していない場合はproto_gccargs2[]によって-O2(または-O1)と-Wuninitializedが自動的に追加されるため、互換性が保たれます。

関連リンク

  • Go Issue #7492 (コミットメッセージに記載されているが、現在のGitHubリポジトリでは直接見つからない可能性あり)
  • Go Code Review 72360045: https://golang.org/cl/72360045 (Goの公式コードレビューシステムへのリンク)

参考にした情報源リンク