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

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

このコミットは、Go言語のツールチェインの一部である cmd/dist ディレクトリ内の build.c ファイルに対する変更です。cmd/dist は、Goのソースコードからブートストラップツールや標準ライブラリをビルドするためのユーティリティ群を含むディレクトリです。build.c は、そのビルドプロセスにおいてC言語で書かれたコンポーネント(例えば、Goのランタイムの一部やツール)をコンパイルおよびリンクするロジックを担っています。具体的には、gcc などのCコンパイラを呼び出す際の引数管理を行っています。

コミット

commit 136f12f51fde69d5b0c89ec7a9cd9436c7b7535d
Author: Russ Cox <rsc@golang.org>
Date:   Wed Feb 8 11:12:14 2012 -0500

    cmd/dist: pass -m32 or -m64 to link too, not just compile
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/5646053

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

https://github.com/golang/go/commit/136f12f51fde69d5b0c89ec7a9cd9436c7b7535d

元コミット内容

cmd/dist: コンパイル時だけでなく、リンク時にも -m32 または -m64 フラグを渡すように変更。

変更の背景

このコミットの背景には、Go言語のビルドシステムがC言語で書かれたコンポーネント(特にブートストラップツールやランタイムの一部)をコンパイルおよびリンクする際の、アーキテクチャ指定フラグの扱いに問題があったことが挙げられます。

Goのビルドプロセスでは、異なるターゲットアーキテクチャ(例: 32ビットまたは64ビット)向けにバイナリを生成する必要があります。これには、Cコンパイラ(通常はGCC)に対して適切なフラグ(-m32 または -m64)を渡すことが不可欠です。

以前の実装では、これらのアーキテクチャ指定フラグがコンパイルステップ(.o ファイルを生成する段階)には渡されていましたが、リンクステップ(実行可能ファイルを生成する段階)には適切に渡されていませんでした。これにより、特定の環境やクロスコンパイルのシナリオにおいて、コンパイルされたオブジェクトファイルとリンカが期待するアーキテクチャが一致せず、リンクエラーが発生する可能性がありました。

この変更は、コンパイルとリンクの両方で一貫してアーキテクチャ指定フラグが適用されるようにすることで、ビルドの堅牢性と正確性を向上させることを目的としています。

前提知識の解説

cmd/dist

cmd/dist は、Go言語のソースコードからGoツールチェイン自体をビルドするためのブートストラップツールです。GoはGo自身で書かれていますが、最初のコンパイラをビルドするためには既存のCコンパイラ(GCCなど)が必要です。cmd/dist はこの初期ビルドプロセスを管理し、Goのコンパイラ、リンカ、標準ライブラリなどを構築します。

GCC (GNU Compiler Collection)

GCCは、C、C++、Goなど様々なプログラミング言語に対応したコンパイラ群です。Goのビルドプロセスでは、特に初期のブートストラップ段階や、C言語で書かれたGoランタイムの一部をコンパイル・リンクするためにGCCが利用されます。

-m32 および -m64 フラグ

これらはGCCのコンパイラおよびリンカオプションで、生成するバイナリのターゲットアーキテクチャを指定します。

  • -m32: 32ビットアーキテクチャ(例: x86)向けのコードを生成するよう指示します。
  • -m64: 64ビットアーキテクチャ(例: x86-64/amd64)向けのコードを生成するよう指示します。 これらのフラグは、コンパイル時(ソースコードをオブジェクトファイルに変換する際)とリンク時(オブジェクトファイルを結合して実行可能ファイルを生成する際)の両方で、一貫して適用される必要があります。

コンパイルとリンク

ソフトウェアのビルドプロセスは、大きく分けて「コンパイル」と「リンク」の2つのフェーズに分かれます。

  • コンパイル: ソースコード(例: .c ファイル)を機械語のオブジェクトファイル(例: .o ファイル)に変換するプロセスです。この段階で、ソースコードの文法チェックや最適化が行われます。
  • リンク: 複数のオブジェクトファイルやライブラリを結合し、最終的な実行可能ファイルや共有ライブラリを生成するプロセスです。この段階で、関数呼び出しのアドレス解決などが行われます。

go_bootstrap

Goのブートストラッププロセスで生成される初期のGoコンパイラやツールを指します。これは、最終的なGoツールチェインをビルドするために使用されます。

技術的詳細

src/cmd/dist/build.c は、GoのビルドシステムがC言語で書かれたコンポーネントを処理する際の中心的なロジックを含んでいます。このファイル内の install 関数は、特定のターゲット(C言語のツールやライブラリ)をビルドする責任を負っています。

ビルドプロセスでは、gcc コマンドが複数回呼び出されます。

  1. コンパイル時: Cソースファイルをオブジェクトファイル(.o)にコンパイルするために gcc -c ... が実行されます。
  2. リンク時: 生成されたオブジェクトファイルを結合し、最終的な実行可能ファイル(例: go_bootstrap やその他のC言語ツール)を生成するために gcc -o ... が実行されます。

問題は、gccargs という変数に格納されているコンパイラオプションが、コンパイル時には適切に適用されていたものの、リンク時には一部が欠落していた点にありました。特に、アーキテクチャ指定フラグである -m32-m64 は、コンパイル時には compile ベクタに追加されていましたが、リンク時には link ベクタに明示的に追加されていませんでした。

このコミットは、リンク時にも gohostarch(ホストアーキテクチャ)に基づいて適切な -m32 または -m64 フラグを link ベクタに追加することで、この不整合を解消しています。また、gccargs から -c フラグを削除し、コンパイル時にのみ明示的に追加するように変更することで、gccargs がコンパイルとリンクの両方に共通して適用されるべきオプションのみを含むように整理しています。

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

src/cmd/dist/build.c ファイルにおいて、以下の変更が行われました。

  1. proto_gccargs 配列から -c フラグが削除されました。

    --- a/src/cmd/dist/build.c
    +++ b/src/cmd/dist/build.c
    @@ -348,7 +348,6 @@ static char *proto_gccargs[] = {
     	"-fno-common",
     	"-ggdb",
     	"-O2",
    -	"-c",
     };
    
  2. install 関数内のCコマンドのリンク処理において、gccargs の内容をコピーし、さらに gohostarch に基づいて -m32 または -m64 フラグが追加されるようになりました。

    --- a/src/cmd/dist/build.c
    +++ b/src/cmd/dist/build.c
    @@ -561,9 +560,16 @@ install(char *dir)\
     	vadd(&link, bpathf(&b, "%s/bin/tool/go_bootstrap%s", goroot, exe));\
     } else {\
     	// C command.\
    -	vadd(&link, "gcc");\
    +	// Use gccargs, but ensure that link.p[2] is output file,\
    +	// as noted above.\
    +	vadd(&link, gccargs.p[0]);\
     	vadd(&link, "-o");\
     	vadd(&link, bpathf(&b, "%s/bin/tool/%s%s", goroot, name, exe));\
    +	vcopy(&link, gccargs.p+1, gccargs.len-1);\
    +	if(streq(gohostarch, "amd64"))\
    +		vadd(&link, "-m64");\
    +	else if(streq(gohostarch, "386"))\
    +		vadd(&link, "-m32");\
     }\
     tttarg = mtime(link.p[2]);\
    
  3. install 関数内のCライブラリまたはツールのコンパイル処理において、compile ベクタに gccargs をコピーした後、明示的に -c フラグが追加されるようになりました。

    --- a/src/cmd/dist/build.c
    +++ b/src/cmd/dist/build.c
    @@ -750,6 +756,7 @@ install(char *dir)\
     	if(!isgo) {\
     		// C library or tool.\
     		vcopy(&compile, gccargs.p, gccargs.len);\
    +		vadd(&compile, "-c");\
     		if(streq(gohostarch, "amd64"))\
     			vadd(&compile, "-m64");\
     		else if(streq(gohostarch, "386"))\
    

コアとなるコードの解説

proto_gccargs から -c の削除

proto_gccargs は、GCCに渡されるデフォルトの引数を定義しています。以前はここに -c (コンパイルのみを行うフラグ) が含まれていました。しかし、-c はコンパイル時にのみ必要なフラグであり、リンク時には不要です。この変更により、gccargs (最終的に proto_gccargs から初期化される) は、コンパイルとリンクの両方に共通して適用されるべきオプションのみを含むように整理されました。これにより、gccargs をリンクコマンドにコピーする際に、不要な -c フラグが渡されるのを防ぎます。

Cコマンドのリンク処理の変更

    } else {
    	// C command.
    	// Use gccargs, but ensure that link.p[2] is output file,
    	// as noted above.
    	vadd(&link, gccargs.p[0]); // gccコマンド自体を追加
    	vadd(&link, "-o"); // 出力ファイル指定フラグ
    	vadd(&link, bpathf(&b, "%s/bin/tool/%s%s", goroot, name, exe)); // 出力ファイルパス
    	vcopy(&link, gccargs.p+1, gccargs.len-1); // gccargsの残りのオプションをコピー
    	if(streq(gohostarch, "amd64"))
    		vadd(&link, "-m64"); // amd64の場合、-m64を追加
    	else if(streq(gohostarch, "386"))
    		vadd(&link, "-m32"); // 386の場合、-m32を追加
    }

このブロックは、C言語で書かれたツール(例: go_bootstrap 以外のCコマンド)をリンクする際のロジックです。

  • 以前は単に vadd(&link, "gcc"); となっていましたが、gccargs.p[0] を使用することで、gccargs に設定されたコンパイラパス(例えば、特定のバージョンのGCCへのパス)を確実に使用するように変更されました。
  • vcopy(&link, gccargs.p+1, gccargs.len-1); は、gccargs に含まれる -fno-common, -ggdb, -O2 などの共通オプションをリンクコマンドにコピーします。これにより、コンパイル時とリンク時で一貫した最適化レベルやデバッグ情報が適用されるようになります。
  • 最も重要な変更は、gohostarch(ビルドを実行しているホストのアーキテクチャ)に基づいて、-m64 または -m32 フラグが明示的に link ベクタに追加されるようになった点です。これにより、リンクされるオブジェクトファイルとリンカが期待するアーキテクチャが確実に一致し、クロスコンパイルや特定の環境でのビルドエラーが解消されます。

Cライブラリまたはツールのコンパイル処理の変更

    	if(!isgo) {
    		// C library or tool.
    		vcopy(&compile, gccargs.p, gccargs.len); // gccargsの全オプションをコピー
    		vadd(&compile, "-c"); // コンパイル時のみ-cを追加
    		if(streq(gohostarch, "amd64"))
    			vadd(&compile, "-m64");
    		else if(streq(gohostarch, "386"))
    			vadd(&compile, "-m32");
    	}

このブロックは、C言語で書かれたライブラリやツールをコンパイルする際のロジックです。

  • vcopy(&compile, gccargs.p, gccargs.len); は、gccargs に含まれる共通オプションをコンパイルコマンドにコピーします。
  • vadd(&compile, "-c"); は、proto_gccargs から削除された -c フラグを、コンパイル時(オブジェクトファイルを生成する際)にのみ明示的に追加するように変更されました。これにより、-c フラグが適切なフェーズでのみ適用されることが保証されます。
  • コンパイル時にも gohostarch に基づいて -m64 または -m32 フラグが追加されるロジックは以前から存在していましたが、このコミットで -c フラグの追加位置が調整されたことで、より論理的なコードフローになりました。

これらの変更により、GoのブートストラップビルドプロセスにおけるC言語コンポーネントのコンパイルとリンクが、ターゲットアーキテクチャに対してより堅牢かつ正確に行われるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語のソースコード (特に src/cmd/dist/build.c の変更前後の比較)
  • GCCのドキュメント (-m32, -m64, -c フラグに関する情報)
  • コンパイルとリンクの一般的な概念に関する知識
  • Go言語のブートストラッププロセスに関する一般的な知識
  • Gitのコミットと差分表示の理解