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

[インデックス 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 の値を動的に取り込むようにしたことです。

  1. gccargs の変更:

    • 以前は static char *gccargs[] = {"gcc", ...} という形で、gcc を含む固定の文字列配列として定義されていました。
    • 変更後、gccargsstatic Vec gccargs; という Vec 型の変数として宣言されます。これにより、実行時に要素を追加・削除できる動的な配列として扱えるようになります。
    • 元の gcc 以外の固定オプション (-Wall, -Wno-sign-compare など) は static char *proto_gccargs[] という新しい静的配列に移動されました。
  2. 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 に追加されます。
  3. コンパイルコマンドの生成:

    • 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\"))

コアとなるコードの解説

  1. static char *proto_gccargs[] の導入:

    • 以前は gccargs という名前で gcc とそのデフォルトオプションがまとめて定義されていました。
    • この変更により、gcc 以外の固定オプションが proto_gccargs という新しい配列に分離されました。これは、gcc 自体は $CC 環境変数から動的に取得されるため、固定オプションと分離する必要があったためです。
  2. static Vec gccargs; の導入:

    • gccargs が静的な char* 配列から、Vec 型の動的な構造体に変更されました。これにより、実行時にコンパイラ名やオプションを柔軟に追加できるようになります。
  3. 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のビルドに必要な共通オプションが適用されます。
  4. vcopy(&compile, gccargs.p, gccargs.len); への変更:

    • C言語のファイル(Go言語ではないファイル)をコンパイルする際に、以前は静的な gccargs 配列を直接コピーしていましたが、この変更により、動的に構築された Vec 型の gccargs の内容 (gccargs.p は内部ポインタ、gccargs.len は要素数) を compile コマンドラインにコピーするようになりました。これにより、$CC 環境変数の値が実際にコンパイルコマンドに反映されるようになります。

これらの変更により、Goのビルドシステムは、Cコンパイラの選択とオプションの指定において、より柔軟で環境変数に依存した動作を実現できるようになりました。

関連リンク

  • Go言語のビルドシステムに関する公式ドキュメント(もしあれば、より詳細な情報が得られる可能性がありますが、cmd/dist は内部ツールのため、公開されているドキュメントは少ないかもしれません。)

参考にした情報源リンク