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

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

このコミットは、Go言語のビルドツール cmd/dist における、gcc に渡す -DGOARCH_$GOARCH フラグの誤りを修正するものです。具体的には、ターゲットアーキテクチャを示すフラグに、誤ってターゲットOSの値が渡されていた問題を解決します。

コミット

  • コミットハッシュ: 1127b229763811c5e90d4d96b2c9f150e816df1d
  • 作者: Shenghou Ma minux.ma@gmail.com
  • 日付: 2012年2月8日 (水) 14:36:38 -0500

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

https://github.com/golang/go/commit/1127b229763811c5e90d4d96b2c9f150e816df1d

元コミット内容

cmd/dist: pass correct -DGOARCH_$GOARCH flag to gcc.

R=rsc
CC=golang-dev
https://golang.org/cl/5643061

変更の背景

Go言語のビルドシステムは、異なるオペレーティングシステム (OS) やCPUアーキテクチャ向けにコンパイル(クロスコンパイル)を行う能力を持っています。このプロセスにおいて、Goのビルドツールチェーンの一部である cmd/dist は、C言語で書かれた部分(例えば、ランタイムや一部の標準ライブラリ)をコンパイルするために gcc などのCコンパイラを呼び出します。

この際、Cコンパイラには、ターゲットのOS (GOOS) やアーキテクチャ (GOARCH) に応じた適切なプリプロセッサ定義(マクロ)を渡す必要があります。例えば、GOOS=linux かつ GOARCH=amd64 の場合、gcc には -DGOOS_linux-DGOARCH_amd64 といったフラグが渡されることが期待されます。これらの定義は、C言語のソースコード内で #ifdef GOOS_linux のように条件付きコンパイルを行うために利用されます。

しかし、このコミット以前の cmd/dist の実装では、-DGOARCH_$GOARCH という形式のフラグを生成する際に、誤って GOARCH の値ではなく GOOS の値を使用していました。つまり、例えば GOARCH=amd64 であっても、-DGOARCH_linux のように、OS名がアーキテクチャ名として渡されてしまうバグが存在していました。

この誤ったフラグの渡し方は、特にクロスコンパイルを行う際に問題を引き起こす可能性がありました。C言語のコードが、誤ったアーキテクチャ定義に基づいてコンパイルされてしまうため、実行時エラーや予期せぬ動作につながる恐れがありました。このコミットは、このビルド時の設定ミスを修正し、Goのビルドプロセスの堅牢性と正確性を向上させることを目的としています。

前提知識の解説

Go言語のビルドシステム (cmd/dist)

Go言語のビルドシステムは、Goのソースコードをコンパイルして実行可能なバイナリを生成する一連のツールとプロセスを指します。その中核をなすのが cmd/dist です。cmd/dist は、Goのツールチェーン自体をビルドしたり、Goの標準ライブラリをコンパイルしたりする際に使用される低レベルのビルドツールです。これは、go build コマンドが内部的に利用する基盤の一部でもあります。

cmd/dist は、Goのソースコードだけでなく、Goランタイムの一部や特定の標準ライブラリがC言語やアセンブリ言語で書かれているため、それらをコンパイルするために gcc などの外部Cコンパイラを呼び出す役割も担っています。この際、ターゲットのOSやアーキテクチャに応じた適切なコンパイルフラグを生成し、Cコンパイラに渡す必要があります。

GOOSGOARCH

GOOSGOARCH は、Go言語のビルドにおいて非常に重要な環境変数です。これらは、Goプログラムが実行されるターゲットのオペレーティングシステムとCPUアーキテクチャを指定するために使用されます。

  • GOOS (Go Operating System): ターゲットのOSを指定します。例えば、linux, windows, darwin (macOS), freebsd などがあります。
  • GOARCH (Go Architecture): ターゲットのCPUアーキテクチャを指定します。例えば、amd64, arm, arm64, 386 などがあります。

これらの環境変数を設定することで、Goコンパイラは指定されたOSとアーキテクチャに最適化されたバイナリを生成できます。これは、特にクロスコンパイル(現在のOSとは異なるOSやアーキテクチャ向けのバイナリを生成すること)を行う際に不可欠です。

gcc-D フラグ

gcc (GNU Compiler Collection) は、C、C++、Objective-C、Fortran、Ada、Goなどのプログラミング言語をサポートするコンパイラ群です。C言語のコンパイルにおいて、-D フラグはプリプロセッサマクロを定義するために使用されます。

構文は gcc -Dmacro_name または gcc -Dmacro_name=value です。 例えば、gcc -DDEBUG とすると、Cソースコード内で DEBUG というマクロが定義された状態になります。これにより、以下のような条件付きコンパイルが可能になります。

#ifdef DEBUG
    // デバッグモードでのみコンパイルされるコード
    printf("Debug mode is enabled.\n");
#endif

Goのビルドシステムでは、GOOSGOARCH の値に基づいて、gcc-DGOOS_linux-DGOARCH_amd64 のようなフラグを渡すことで、C言語で書かれたGoランタイムやライブラリのコードが、ターゲット環境に特化した形でコンパイルされるように制御しています。

技術的詳細

このコミットが修正しているのは、src/cmd/dist/build.c ファイル内の install 関数です。この関数は、Goのビルドプロセスにおいて、C言語で書かれた部分をコンパイルするためのコマンドライン引数を構築する役割を担っています。

具体的には、install 関数内で gcc に渡す引数を格納する compile という変数に、vadd 関数を使って引数を追加しています。問題の箇所は、GOARCH に対応するプリプロセッサ定義を追加する部分でした。

変更前のコードでは、以下のようになっていました。

tvadd(&compile, bprintf(&b, "-DGOARCH_%s", goos));

ここで bprintf(&b, "-DGOARCH_%s", goos) は、フォーマット文字列 "-DGOARCH_%s"%s 部分に goos 変数(ターゲットOS名)の値を挿入して文字列を生成しています。例えば、goos が "linux" であれば、結果として "-DGOARCH_linux" という文字列が生成され、これが gcc に渡されていました。

しかし、意図されていたのはターゲットアーキテクチャ (goarch) の値を使用することでした。つまり、goarch が "amd64" であれば、"-DGOARCH_amd64" という文字列が生成されるべきでした。

このコミットによる修正は、この goosgoarch に変更するだけという非常にシンプルなものです。

tvadd(&compile, bprintf(&b, "-DGOARCH_%s", goarch));

この変更により、bprintf 関数は正しい goarch 変数の値を使用して文字列を生成するようになり、結果として gcc には -DGOARCH_amd64-DGOARCH_arm のように、正しいターゲットアーキテクチャを示すプリプロセッサ定義が渡されるようになります。

この修正は、Goのクロスコンパイル機能の正確性を保証し、特にC言語で書かれたGoランタイムや標準ライブラリのコンパイルが、ターゲットのCPUアーキテクチャに完全に適合するようにするために不可欠です。これにより、異なるプラットフォーム上でのGoプログラムの安定性と互換性が向上します。

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

変更は src/cmd/dist/build.c ファイルの install 関数内、具体的には796行目付近の一箇所です。

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -796,7 +796,7 @@ install(char *dir)
 		tvadd(&compile, "-I");
 		tvadd(&compile, workdir);
 		tvadd(&compile, bprintf(&b, "-DGOOS_%s", goos));
-		tvadd(&compile, bprintf(&b, "-DGOARCH_%s", goos));
+		tvadd(&compile, bprintf(&b, "-DGOARCH_%s", goarch));
 	}

 	bpathf(&b, "%s/%s", workdir, lastelem(files.p[i]));

コアとなるコードの解説

上記の差分が示すように、変更は非常に簡潔です。

  • 変更前: tvadd(&compile, bprintf(&b, "-DGOARCH_%s", goos)); この行では、gcc に渡すコンパイル引数リスト compile に、-DGOARCH_ に続けてターゲットOS名 (goos) を付加した文字列を追加していました。これは論理的な誤りであり、GOARCH フラグにはターゲットアーキテクチャ名が付加されるべきです。

  • 変更後: tvadd(&compile, bprintf(&b, "-DGOARCH_%s", goarch)); この行では、-DGOARCH_ に続けてターゲットアーキテクチャ名 (goarch) を付加した文字列を追加するように修正されています。これにより、gcc は正しいプリプロセッサ定義を受け取り、ターゲットアーキテクチャに合わせた適切なコンパイルが行われるようになります。

この修正は、GoのビルドシステムがCコンパイラに渡す引数の正確性を保証し、クロスコンパイル時の潜在的な問題を解消するために不可欠なものです。

関連リンク

  • Go Change List (CL) 5643061: https://golang.org/cl/5643061 このコミットに対応するGoのコードレビューシステム(Gerrit)上の変更リストです。元の議論や詳細な変更内容を確認できます。

参考にした情報源リンク