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

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

このコミットは、Go言語のビルドシステムにおいて、make.bashスクリプトに--no-cleanオプションを追加する変更です。これにより、異なるアーキテクチャ向けにGoをビルドする際に、以前のビルドで生成されたファイルを削除せずに済むようになり、ビルドプロセスの効率が向上します。

コミット

commit 2506fd43d463b5fe5e5c89982a6fea4a1602908b
Author: Russ Cox <rsc@golang.org>
Date:   Wed Feb 15 11:48:17 2012 -0500

    build: add make.bash --no-clean option
    
    Makes it possible to run
    
    GOARCH=amd64 make.bash
    GOARCH=386 make.bash --no-clean
    
    to avoid deleting some of the work done by the first one.
    
    R=golang-dev
    CC=golang-dev
    https://golang.org/cl/5673056

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

https://github.com/golang/go/commit/2506fd43d463b5fe5e5c89982a6fea4a1602908b

元コミット内容

このコミットは、Go言語のビルドシステムにmake.bash --no-cleanオプションを追加します。このオプションは、make.bashを複数回実行する際に、以前のビルドで生成された中間ファイルや成果物を削除しないようにするために導入されました。具体的には、異なるGOARCH(ターゲットアーキテクチャ)でmake.bashを連続して実行する際に、最初のビルドで生成された共通のビルド成果物が削除されるのを防ぎ、2回目以降のビルド時間を短縮することを目的としています。

変更の背景

Go言語のビルドプロセスでは、通常、make.bashスクリプトが実行されると、ビルドディレクトリがクリーンアップされ、既存のビルド成果物が削除されます。これは、クリーンな状態からビルドを開始し、予期せぬ問題を避けるための一般的なプラクティスです。

しかし、開発者が複数のアーキテクチャ(例: amd64386)向けにGoをビルドしたい場合、現状のビルドシステムでは、最初のmake.bash実行後に生成された共通のビルド成果物(例えば、ホストアーキテクチャ用のコンパイラやツール)が、2回目のmake.bash実行時に削除されてしまいます。これにより、2回目のビルドでも最初から全てのコンポーネントを再ビルドする必要があり、ビルド時間が無駄に長くなるという問題がありました。

このコミットは、この非効率性を解消するために、--no-cleanオプションを導入しました。このオプションを使用することで、開発者は特定のビルドステップでクリーンアップをスキップし、以前のビルドの成果物を再利用できるようになります。これにより、特にクロスコンパイル環境での開発効率が向上します。

前提知識の解説

このコミットを理解するためには、Go言語のビルドシステムと関連する概念について理解しておく必要があります。

  • make.bash: Go言語のソースコードからGoツールチェイン全体をビルドするための主要なシェルスクリプトです。Unix系システムでGoをソースからビルドする際に使用されます。このスクリプトは、コンパイラ、リンカ、標準ライブラリ、およびその他のGoツールを構築します。
  • src/cmd/dist/dist: Goのビルドシステムの中核をなすツールです。make.bashから呼び出され、Goのブートストラップビルド、パッケージのインストール、テストの実行など、様々なビルド関連のタスクを管理します。distツールは、Goのソースツリー内の様々なコンポーネントを調整し、正しい順序でビルドされるようにします。
  • ブートストラップビルド (Bootstrap Build): Go言語のコンパイラ自体がGoで書かれているため、Goのビルドプロセスは「ブートストラップ」と呼ばれる特殊な手順を必要とします。これは、まず既存のGoコンパイラ(またはC言語で書かれた初期のコンパイラ)を使用して、Goのソースコードから最初のGoコンパイラをビルドし、次にその新しくビルドされたコンパイラを使用して、Goツールチェインの残りの部分をビルドするというプロセスです。dist bootstrapコマンドがこのプロセスを開始します。
  • GOARCH: GoプログラムをビルドするターゲットのCPUアーキテクチャを指定する環境変数です(例: amd64, 386, arm)。
  • GOHOSTOS / GOHOSTARCH: Goツールチェイン自体が動作するホストシステムのOSとCPUアーキテクチャを指定する環境変数です。Goのビルドプロセスでは、まずホストシステム上で動作するツールチェイン(コンパイラなど)をビルドし、次にそのツールチェインを使ってターゲットアーキテクチャ用のGoプログラムやライブラリをビルドします。
  • xremoveall(path): Goのビルドシステム内で使用されるユーティリティ関数で、指定されたパスのディレクトリとその内容を再帰的に削除します。これは、クリーンなビルド環境を確保するためによく使用されます。
  • xmkdir(path) / xmkdirall(path): xmkdirは単一のディレクトリを作成し、xmkdirallは指定されたパスの全ての親ディレクトリを含めて再帰的にディレクトリを作成します。ビルドプロセス中に必要なディレクトリ構造を準備するために使用されます。
  • rebuildall: Goのビルドシステム内で使用される内部フラグで、全てのビルド成果物を最初から再構築する必要があるかどうかを示します。通常、dist bootstrap -aのように-a(all)オプションが指定された場合にtrueになります。

技術的詳細

このコミットの技術的な核心は、Goのビルドプロセスにおける「クリーンアップ」の挙動を制御することにあります。

変更は主に2つのファイルにわたります。

  1. src/cmd/dist/build.c:

    • このC言語のファイルは、Goのビルドシステムの中核であるdistツールのセットアップロジックを含んでいます。
    • 以前は、setup()関数内でpkgディレクトリ(ビルドされたパッケージが格納される場所)やtoolディレクトリ(ビルドツールが格納される場所)を作成する際に、無条件にxremoveall()を呼び出して既存のディレクトリを削除していました。
    • この変更により、xremoveall()の呼び出しがrebuildallフラグの条件付きになりました。つまり、rebuildalltrueの場合(通常、dist bootstrap -aのように-aオプションが指定された場合)にのみ、これらのディレクトリが削除されるようになりました。
    • また、xmkdirxmkdirallに変更されている箇所があります。これは、単一のディレクトリ作成から、必要に応じて親ディレクトリも作成する、より堅牢なディレクトリ作成に切り替わったことを示しています。
    • cmdbootstrap関数内でも、以前は無条件にclean()関数(ビルドディレクトリをクリーンアップする関数)が呼び出されていましたが、これもrebuildallフラグの条件付きになりました。
  2. src/make.bash:

    • このシェルスクリプトは、distツールを呼び出してGoのビルドプロセスをオーケストレーションします。
    • 新しい--no-cleanオプションの処理が追加されました。スクリプトは、最初の引数が--no-cleanであるかどうかをチェックします。
    • もし--no-cleanが指定された場合、dist bootstrapコマンドに渡されるbuildall変数が空文字列("")に設定されます。
    • --no-cleanが指定されない場合、buildallはデフォルトで-aに設定されます。
    • このbuildall変数が./cmd/dist/dist bootstrap $buildall -vという形でdist bootstrapコマンドに渡されます。
    • これにより、--no-cleanが指定された場合はdist bootstrap-aオプションが渡されなくなり、結果としてdistツール内部のrebuildallフラグがfalseになるため、クリーンアップ処理がスキップされるようになります。

これらの変更により、make.bash --no-cleanを実行すると、distツールがビルドディレクトリをクリーンアップせずにビルドを進めることが可能になります。これにより、異なるGOARCHで連続してビルドを行う際に、共通のビルド成果物を再利用し、ビルド時間を短縮できるという効果が得られます。

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

src/cmd/dist/build.c

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -314,12 +314,12 @@ setup(void)\
 	p = bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch);\
 	if(rebuildall)\
 		xremoveall(p);\
-	xmkdir(p);\
+	xmkdirall(p);\
 	if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) {\
 		p = bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch);\
 		if(rebuildall)\
 			xremoveall(p);\
-		xmkdir(p);\
+		xmkdirall(p);\
 	}\
 	\
 	// Create object directory.\
@@ -337,7 +337,8 @@ setup(void)\
 \n\
 	// Create tool directory.\
 	// We keep it in pkg/, just like the object directory above.\
-\txremoveall(tooldir);\
+\tif(rebuildall)\
+\t\txremoveall(tooldir);\
 \txmkdirall(tooldir);\
 \n\
 	// Remove tool binaries from before the tool/gohostos_gohostarch\
@@ -1330,7 +1331,8 @@ cmdbootstrap(int argc, char **argv)\
 	if(argc > 0)\
 		usage();\
 \n-\tclean();\
+\tif(rebuildall)\
+\t\tclean();\
 \tgoversion = findgoversion();\
 \tsetup();\
 \t

src/make.bash

--- a/src/make.bash
+++ b/src/make.bash
@@ -75,8 +75,12 @@ if [ "$1" = "--dist-tool" ]; then
 fi
 
 echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH."
-./cmd/dist/dist bootstrap -a -v # builds go_bootstrap
-# Delay move of dist tool to now, because bootstrap cleared tool directory.
+buildall="-a"
+if [ "$1" = "--no-clean" ]; then
+	buildall=""
+fi
+./cmd/dist/dist bootstrap $buildall -v # builds go_bootstrap
+# Delay move of dist tool to now, because bootstrap may clear tool directory.
 mv cmd/dist/dist $GOTOOLDIR/dist
 $GOTOOLDIR/go_bootstrap clean -i std
 echo

コアとなるコードの解説

src/cmd/dist/build.c の変更点

  1. setup() 関数内の pkg ディレクトリ作成ロジック:
    • 変更前: xremoveall(p); xmkdir(p);
    • 変更後: if(rebuildall) xremoveall(p); xmkdirall(p);
    • この変更により、pkgディレクトリ(ビルドされたGoパッケージが格納される場所)の削除がrebuildallフラグに依存するようになりました。rebuildalltrueの場合にのみ既存のディレクトリが削除されます。また、xmkdirxmkdirallに変更され、親ディレクトリが存在しない場合でも自動的に作成されるようになりました。これは、gohostos_gohostarch(ホストOS/アーキテクチャ)とgoos_goarch(ターゲットOS/アーキテクチャ)の両方のpkgディレクトリに適用されます。
  2. setup() 関数内の tool ディレクトリ作成ロジック:
    • 変更前: xremoveall(tooldir);
    • 変更後: if(rebuildall) xremoveall(tooldir);
    • toolディレクトリ(Goのビルドツールが格納される場所)の削除もrebuildallフラグに依存するようになりました。これにより、--no-cleanオプションが指定された場合に、このディレクトリが保持されるようになります。
  3. cmdbootstrap() 関数内の clean() 呼び出し:
    • 変更前: clean();
    • 変更後: if(rebuildall) clean();
    • ブートストラップビルドを開始するcmdbootstrap関数内で、ビルドディレクトリ全体をクリーンアップするclean()関数の呼び出しが、rebuildallフラグに依存するようになりました。これにより、--no-cleanオプションが指定された場合に、ビルド全体のクリーンアップがスキップされます。

これらの変更は、distツールがビルドディレクトリをクリーンアップするかどうかを、rebuildallフラグ(make.bashから渡される-aオプションによって設定される)に基づいて制御するようにします。

src/make.bash の変更点

  1. --no-clean オプションの処理:
    • 新しいif文が追加され、最初のコマンドライン引数($1)が--no-cleanであるかどうかがチェックされます。
    • buildallという変数が導入されました。デフォルトでは-adist bootstrapに渡される「全てをビルドする」オプション)に設定されます。
    • もし--no-cleanが指定された場合、buildallは空文字列("")に設定されます。
  2. dist bootstrap コマンドへの引数渡し:
    • 変更前: ./cmd/dist/dist bootstrap -a -v
    • 変更後: ./cmd/dist/dist bootstrap $buildall -v
    • これにより、--no-cleanが指定された場合はdist bootstrap-aオプションが渡されなくなります。結果として、distツール内部のrebuildallフラグがfalseになり、src/cmd/dist/build.cで説明した条件付きクリーンアップロジックが発動し、クリーンアップがスキップされます。

このmake.bashの変更は、ユーザーが--no-cleanオプションを通じてビルドのクリーンアップ挙動を直接制御できるようにするためのインターフェースを提供します。

関連リンク

参考にした情報源リンク