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

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

このコミットは、Go言語のビルドシステムにおける GOROOT_FINAL の取り扱いに関する問題を修正するものです。具体的には、GoのソースコードからGoツールチェインをビルドする際に使用される cmd/dist ツールが、GOROOT および GOROOT_FINAL 環境変数を正しく解釈し、適用するように改善されています。これにより、Goのインストールパスが期待通りに設定され、ビルドされたGoバイナリが正しいランタイム環境を参照できるようになります。

コミット

commit 54f1e1b1634cc0292fa8a1ecaf2569caafb257bf
Author: Gustavo Niemeyer <gustavo@niemeyer.net>
Date:   Thu Feb 9 20:47:12 2012 -0200

    cmd/dist: fix GOROOT_FINAL
    
    R=rsc, gustavo
    CC=golang-dev
    https://golang.org/cl/5642045

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

https://github.com/golang/go/commit/54f1e1b1634cc0292fa8a1ecaf2569caafb257bf

元コミット内容

cmd/dist: fix GOROOT_FINAL

このコミットは、Goのビルドプロセスで使用される cmd/dist ツールにおける GOROOT_FINAL の問題を修正します。

変更の背景

Go言語のビルドシステムは、ソースコードからGoツールチェイン自体を構築する際に、いくつかの重要な環境変数を扱います。その中でも GOROOT はGoのインストールディレクトリを指し、GOROOT_FINAL は最終的にGoがインストールされるパスを示すために使用されます。

このコミットが行われた2012年当時、Goのビルドプロセスは現在よりも複雑で、特にブートストラップ(Go自身をビルドするために一時的に古いGoコンパイラを使用するプロセス)と最終的なインストールパスの決定において、GOROOTGOROOT_FINAL の間の連携に問題がありました。

具体的には、cmd/dist ツールが GOROOT_FINAL を適切に処理せず、結果としてビルドされたGoバイナリが、最終的なインストール場所ではなく、ビルド時の一時的な GOROOT を参照してしまう可能性がありました。これは、Goのツールチェインが正しく動作しない、あるいは異なる環境にデプロイされた際に問題を引き起こす原因となります。

この問題は、GoのIssue 5642045 (https://golang.org/cl/5642045) で議論され、Gustavo NiemeyerとRuss Coxの間で解決策が検討されました。当初、Gustavoは DEFAULT_ROOTGOROOT_FINAL の概念を統一することを提案しましたが、Russは dist がコンパイル時に渡される DEFAULT_GOROOT マクロを使用し、make.bash および make.bat が環境変数ロジックを処理するべきだと主張しました。最終的に、このコミットは GOROOT_FINAL の扱いを改善し、特に GOROOT が設定されていない場合や、異なる環境にデプロイされるシナリオでの堅牢性を高めることを目的としています。

前提知識の解説

  • Go言語のビルドシステム: Go言語は、自身のコンパイラやツールチェインをGo言語自身で記述しています。そのため、GoのソースコードからGoの実行環境を構築する際には、ブートストラップと呼ばれる特殊なビルドプロセスが必要です。これは、既存のGoコンパイラ(またはCコンパイラ)を使用して、新しいGoコンパイラをビルドし、その新しいコンパイラでGoの標準ライブラリなどをビルドするという多段階のプロセスです。
  • GOROOT: Goのインストールディレクトリ、またはGoのソースコードが置かれているディレクトリを指す環境変数です。Goのツールチェイン(go コマンド、コンパイラ、リンカなど)は、この GOROOT を基準に動作します。
  • GOROOT_FINAL: Goのビルドプロセスにおいて、最終的にGoがインストールされるパスを示すために使用される概念です。特に、ビルド環境と実行環境が異なる場合(例:コンテナ内でビルドし、別の環境にデプロイする場合)に重要になります。GOROOT がビルド時のパスを指すのに対し、GOROOT_FINAL はビルドされたバイナリが参照すべき最終的なパスを指します。
  • cmd/dist: GoのソースコードからGoツールチェインをビルドするための主要なツールです。このツールは、コンパイラ、リンカ、標準ライブラリなどのビルドをオーケストレーションします。
  • make.bash / make.bat: Goのビルドプロセスを開始するためのシェルスクリプト(Linux/macOS用)およびバッチファイル(Windows用)です。これらは cmd/dist を呼び出し、ビルドに必要な環境変数を設定します。
  • C言語のプリプロセッサマクロ (-D): C言語のコンパイル時に、-D オプションを使ってマクロを定義できます。これにより、ソースコード内の特定のマクロがコンパイル時に指定された値に置き換えられます。このコミットでは、cmd/dist のコンパイル時に GOROOT_FINAL の値をマクロとして渡すことで、ビルドされた dist ツールが正しい最終パスを認識するようにしています。

技術的詳細

このコミットの核心は、Goのビルドプロセスにおける GOROOTGOROOT_FINAL の役割を明確にし、cmd/dist ツールが最終的なインストールパスを正しく埋め込むようにすることです。

以前の cmd/dist/build.c では、goroot 変数が DEFAULT_GOROOT マクロ(これは make.bashmake.bat で定義される)から初期化され、GOROOT_FINALgoroot と同じ値を持つか、環境変数 GOROOT_FINAL が設定されていればその値を使用していました。このアプローチでは、GOROOT が環境変数で明示的に設定されていない場合に、DEFAULT_GOROOT が使用され、その値が goroot_final にも伝播するという問題がありました。

このコミットでは、以下の変更が加えられています。

  1. GOROOT_FINAL の一元化: src/cmd/dist/a.h から default_goroot の宣言が削除され、src/cmd/dist/build.c では gorootgoroot_final の両方が GOROOT_FINAL マクロで初期化されるようになりました。これにより、cmd/dist がビルドされる時点で、最終的な GOROOT のパスがコンパイル時に埋め込まれるようになります。
  2. GOROOT 環境変数の優先: src/cmd/dist/build.cinit 関数内で、環境変数 GOROOT が設定されている場合は、その値が goroot 変数に優先的に設定されるようになりました。これにより、ビルド時に一時的な GOROOT を指定する柔軟性が維持されます。
  3. GOROOT_FINAL の伝播: src/cmd/dist/build.cinstall 関数において、Goのソースファイル(特に goos.c のようなプラットフォーム固有のファイル)をコンパイルする際に、GOROOT の値として goroot_final が使用されるようになりました。これにより、ビルドされたGoバイナリ(例えば go コマンドやランタイム)が、自身の内部で参照する GOROOT のパスとして、最終的なインストールパスを正しく持つようになります。
  4. buildruntime.c の修正: src/cmd/dist/buildruntime.c で生成される zversion.go ファイル(Goランタイムのバージョン情報を含むファイル)において、defaultGoroot 定数に goroot_final の値が使用されるようになりました。これは、Goランタイムが自身の GOROOT を決定する際に、最終的なインストールパスを参照するようにするためです。
  5. make.bash / make.bat の変更:
    • src/make.bash では、GOROOT 環境変数が現在のディレクトリの親ディレクトリに設定され、GOROOT_FINAL が設定されていない場合は GOROOT の値が使用されるようになりました。そして、この GOROOT_FINAL の値が DEFGOROOT マクロとして cmd/dist のコンパイル時に渡されます。
    • src/make.bat でも同様に、GOROOT が設定され、GOROOT_FINAL が設定されていない場合は GOROOT の値が使用されます。そして、GOROOT_FINAL の値が DEFGOROOT マクロとして cmd/dist のコンパイル時に渡されます。特に、Windowsのパスにおけるバックスラッシュのエスケープ処理が改善されています。

これらの変更により、Goのビルドプロセスは、ビルド時の一時的な GOROOT と、最終的なインストールパスである GOROOT_FINAL を明確に区別し、ビルドされたGoバイナリが常に正しい最終インストールパスを内部的に参照するようになります。これは、Goの配布とデプロイの堅牢性を高める上で非常に重要です。

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

このコミットでは、以下の5つのファイルが変更されています。

  1. src/cmd/dist/a.h: ヘッダーファイル。default_goroot の宣言が削除され、goroot_final の宣言が追加されました。
  2. src/cmd/dist/build.c: cmd/dist の主要なビルドロジック。gorootgoroot_final の初期化方法、および GOROOT 環境変数の処理、Goソースファイルのコンパイル時の GOROOT の埋め込み方法が変更されました。
  3. src/cmd/dist/buildruntime.c: Goランタイムのバージョン情報を生成するロジック。defaultGoroot 定数に goroot_final が使用されるようになりました。
  4. src/make.bash: Linux/macOS向けのビルドスクリプト。GOROOTGOROOT_FINAL の設定ロジック、および cmd/dist へのマクロ渡し方が変更されました。
  5. src/make.bat: Windows向けのビルドスクリプト。GOROOTGOROOT_FINAL の設定ロジック、および cmd/dist へのマクロ渡し方が変更されました。

コアとなるコードの解説

src/cmd/dist/a.h

--- a/src/cmd/dist/a.h
+++ b/src/cmd/dist/a.h
@@ -62,7 +62,6 @@ void	splitlines(Vec*, char*);
 void	splitfields(Vec*, char*);
 
 // build.c
-extern char *default_goroot;
 extern char *goarch;
 extern char *gobin;
 extern char *gochar;
@@ -70,6 +69,7 @@ extern char *gohostarch;
 extern char *gohostos;
 extern char *goos;
 extern char *goroot;
+extern char *goroot_final;
 extern char *goversion;
 extern char *workdir;
 extern char *slash;	// / for unix, \ for windows

default_goroot の宣言が削除され、goroot_finalbuild.c で外部変数として利用可能になるように宣言が追加されました。これは、default_goroot の概念が GOROOT_FINAL に統合されたことを示しています。

src/cmd/dist/build.c

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -15,13 +15,12 @@ char *gobin;
 char *gohostarch;
 char *gohostos;
 char *goos;
-char *goroot;
+char *goroot = GOROOT_FINAL;
+char *goroot_final = GOROOT_FINAL;
 char *workdir;
 char *gochar;
-char *goroot_final;
 char *goversion;
 char *slash;	// / for unix, \ for windows
-char *default_goroot = DEFAULT_GOROOT;
 
 static bool shouldbuild(char*, char*);
 static void copy(char*, char*);
@@ -74,12 +73,8 @@ init(void)\n 	binit(&b);\n \n 	xgetenv(&b, "GOROOT");
-	if(b.len == 0) {
-		if(default_goroot == nil)
-			fatal("$GOROOT not set and not available");
-		writestr(&b, default_goroot);
-	}
-	goroot = btake(&b);
+	if(b.len > 0)
+		goroot = btake(&b);
 
 	xgetenv(&b, "GOBIN");
 	if(b.len == 0)
@@ -116,12 +111,6 @@ init(void)\n 	bprintf(&b, "%c", gochars[i]);
 	gochar = btake(&b);
 
-	xgetenv(&b, "GOROOT_FINAL");
-	if(b.len > 0)
-		goroot_final = btake(&b);
-	else
-		goroot_final = goroot;
-	
 	xsetenv("GOROOT", goroot);
 	xsetenv("GOARCH", goarch);
 	xsetenv("GOOS", goos);
@@ -777,7 +766,7 @@ install(char *dir)\n 			if(streq(name, "goos.c")) {
 				vadd(&compile, bprintf(&b, "-DGOOS=\"%s\"", goos));
 				vadd(&compile, bprintf(&b, "-DGOARCH=\"%s\"", goarch));
-				bprintf(&b1, "%s", goroot);
+				bprintf(&b1, "%s", goroot_final);
 				bsubst(&b1, "\\", "\\\\");  // turn into C string
 				vadd(&compile, bprintf(&b, "-DGOROOT=\"%s\"", bstr(&b1)));
 				vadd(&compile, bprintf(&b, "-DGOVERSION=\"%s\"", goversion));
  • gorootgoroot_final が、コンパイル時にマクロとして渡される GOROOT_FINAL で直接初期化されるようになりました。これにより、cmd/dist がビルドされる時点で、最終的な GOROOT のパスが埋め込まれます。
  • init() 関数内で、環境変数 GOROOT が設定されている場合のみ、その値が goroot に設定されるようになりました。これにより、環境変数 GOROOT が優先される動作が明確になります。
  • GOROOT_FINAL を環境変数から取得するロジックが削除されました。これは、GOROOT_FINAL がコンパイル時にマクロとして渡されるようになったためです。
  • install() 関数内で、Goのソースファイル(例: goos.c)をコンパイルする際に、GOROOT の値として goroot_final が使用されるようになりました。これは、ビルドされたGoバイナリが最終的なインストールパスを内部的に参照するようにするためです。

src/cmd/dist/buildruntime.c

--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -29,7 +29,7 @@ mkzversion(char *dir, char *file)\n 		"package runtime\n"\n 		"\n"\n 		"const defaultGoroot = `%s`\n"\n-		"const theVersion = `%s`\n", goroot, goversion));
+		"const theVersion = `%s`\n", goroot_final, goversion));
 
 	writefile(&out, file);
 	

mkzversion 関数で生成される zversion.go ファイル内の defaultGoroot 定数に、goroot の代わりに goroot_final が使用されるようになりました。これにより、Goランタイムが自身の GOROOT を決定する際に、最終的なインストールパスを参照するようになります。

src/make.bash

--- a/src/make.bash
+++ b/src/make.bash
@@ -47,7 +47,9 @@ done
 
 echo '# Building C bootstrap tool.'
 mkdir -p ../bin/tool
-DEFGOROOT='-DDEFAULT_GOROOT="'"$(cd .. && pwd)"'"'
+export GOROOT="$(cd .. && pwd)"
+GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}"
+DEFGOROOT='-DGOROOT_FINAL="'"$(cd .. && pwd)"'"'
 gcc -O2 -Wall -Werror -o ../bin/tool/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
 echo
 
  • export GOROOT="$(cd .. && pwd)" で、現在のディレクトリの親ディレクトリを GOROOT として設定しています。
  • GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}" で、GOROOT_FINAL が設定されていない場合は GOROOT の値を使用するようにしています。
  • DEFGOROOT='-DGOROOT_FINAL="'"$(cd .. && pwd)"'"' で、cmd/dist をコンパイルする際に、現在のディレクトリの親ディレクトリ(つまり GOROOT)を GOROOT_FINAL マクロとして渡しています。これにより、cmd/dist はビルド時に最終的なインストールパスを認識します。

src/make.bat

--- a/src/make.bat
+++ b/src/make.bat
@@ -10,14 +10,16 @@ echo Must run make.bat from Go src directory.
 goto fail 
 :ok
 
-:: Grab default $GOROOT, escape \ for C string.
-:: The expression %CD:\=\\% means to take %CD%\n :: and apply the substitution \ = \\, escaping the\n :: backslashes.  Then we wrap that in quotes to create\n :: a C string.\n cd ..
-set DEFGOROOT=-DDEFAULT_GOROOT="\"%CD:\=\\%\""
+:: Grab default GOROOT_FINAL and set GOROOT for build.
+:: The expression %VAR:\=\\% means to take %VAR%\n :: and apply the substitution \ = \\, escaping the\n :: backslashes.  Then we wrap that in quotes to create\n :: a C string.\n cd ..
+set GOROOT="%CD%"
 cd src
+if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL="%GOROOT%"
+set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\""
 
 echo # Building C bootstrap tool.
 if not exist ..\bin\tool mkdir ..\bin\tool
@@ -40,7 +42,7 @@ if errorlevel 1 goto fail
 del ..\bin\tool\go_bootstrap.exe
 echo .
 
-if x%1==x--no-banner goto nobanner
+if "x%1"=="x--no-banner" goto nobanner
 ..\bin\tool\dist banner
 :nobanner
 
  • set GOROOT="%CD%" で、現在のディレクトリを GOROOT として設定しています。
  • if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL="%GOROOT%" で、GOROOT_FINAL が設定されていない場合は GOROOT の値を使用するようにしています。
  • set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\"" で、cmd/dist をコンパイルする際に、GOROOT_FINAL の値をマクロとして渡しています。Windowsのパスにおけるバックスラッシュのエスケープ処理 (:\=\\) が適用されています。
  • if "x%1"=="x--no-banner" goto nobanner のように、文字列比較の構文が修正されています。

これらの変更は、Goのビルドシステムが GOROOTGOROOT_FINAL をより堅牢かつ正確に扱うための重要なステップであり、Goの配布とデプロイの信頼性を向上させました。

関連リンク

参考にした情報源リンク

  • Go Code Review 5642045 (https://golang.org/cl/5642045) - このコミットの背景、議論、および具体的な変更内容に関する主要な情報源。```markdown

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

このコミットは、Go言語のビルドシステムにおける GOROOT_FINAL の取り扱いに関する問題を修正するものです。具体的には、GoのソースコードからGoツールチェインをビルドする際に使用される cmd/dist ツールが、GOROOT および GOROOT_FINAL 環境変数を正しく解釈し、適用するように改善されています。これにより、Goのインストールパスが期待通りに設定され、ビルドされたGoバイナリが正しいランタイム環境を参照できるようになります。

コミット

commit 54f1e1b1634cc0292fa8a1ecaf2569caafb257bf
Author: Gustavo Niemeyer <gustavo@niemeyer.net>
Date:   Thu Feb 9 20:47:12 2012 -0200

    cmd/dist: fix GOROOT_FINAL
    
    R=rsc, gustavo
    CC=golang-dev
    https://golang.org/cl/5642045

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

https://github.com/golang/go/commit/54f1e1b1634cc0292fa8a1ecaf2569caafb257bf

元コミット内容

cmd/dist: fix GOROOT_FINAL

このコミットは、Goのビルドプロセスで使用される cmd/dist ツールにおける GOROOT_FINAL の問題を修正します。

変更の背景

Go言語のビルドシステムは、自身のコンパイラやツールチェインをGo言語自身で記述しており、ソースコードからGoの実行環境を構築する際には、ブートストラップと呼ばれる特殊なビルドプロセスが必要です。このプロセスにおいて、Goのインストールディレクトリを指す GOROOT と、最終的にGoがインストールされるパスを示す GOROOT_FINAL という二つの重要な概念が存在します。

このコミットが行われた2012年当時、Goのビルドプロセスは現在よりも複雑で、特にブートストラップと最終的なインストールパスの決定において、GOROOTGOROOT_FINAL の間の連携に問題がありました。

具体的には、GoのソースコードからGoツールチェインをビルドする際に使用される cmd/dist ツールが、GOROOT_FINAL を適切に処理せず、結果としてビルドされたGoバイナリが、最終的なインストール場所ではなく、ビルド時の一時的な GOROOT を参照してしまう可能性がありました。これは、Goのツールチェインが正しく動作しない、あるいは異なる環境にデプロイされた際に問題を引き起こす原因となります。例えば、Goを /usr/local/go にインストールすることを意図してビルドしても、ビルドされたバイナリが /tmp/go-build-xxxx のような一時ディレクトリを内部的に参照してしまうといった状況が考えられます。

この問題は、Goのコードレビューシステム (Go Code Review 5642045: https://golang.org/cl/5642045) で議論され、Gustavo NiemeyerとRuss Coxの間で解決策が検討されました。当初、Gustavoは DEFAULT_ROOTGOROOT_FINAL の概念を統一することを提案しましたが、Russは dist がコンパイル時に渡される DEFAULT_GOROOT マクロを使用し、make.bash および make.bat が環境変数ロジックを処理するべきだと主張しました。最終的に、このコミットは GOROOT_FINAL の扱いを改善し、特に GOROOT が設定されていない場合や、異なる環境にデプロイされるシナリオでの堅牢性を高めることを目的としています。

前提知識の解説

  • Go言語のビルドシステム: Go言語は、自身のコンパイラやツールチェインをGo言語自身で記述しています。そのため、GoのソースコードからGoの実行環境を構築する際には、ブートストラップと呼ばれる特殊なビルドプロセスが必要です。これは、既存のGoコンパイラ(またはCコンパイラ)を使用して、新しいGoコンパイラをビルドし、その新しいコンパイラでGoの標準ライブラリなどをビルドするという多段階のプロセスです。
  • GOROOT: Goのインストールディレクトリ、またはGoのソースコードが置かれているディレクトリを指す環境変数です。Goのツールチェイン(go コマンド、コンパイラ、リンカなど)は、この GOROOT を基準に動作します。開発者がGoのソースコードを特定の場所にクローンし、そこからビルドを行う場合、この GOROOT がビルド時のベースパスとなります。
  • GOROOT_FINAL: Goのビルドプロセスにおいて、最終的にGoがインストールされるパスを示すために使用される概念です。特に、ビルド環境と実行環境が異なる場合(例:コンテナ内でビルドし、別の環境にデプロイする場合、またはシステム全体にGoをインストールする場合)に重要になります。GOROOT がビルド時のパスを指すのに対し、GOROOT_FINAL はビルドされたバイナリが参照すべき最終的なパスを指します。Goのバイナリは、自身のランタイムや標準ライブラリを見つけるために、内部に GOROOT のパスを埋め込んでいます。この埋め込まれるパスが GOROOT_FINAL になります。
  • cmd/dist: GoのソースコードからGoツールチェインをビルドするための主要なツールです。このツールは、コンパイラ、リンカ、標準ライブラリなどのビルドをオーケストレーションします。make.bashmake.bat から呼び出され、Goのビルドプロセス全体を管理します。
  • make.bash / make.bat: Goのビルドプロセスを開始するためのシェルスクリプト(Linux/macOS用)およびバッチファイル(Windows用)です。これらは cmd/dist を呼び出す前に、ビルドに必要な環境変数を設定したり、C言語のブートストラップコンパイラをビルドしたりします。
  • C言語のプリプロセッサマクロ (-D): C言語のコンパイル時に、-D オプションを使ってマクロを定義できます。これにより、ソースコード内の特定のマクロがコンパイル時に指定された値に置き換えられます。このコミットでは、cmd/dist のコンパイル時に GOROOT_FINAL の値をマクロとして渡すことで、ビルドされた dist ツールが正しい最終パスを認識するようにしています。

技術的詳細

このコミットの核心は、Goのビルドプロセスにおける GOROOTGOROOT_FINAL の役割を明確にし、cmd/dist ツールが最終的なインストールパスを正しく埋め込むようにすることです。

以前の cmd/dist/build.c では、goroot 変数が DEFAULT_GOROOT マクロ(これは make.bashmake.bat で定義される)から初期化され、GOROOT_FINALgoroot と同じ値を持つか、環境変数 GOROOT_FINAL が設定されていればその値を使用していました。このアプローチでは、GOROOT が環境変数で明示的に設定されていない場合に、DEFAULT_GOROOT が使用され、その値が goroot_final にも伝播するという問題がありました。これは、ビルド時の一時的なパスが最終的なインストールパスとして埋め込まれてしまう可能性を意味します。

このコミットでは、以下の変更が加えられています。

  1. GOROOT_FINAL の一元化とコンパイル時埋め込み:
    • src/cmd/dist/a.h から default_goroot の宣言が削除されました。これは、default_goroot という概念が GOROOT_FINAL に統合されたことを示します。
    • src/cmd/dist/build.c では、gorootgoroot_final の両方が、コンパイル時にCプリプロセッサマクロとして渡される GOROOT_FINAL の値で直接初期化されるようになりました。これにより、cmd/dist がビルドされる時点で、最終的な GOROOT のパスがコンパイル時に埋め込まれ、実行時に動的に決定されるのではなく、静的に決定されるようになります。
  2. GOROOT 環境変数の優先:
    • src/cmd/dist/build.cinit 関数内で、環境変数 GOROOT が設定されている場合は、その値が goroot 変数に優先的に設定されるようになりました。これにより、開発者がビルド時に一時的な GOROOT を指定する柔軟性が維持されます。例えば、特定のGoのバージョンをテストするために、一時的なビルドディレクトリを指定したい場合に有用です。
    • 以前の default_goroot を使用して GOROOT を設定するロジックは削除されました。
  3. GOROOT_FINAL のGoバイナリへの伝播:
    • src/cmd/dist/build.cinstall 関数において、Goのソースファイル(特に goos.c のようなプラットフォーム固有のファイル)をコンパイルする際に、GOROOT の値として goroot_final がCプリプロセッサマクロ (-DGOROOT="...") として使用されるようになりました。これにより、ビルドされたGoバイナリ(例えば go コマンドやランタイム)が、自身の内部で参照する GOROOT のパスとして、最終的なインストールパスを正しく持つようになります。これは、Goのバイナリが自身の標準ライブラリやツールを見つけるために非常に重要です。
  4. Goランタイムの defaultGoroot 定数への反映:
    • src/cmd/dist/buildruntime.c で生成される zversion.go ファイル(Goランタイムのバージョン情報を含むファイル)において、const defaultGoroot 定数に goroot_final の値が使用されるようになりました。これは、Goランタイムが自身の GOROOT を決定する際に、最終的なインストールパスを参照するようにするためです。
  5. make.bash / make.bat の変更:
    • これらのスクリプトは、cmd/dist をビルドする前に、GOROOT 環境変数を設定し、GOROOT_FINAL が設定されていない場合は GOROOT の値を使用するように変更されました。
    • 最も重要な変更は、cmd/dist をコンパイルする際に、GOROOT_FINAL の値をCプリプロセッサマクロ (-DGOROOT_FINAL="...") として渡すようになった点です。これにより、cmd/dist はビルド時に最終的なインストールパスを静的に認識し、その情報をGoバイナリに埋め込むことができます。
    • src/make.bat では、Windowsのパスにおけるバックスラッシュのエスケープ処理 (%VAR:\=\\%) が改善され、パスにスペースが含まれる場合でも正しく処理されるようになりました。また、文字列比較の構文も修正されています。

これらの変更により、Goのビルドプロセスは、ビルド時の一時的な GOROOT と、最終的なインストールパスである GOROOT_FINAL を明確に区別し、ビルドされたGoバイナリが常に正しい最終インストールパスを内部的に参照するようになります。これは、Goの配布とデプロイの堅牢性を高める上で非常に重要であり、特にGoをシステム全体にインストールしたり、コンテナイメージとして配布したりするシナリオにおいて、Goツールチェインが期待通りに動作することを保証します。

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

このコミットでは、以下の5つのファイルが変更されています。

  1. src/cmd/dist/a.h: ヘッダーファイル。default_goroot の宣言が削除され、goroot_final の宣言が追加されました。
  2. src/cmd/dist/build.c: cmd/dist の主要なビルドロジック。gorootgoroot_final の初期化方法、および GOROOT 環境変数の処理、Goソースファイルのコンパイル時の GOROOT の埋め込み方法が変更されました。
  3. src/cmd/dist/buildruntime.c: Goランタイムのバージョン情報を生成するロジック。defaultGoroot 定数に goroot_final が使用されるようになりました。
  4. src/make.bash: Linux/macOS向けのビルドスクリプト。GOROOTGOROOT_FINAL の設定ロジック、および cmd/dist へのマクロ渡し方が変更されました。
  5. src/make.bat: Windows向けのビルドスクリプト。GOROOTGOROOT_FINAL の設定ロジック、および cmd/dist へのマクロ渡し方が変更されました。

コアとなるコードの解説

src/cmd/dist/a.h

--- a/src/cmd/dist/a.h
+++ b/src/cmd/dist/a.h
@@ -62,7 +62,6 @@ void	splitlines(Vec*, char*);
 void	splitfields(Vec*, char*);
 
 // build.c
-extern char *default_goroot;
 extern char *goarch;
 extern char *gobin;
 extern char *gochar;
@@ -70,6 +69,7 @@ extern char *gohostarch;
 extern char *gohostos;
 extern char *goos;
 extern char *goroot;
+extern char *goroot_final;
 extern char *goversion;
 extern char *workdir;
 extern char *slash;	// / for unix, \ for windows

default_goroot の宣言が削除され、goroot_finalbuild.c で外部変数として利用可能になるように宣言が追加されました。これは、default_goroot の概念が GOROOT_FINAL に統合され、cmd/dist が最終的なインストールパスを直接扱うようになったことを示しています。

src/cmd/dist/build.c

--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -15,13 +15,12 @@ char *gobin;
 char *gohostarch;
 char *gohostos;
 char *goos;
-char *goroot;
+char *goroot = GOROOT_FINAL;
+char *goroot_final = GOROOT_FINAL;
 char *workdir;
 char *gochar;
-char *goroot_final;
 char *goversion;
 char *slash;	// / for unix, \ for windows
-char *default_goroot = DEFAULT_GOROOT;
 
 static bool shouldbuild(char*, char*);
 static void copy(char*, char*);
@@ -74,12 +73,8 @@ init(void)\n 	binit(&b);\n \n 	xgetenv(&b, "GOROOT");
-	if(b.len == 0) {
-		if(default_goroot == nil)
-			fatal("$GOROOT not set and not available");
-		writestr(&b, default_goroot);
-	}
-	goroot = btake(&b);
+	if(b.len > 0)
+		goroot = btake(&b);
 
 	xgetenv(&b, "GOBIN");
 	if(b.len == 0)
@@ -116,12 +111,6 @@ init(void)\n 	bprintf(&b, "%c", gochars[i]);
 	gochar = btake(&b);
 
-	xgetenv(&b, "GOROOT_FINAL");
-	if(b.len > 0)
-		goroot_final = btake(&b);
-	else
-		goroot_final = goroot;
-	
 	xsetenv("GOROOT", goroot);
 	xsetenv("GOARCH", goarch);
 	xsetenv("GOOS", goos);
@@ -777,7 +766,7 @@ install(char *dir)\n 			if(streq(name, "goos.c")) {
 				vadd(&compile, bprintf(&b, "-DGOOS=\"%s\"", goos));
 				vadd(&compile, bprintf(&b, "-DGOARCH=\"%s\"", goarch));
-				bprintf(&b1, "%s", goroot);
+				bprintf(&b1, "%s", goroot_final);
 				bsubst(&b1, "\\", "\\\\");  // turn into C string
 				vadd(&compile, bprintf(&b, "-DGOROOT=\"%s\"", bstr(&b1)));
 				vadd(&compile, bprintf(&b, "-DGOVERSION=\"%s\"", goversion));
  • gorootgoroot_final が、コンパイル時にCプリプロセッサマクロとして渡される GOROOT_FINAL で直接初期化されるようになりました。これにより、cmd/dist がビルドされる時点で、最終的な GOROOT のパスが埋め込まれます。
  • init() 関数内で、環境変数 GOROOT が設定されている場合のみ、その値が goroot に設定されるようになりました。これにより、環境変数 GOROOT が優先される動作が明確になります。以前の default_goroot を使用して GOROOT を設定する複雑なロジックは削除されました。
  • GOROOT_FINAL を環境変数から取得するロジックが削除されました。これは、GOROOT_FINAL がコンパイル時にマクロとして渡されるようになったため、実行時に環境変数を参照する必要がなくなったためです。
  • install() 関数内で、Goのソースファイル(例: goos.c)をコンパイルする際に、GOROOT の値として goroot_final が使用されるようになりました。これは、ビルドされたGoバイナリが最終的なインストールパスを内部的に参照するようにするためです。

src/cmd/dist/buildruntime.c

--- a/src/cmd/dist/buildruntime.c
+++ b/src/cmd/dist/buildruntime.c
@@ -29,7 +29,7 @@ mkzversion(char *dir, char *file)\n 		"package runtime\n"\n 		"\n"\n 		"const defaultGoroot = `%s`\n"\n-		"const theVersion = `%s`\n", goroot, goversion));
+		"const theVersion = `%s`\n", goroot_final, goversion));
 
 	writefile(&out, file);
 	

mkzversion 関数で生成される zversion.go ファイル内の defaultGoroot 定数に、goroot の代わりに goroot_final が使用されるようになりました。これにより、Goランタイムが自身の GOROOT を決定する際に、最終的なインストールパスを参照するようになります。これは、Goのランタイムが標準ライブラリなどのリソースを正しく見つけるために重要です。

src/make.bash

--- a/src/make.bash
+++ b/src/make.bash
@@ -47,7 +47,9 @@ done
 
 echo '# Building C bootstrap tool.'
 mkdir -p ../bin/tool
-DEFGOROOT='-DDEFAULT_GOROOT="'"$(cd .. && pwd)"'"'
+export GOROOT="$(cd .. && pwd)"
+GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}"
+DEFGOROOT='-DGOROOT_FINAL="'"$(cd .. && pwd)"'"'
 gcc -O2 -Wall -Werror -o ../bin/tool/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
 echo
 
  • export GOROOT="$(cd .. && pwd)" で、現在のディレクトリの親ディレクトリ(Goのソースルート)を GOROOT として設定しています。これは、ビルド時のGoのソースツリーの場所を示します。
  • GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}" で、GOROOT_FINAL 環境変数が既に設定されていない場合は、GOROOT の値(現在のビルドディレクトリ)を GOROOT_FINAL として使用するようにしています。これにより、ユーザーが明示的に GOROOT_FINAL を指定しない限り、ビルドされたGoバイナリはビルド時のパスを最終パスとして埋め込みます。
  • DEFGOROOT='-DGOROOT_FINAL="'"$(cd .. && pwd)"'"' で、cmd/dist をコンパイルする際に、現在のディレクトリの親ディレクトリ(つまり GOROOT)を GOROOT_FINAL マクロとしてCコンパイラに渡しています。これにより、cmd/dist はビルド時に最終的なインストールパスを静的に認識し、その情報をGoバイナリに埋め込むことができます。

src/make.bat

--- a/src/make.bat
+++ b/src/make.bat
@@ -10,14 +10,16 @@ echo Must run make.bat from Go src directory.
 goto fail 
 :ok
 
-:: Grab default $GOROOT, escape \ for C string.
-:: The expression %CD:\=\\% means to take %CD%\n :: and apply the substitution \ = \\, escaping the\n :: backslashes.  Then we wrap that in quotes to create\n :: a C string.\n cd ..
-set DEFGOROOT=-DDEFAULT_GOROOT="\"%CD:\=\\%\""
+:: Grab default GOROOT_FINAL and set GOROOT for build.
+:: The expression %VAR:\=\\% means to take %VAR%\n :: and apply the substitution \ = \\, escaping the\n :: backslashes.  Then we wrap that in quotes to create\n :: a C string.\n cd ..
+set GOROOT="%CD%"
 cd src
+if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL="%GOROOT%"
+set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\""
 
 echo # Building C bootstrap tool.
 if not exist ..\bin\tool mkdir ..\bin\tool
@@ -40,7 +42,7 @@ if errorlevel 1 goto fail
 del ..\bin\tool\go_bootstrap.exe
 echo .
 
-if x%1==x--no-banner goto nobanner
+if "x%1"=="x--no-banner" goto nobanner
 ..\bin\tool\dist banner
 :nobanner
 
  • set GOROOT="%CD%" で、現在のディレクトリ(Goのソースルート)を GOROOT として設定しています。
  • if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL="%GOROOT%" で、GOROOT_FINAL が設定されていない場合は GOROOT の値を使用するようにしています。これは make.bash と同様のロジックです。
  • set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\"" で、cmd/dist をコンパイルする際に、GOROOT_FINAL の値をマクロとして渡しています。Windowsのパスにおけるバックスラッシュのエスケープ処理 (:\=\\) が改善され、パスにスペースが含まれる場合でも正しく処理されるようになりました。
  • if "x%1"=="x--no-banner" goto nobanner のように、バッチファイルにおける文字列比較の構文が修正されています。

これらの変更は、Goのビルドシステムが GOROOTGOROOT_FINAL をより堅牢かつ正確に扱うための重要なステップであり、Goの配布とデプロイの信頼性を向上させました。特に、ビルド環境と実行環境が異なるシナリオでのGoツールチェインの動作の安定性に寄与しています。

関連リンク

参考にした情報源リンク

  • Go Code Review 5642045 (https://golang.org/cl/5642045) - このコミットの背景、議論、および具体的な変更内容に関する主要な情報源。