[インデックス 11699] ファイルの概要
このコミットは、Go言語のビルドシステムの一部である cmd/dist ツールにおいて、Cコンパイラを指定する環境変数 $CC を尊重するように変更を加えるものです。これにより、quietgcc.bash スクリプトが以前行っていた $CC の設定が cmd/dist にも適用されるようになり、ビルドプロセスの柔軟性が向上します。
コミット
commit 3f6a517db6f5e63844c4bd7b8e1871314df8b10d
Author: Russ Cox <rsc@golang.org>
Date: Wed Feb 8 00:22:38 2012 -0500
cmd/dist: respect $CC, as quietgcc.bash used to
R=golang-dev, r, iant
CC=golang-dev
https://golang.org/cl/5641051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3f6a517db6f5e63844c4bd7b8e1871314df8b10d
元コミット内容
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -336,8 +336,7 @@ setup(void)\n */\n \n // gccargs is the gcc command line to use for compiling a single C file.\n-static char *gccargs[] = {\n-\t\"gcc\",\n+static char *proto_gccargs[] = {\n \t\"-Wall\",\n \t\"-Wno-sign-compare\",\n \t\"-Wno-missing-braces\",
@@ -352,6 +351,8 @@ static char *gccargs[] = {\n \t\"-c\",\n };\n \n+static Vec gccargs;\n+\n // deptab lists changes to the default dependencies for a given prefix.\n // deps ending in /* read the whole directory; deps beginning with - \n // exclude files with that prefix.\n@@ -513,6 +514,16 @@ install(char *dir)\n \tvinit(&lib);\n \tvinit(&extra);\n \t\n+\t// set up gcc command line on first run.\n+\tif(gccargs.len == 0) {\n+\t\txgetenv(&b, \"CC\");\n+\t\tif(b.len == 0)\n+\t\t\tbprintf(&b, \"gcc\");\n+\t\tsplitfields(&gccargs, bstr(&b));\n+\t\tfor(i=0; i<nelem(proto_gccargs); i++)\n+\t\t\tvadd(&gccargs, proto_gccargs[i]);\n+\t}\n+\t\n \t// path = full path to dir.\n \tbpathf(&path, \"%s/src/%s\", goroot, dir);\n \tname = lastelem(dir);\n@@ -732,7 +743,7 @@ install(char *dir)\n \t\tvreset(&compile);\n \t\tif(!isgo) {\n \t\t\t// C library or tool.\n-\t\t\tvcopy(&compile, gccargs, nelem(gccargs));\n+\t\t\tvcopy(&compile, gccargs.p, gccargs.len);\n \t\t\tif(streq(gohostarch, \"amd64\"))\n \t\t\t\tvadd(&compile, \"-m64\");\n \t\t\telse if(streq(gohostarch, \"386\"))
変更の背景
Go言語のビルドプロセスでは、C言語で書かれた部分(例えば、ランタイムや一部のツール)をコンパイルするためにCコンパイラを使用します。以前は、quietgcc.bash というスクリプトが $CC 環境変数を設定し、特定のCコンパイラを使用するように指定していました。しかし、cmd/dist ツール自体がこの $CC 環境変数を直接尊重していなかったため、ビルドプロセス全体で一貫したCコンパイラの指定が困難でした。
このコミットの目的は、cmd/dist が $CC 環境変数の値を読み取り、それをCコンパイラのコマンドライン引数として使用するように変更することです。これにより、ユーザーやビルドシステムが $CC を通じて任意のCコンパイラを指定できるようになり、ビルド環境の柔軟性とカスタマイズ性が向上します。
前提知識の解説
cmd/dist
cmd/dist は、Go言語のソースコードからGoのディストリビューション(コンパイラ、ツール、標準ライブラリなど)をビルドするための内部ツールです。Goのブートストラッププロセスにおいて重要な役割を担っており、Goのコンパイラ自体がGoで書かれるようになる前に、初期のGoコンパイラをビルドするためにC言語で書かれていました。現在でも、Goのビルドシステムの中核をなすツールの一つです。一般的なGoアプリケーション開発者が直接使用することはほとんどありませんが、Goのビルドプロセスを理解する上で不可欠な要素です。
$CC 環境変数
$CC は、Unix系システムでCコンパイラを指定するために広く使われる環境変数です。例えば、CC=clang と設定すると、ビルドシステムはデフォルトの gcc ではなく clang をCコンパイラとして使用しようとします。これにより、異なるコンパイラを使用したり、特定のコンパイラオプションを適用したりすることが可能になります。
Vec 型 (Goの cmd/dist における)
Go言語の cmd/dist パッケージにおける Vec 型は、一般的なGoのプログラミングで使われるスライス ([]T) とは異なり、cmd/dist 内部で定義された動的な配列のようなデータ構造です。これは、cmd/dist がGo言語で書かれる以前のC言語のコードベースから派生しているため、C言語の慣習に近い形で実装されています。
ウェブ検索の結果によると、cmd/dist はGoのディストリビューション自体をブートストラップ、ビルド、テストするための内部コマンドラインツールであり、一般的なGoアプリケーションでの使用やインポートは意図されていません。Vec 型に関する直接的なドキュメントは公開されていませんが、その使用法から、可変長の文字列配列を扱うための内部的なユーティリティ構造であることが推測されます。
技術的詳細
このコミットの主要な変更点は、Cコンパイラのコマンドライン引数を格納する方法を静的な配列から動的な Vec 型の構造体に変更し、環境変数 $CC の値を動的に取り込むようにしたことです。
-
gccargsの変更:- 以前は
static char *gccargs[] = {"gcc", ...}という形で、gccを含む固定の文字列配列として定義されていました。 - 変更後、
gccargsはstatic Vec gccargs;というVec型の変数として宣言されます。これにより、実行時に要素を追加・削除できる動的な配列として扱えるようになります。 - 元の
gcc以外の固定オプション (-Wall,-Wno-sign-compareなど) はstatic char *proto_gccargs[]という新しい静的配列に移動されました。
- 以前は
-
install関数内での初期化ロジック:install関数内で、gccargs.len == 0(つまり、初回実行時) の場合にのみ、gccargsを初期化するロジックが追加されました。xgetenv(&b, "CC")を使用して環境変数$CCの値を取得します。- もし
$CCが設定されていない (b.len == 0) 場合は、デフォルトで"gcc"を使用します。 splitfields(&gccargs, bstr(&b))を呼び出し、取得した$CCの値をスペースで分割してgccargs(Vec型) の最初の要素として追加します。これにより、$CCに複数の引数(例:clang -target x86_64-linux-gnu)が設定されている場合でも適切に処理されます。for(i=0; i<nelem(proto_gccargs); i++) vadd(&gccargs, proto_gccargs[i]);ループにより、proto_gccargsに定義されていた固定のコンパイラオプションがgccargsに追加されます。
-
コンパイルコマンドの生成:
install関数内のCファイルのコンパイル部分 (if(!isgo)) で、コンパイルコマンドを生成する際に、以前はvcopy(&compile, gccargs, nelem(gccargs));と静的配列のgccargsをコピーしていましたが、変更後はvcopy(&compile, gccargs.p, gccargs.len);と、動的に構築されたVec型のgccargsの内容をコピーするように変更されました。
これらの変更により、cmd/dist はビルド時に $CC 環境変数を参照し、その値に基づいてCコンパイラと初期オプションを動的に設定できるようになります。
コアとなるコードの変更箇所
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -336,8 +336,7 @@ setup(void)\n */\n \n // gccargs is the gcc command line to use for compiling a single C file.\n-static char *gccargs[] = {\n-\t\"gcc\",\n+static char *proto_gccargs[] = {\n \t\"-Wall\",\n \t\"Wno-sign-compare\",\n \t\"-Wno-missing-braces\",
@@ -352,6 +351,8 @@ static char *gccargs[] = {\n \t\"-c\",\n };\n \n+static Vec gccargs;\n+\n // deptab lists changes to the default dependencies for a given prefix.\n // deps ending in /* read the whole directory; deps beginning with - \n // exclude files with that prefix.\n@@ -513,6 +514,16 @@ install(char *dir)\n \tvinit(&lib);\n \tvinit(&extra);\n \t\n+\t// set up gcc command line on first run.\n+\tif(gccargs.len == 0) {\n+\t\txgetenv(&b, \"CC\");\n+\t\tif(b.len == 0)\n+\t\t\tbprintf(&b, \"gcc\");\n+\t\tsplitfields(&gccargs, bstr(&b));\n+\t\tfor(i=0; i<nelem(proto_gccargs); i++)\n+\t\t\tvadd(&gccargs, proto_gccargs[i]);\n+\t}\n+\t\n \t// path = full path to dir.\n \tbpathf(&path, \"%s/src/%s\", goroot, dir);\n \tname = lastelem(dir);\n@@ -732,7 +743,7 @@ install(char *dir)\n \t\tvreset(&compile);\n \t\tif(!isgo) {\n \t\t\t// C library or tool.\n-\t\t\tvcopy(&compile, gccargs, nelem(gccargs));\n+\t\t\tvcopy(&compile, gccargs.p, gccargs.len);\n \t\t\tif(streq(gohostarch, \"amd64\"))\n \t\t\t\tvadd(&compile, \"-m64\");\n \t\t\telse if(streq(gohostarch, \"386\"))
コアとなるコードの解説
-
static char *proto_gccargs[]の導入:- 以前は
gccargsという名前でgccとそのデフォルトオプションがまとめて定義されていました。 - この変更により、
gcc以外の固定オプションがproto_gccargsという新しい配列に分離されました。これは、gcc自体は$CC環境変数から動的に取得されるため、固定オプションと分離する必要があったためです。
- 以前は
-
static Vec gccargs;の導入:gccargsが静的なchar*配列から、Vec型の動的な構造体に変更されました。これにより、実行時にコンパイラ名やオプションを柔軟に追加できるようになります。
-
install関数内でのgccargsの初期化ロジック:if(gccargs.len == 0): この条件は、gccargsがまだ初期化されていない初回のみ、以下の処理を実行することを保証します。これにより、環境変数の読み込みやVecの構築が一度だけ行われます。xgetenv(&b, "CC");: 環境変数CCの値を取得し、bというバッファに格納します。if(b.len == 0) bprintf(&b, "gcc");: もしCCが設定されていない場合、デフォルトのコンパイラとして"gcc"を使用するようにbを設定します。splitfields(&gccargs, bstr(&b));:bに格納された文字列($CCの値、または"gcc")をスペースで分割し、その結果をgccargs(Vec型) の要素として追加します。これにより、CC="clang -target x86_64-linux-gnu"のような値も適切に処理され、clangと-target x86_64-linux-gnuが別々の引数としてgccargsに格納されます。for(i=0; i<nelem(proto_gccargs); i++) vadd(&gccargs, proto_gccargs[i]);:proto_gccargsに定義されている-Wallなどの標準的なコンパイラオプションを、vadd関数を使ってgccargsに追加します。これにより、$CCで指定されたコンパイラに加えて、Goのビルドに必要な共通オプションが適用されます。
-
vcopy(&compile, gccargs.p, gccargs.len);への変更:- C言語のファイル(Go言語ではないファイル)をコンパイルする際に、以前は静的な
gccargs配列を直接コピーしていましたが、この変更により、動的に構築されたVec型のgccargsの内容 (gccargs.pは内部ポインタ、gccargs.lenは要素数) をcompileコマンドラインにコピーするようになりました。これにより、$CC環境変数の値が実際にコンパイルコマンドに反映されるようになります。
- C言語のファイル(Go言語ではないファイル)をコンパイルする際に、以前は静的な
これらの変更により、Goのビルドシステムは、Cコンパイラの選択とオプションの指定において、より柔軟で環境変数に依存した動作を実現できるようになりました。
関連リンク
- Go言語のビルドシステムに関する公式ドキュメント(もしあれば、より詳細な情報が得られる可能性がありますが、
cmd/distは内部ツールのため、公開されているドキュメントは少ないかもしれません。)
参考にした情報源リンク
- GitHub: golang/go commit 3f6a517db6f5e63844c4bd7b8e1871314df8b10d
- Go言語の
cmd/distに関するウェブ検索結果 - Go言語の
cmd/compile/internal/bitvecに関するウェブ検索結果 - 一般的なUnix系システムにおける
$CC環境変数の使用に関する知識