[インデックス 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
環境変数の使用に関する知識