[インデックス 11947] ファイルの概要
このコミットは、Go言語のWindowsビルドプロセスにおいて、環境変数の変更がビルドスクリプトのローカルスコープに限定されるように修正するものです。具体的には、all.bat
とmake.bat
という2つのバッチスクリプトにsetlocal
とendlocal
コマンドを導入し、ビルド中に設定された環境変数が、スクリプトの実行終了後にシステム全体に影響を与えないようにしています。これにより、ビルドプロセスの独立性とクリーンさが保たれます。
コミット
commit 32cb495b185b50b08aea7fd9402ddf3152f1fda8
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Thu Feb 16 10:26:01 2012 +1100
build: keep environment variable changes local during Windows build
R=bradfitz, rsc
CC=golang-dev
https://golang.org/cl/5673048
---
src/all.bat | 7 +++----
src/make.bat | 15 ++++++++++-----
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/src/all.bat b/src/all.bat
index 7792cf1746..980f937efc 100644
--- a/src/all.bat
+++ b/src/all.bat
@@ -3,20 +3,19 @@
:: license that can be found in the LICENSE file.\n @echo off
\n+setlocal
+\n if exist make.bat goto ok
echo all.bat must be run from go\\src
:: cannot exit: would kill parent command interpreter
goto end
:ok
\n-set GOOLDPATH=%PATH%\n-\n-call make.bat --no-banner
+call make.bat --no-banner --no-local
if %GOBUILDFAIL%==1 goto end
call run.bat --no-rebuild
if %GOBUILDFAIL%==1 goto end
go tool dist banner
\n :end
-set PATH=%GOOLDPATH%\n if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%\ndiff --git a/src/make.bat b/src/make.bat
index 6618bc4ed9..e6921aa791 100644
--- a/src/make.bat
+++ b/src/make.bat
@@ -3,6 +3,13 @@
:: license that can be found in the LICENSE file.\n @echo off
\n+:: Keep environment variables within this script
+:: unless invoked with --no-local.
+if x%1==x--no-local goto nolocal
+if x%2==x--no-local goto nolocal
+setlocal
+:nolocal
+\n set GOBUILDFAIL=0
\n if exist make.bat goto ok
@@ -48,13 +55,11 @@ goto mainbuild
\n :localbuild
echo # Building tools for local system. %GOHOSTOS%/%GOHOSTARCH%\n-set oldGOOS=%GOOS%\n-set oldGOARCH=%GOARCH%\n+setlocal
set GOOS=%GOHOSTOS%\n set GOARCH=%GOHOSTARCH%\n %GOTOOLDIR%\\go_bootstrap install -v std
-set GOOS=%oldGOOS%\n-set GOARCH=%oldGOARCH%\n+endlocal
if errorlevel 1 goto fail
echo .\n \n@@ -65,7 +70,7 @@ if errorlevel 1 goto fail
del %GOTOOLDIR%\\go_bootstrap.exe
echo .\n \n-if \"x%1\"==\"x--no-banner\" goto nobanner
+if x%1==x--no-banner goto nobanner
%GOTOOLDIR%\\dist banner
:nobanner
\n
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/32cb495b185b50b08aea7fd9402ddf3152f1fda8
元コミット内容
build: keep environment variable changes local during Windows build
R=bradfitz, rsc
CC=golang-dev
https://golang.org/cl/5673048
変更の背景
このコミットの背景には、Go言語のWindowsビルドプロセスにおける環境変数の管理に関する問題がありました。従来のバッチスクリプト(all.bat
やmake.bat
)では、ビルド中にPATH
やGOOS
、GOARCH
といった環境変数を変更していました。しかし、これらの変更がスクリプトの実行終了後もシステム全体に永続的に影響を与えてしまう可能性がありました。
これは、特に開発者が複数のGoバージョンを切り替えたり、異なるビルド設定で作業したりする場合に問題となります。例えば、あるビルドスクリプトがGOOS=windows
と設定した後、その設定がシステム全体に残ってしまうと、その後のGoコマンドの実行や別のビルドスクリプトの動作に予期せぬ影響を与える可能性があります。
このコミットは、このような環境変数の「汚染」を防ぎ、ビルドスクリプトが自身の実行スコープ内でのみ環境変数を変更するようにすることで、ビルドプロセスの独立性と再現性を高めることを目的としています。
前提知識の解説
1. Windowsバッチスクリプトと環境変数
Windowsのバッチスクリプト(.bat
ファイル)は、コマンドプロンプトで実行される一連のコマンドを記述したテキストファイルです。バッチスクリプト内でset
コマンドを使用すると、環境変数の値を設定できます。
例:
set MY_VAR=Hello
echo %MY_VAR%
2. setlocal
とendlocal
コマンド
setlocal
とendlocal
は、Windowsバッチスクリプトにおいて環境変数のスコープを管理するための重要なコマンドです。
setlocal
: このコマンドが実行されると、現在の環境変数の状態が保存されます。setlocal
以降にスクリプト内で環境変数を変更しても、その変更はsetlocal
が有効なブロック内でのみ有効となります。endlocal
: このコマンドが実行されると、setlocal
が実行された時点の環境変数の状態が復元されます。つまり、setlocal
とendlocal
の間で行われた環境変数の変更は、endlocal
の実行によって元に戻されます。
setlocal
とendlocal
を使用しない場合、バッチスクリプト内で行われた環境変数の変更は、スクリプトの実行終了後もコマンドプロンプトのセッションに永続的に影響を与えます。
3. Go言語のビルドプロセス(Windowsにおけるall.bat
とmake.bat
)
Go言語のソースコードからGoツールチェインをビルドする際には、プラットフォーム固有のスクリプトが使用されます。Windows環境では、主にsrc/all.bat
とsrc/make.bat
がその役割を担います。
src/all.bat
: Goのビルドとテストを実行するためのトップレベルのスクリプトです。通常、このスクリプトを実行することで、Goのツールチェイン全体がビルドされ、テストが実行されます。src/make.bat
: 実際のビルド作業を行うスクリプトです。Goのコンパイラや標準ライブラリなどをビルドするために、内部で様々な環境変数を設定し、Goツールを実行します。
これらのスクリプトは、ビルドの過程でGOOS
(ターゲットOS)、GOARCH
(ターゲットアーキテクチャ)、PATH
(実行可能ファイルの検索パス)などの環境変数を一時的に変更することがあります。
技術的詳細
このコミットの技術的な核心は、Windowsバッチスクリプトにおける環境変数の「スコープ」を適切に管理することにあります。
Goのビルドスクリプト(all.bat
とmake.bat
)は、ビルドの特定の段階で、一時的に異なるGOOS
やGOARCH
、あるいはPATH
を設定する必要があります。例えば、クロスコンパイルを行う場合、ホストOSとは異なるターゲットOS/アーキテクチャ向けにツールをビルドするために、これらの環境変数を変更します。
しかし、setlocal
を使用しない場合、これらの環境変数の変更は、スクリプトが終了した後も、そのスクリプトを呼び出した親のコマンドプロンプトセッションに引き継がれてしまいます。これは、以下のような問題を引き起こす可能性があります。
- 環境の汚染: ビルドスクリプトが終了した後も、開発者のコマンドプロンプト環境がビルド時の特定の設定(例:
GOOS=windows
)で上書きされたままになり、その後の開発作業に影響を与える。 - 再現性の低下: 同じコマンドプロンプトセッション内で複数のビルドを連続して実行した場合、前のビルドの環境変数の変更が次のビルドに影響を与え、予期せぬ結果やエラーを引き起こす可能性がある。
- デバッグの困難さ: 環境変数の状態が予測不能になるため、問題の特定とデバッグが難しくなる。
このコミットでは、setlocal
コマンドをスクリプトの冒頭に配置することで、スクリプト内で変更されるすべての環境変数が、そのスクリプトの実行スコープ内でのみ有効となるようにしています。endlocal
は通常、setlocal
と対で使用され、setlocal
が有効なブロックの終了時に環境変数を元の状態に戻しますが、バッチスクリプトの実行が終了すると暗黙的にendlocal
が実行されるため、トップレベルのスクリプトでは明示的なendlocal
は不要な場合もあります。
make.bat
では、--no-local
という新しい引数を導入し、setlocal
の実行を制御しています。これは、make.bat
がall.bat
から呼び出される際に、all.bat
が既にsetlocal
を設定しているため、make.bat
内でさらにsetlocal
をネストする必要がない、あるいは特定のシナリオで環境変数の変更を意図的に永続化させたい場合に柔軟性を持たせるためと考えられます。しかし、このコミットではall.bat
からmake.bat
を呼び出す際に--no-local
を渡すことで、make.bat
内のトップレベルのsetlocal
をスキップさせています。
また、make.bat
内のlocalbuild
セクションでは、GOOS
とGOARCH
を一時的に変更する際に、以前はoldGOOS
とoldGOARCH
という一時変数に退避させていましたが、これもsetlocal
とendlocal
で置き換えられています。これにより、変数の退避と復元を手動で行う必要がなくなり、コードがよりクリーンで堅牢になっています。
コアとなるコードの変更箇所
src/all.bat
--- a/src/all.bat
+++ b/src/all.bat
@@ -3,20 +3,19 @@
:: license that can be found in the LICENSE file.
@echo off
+setlocal
+\n if exist make.bat goto ok
echo all.bat must be run from go\\src
:: cannot exit: would kill parent command interpreter
goto end
:ok
-set GOOLDPATH=%PATH%\n-\n-call make.bat --no-banner
+call make.bat --no-banner --no-local
if %GOBUILDFAIL%==1 goto end
call run.bat --no-rebuild
if %GOBUILDFAIL%==1 goto end
go tool dist banner
:end
-set PATH=%GOOLDPATH%\n if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%\n
setlocal
がスクリプトの冒頭に追加されました。PATH
をGOOLDPATH
に保存し、スクリプト終了時に復元するロジックが削除されました。これはsetlocal
によって不要になったためです。make.bat
の呼び出しに--no-local
引数が追加されました。
src/make.bat
--- a/src/make.bat
+++ b/src/make.bat
@@ -3,6 +3,13 @@
:: license that can be found in the LICENSE file.
@echo off
+:: Keep environment variables within this script
+:: unless invoked with --no-local.
+if x%1==x--no-local goto nolocal
+if x%2==x--no-local goto nolocal
+setlocal
+:nolocal
+\n set GOBUILDFAIL=0
if exist make.bat goto ok
@@ -48,13 +55,11 @@ goto mainbuild
:localbuild
echo # Building tools for local system. %GOHOSTOS%/%GOHOSTARCH%\n-set oldGOOS=%GOOS%\n-set oldGOARCH=%GOARCH%\n+setlocal
set GOOS=%GOHOSTOS%\n set GOARCH=%GOHOSTARCH%\n %GOTOOLDIR%\\go_bootstrap install -v std
-set GOOS=%oldGOOS%\n-set GOARCH=%oldGOARCH%\n+endlocal
if errorlevel 1 goto fail
echo .\n \n@@ -65,7 +70,7 @@ if errorlevel 1 goto fail
del %GOTOOLDIR%\\go_bootstrap.exe
echo .\n \n-if \"x%1\"==\"x--no-banner\" goto nobanner
+if x%1==x--no-banner goto nobanner
%GOTOOLDIR%\\dist banner
:nobanner
\n
- スクリプトの冒頭に
setlocal
が追加されましたが、--no-local
引数が渡された場合はスキップされるロジックが追加されました。 :localbuild
セクションで、oldGOOS
とoldGOARCH
を使った環境変数の退避・復元ロジックがsetlocal
とendlocal
に置き換えられました。
コアとなるコードの解説
このコミットの主要な変更は、Windowsバッチスクリプトのsetlocal
とendlocal
コマンドを戦略的に使用することで、環境変数のスコープを限定している点です。
-
src/all.bat
の変更:- スクリプトの冒頭に
setlocal
が追加されました。これにより、all.bat
内で設定されるすべての環境変数(例:GOBUILDFAIL
、PATH
の変更など)は、このスクリプトの実行が終了すると自動的に元の状態に戻されます。以前はPATH
を手動で保存・復元していましたが、setlocal
の導入によりその手間が不要になり、より堅牢な管理が可能になりました。 call make.bat --no-banner
がcall make.bat --no-banner --no-local
に変更されました。これは、all.bat
が既にsetlocal
で環境変数のスコープを管理しているため、make.bat
内でさらにトップレベルのsetlocal
をネストする必要がないことをmake.bat
に伝えています。
- スクリプトの冒頭に
-
src/make.bat
の変更:- スクリプトの冒頭に、
--no-local
引数の有無をチェックするロジックが追加されました。もし--no-local
が渡された場合(all.bat
からの呼び出し時など)、setlocal
は実行されず、環境変数の変更は親のスコープ(この場合はall.bat
のsetlocal
スコープ)に引き継がれます。これにより、all.bat
とmake.bat
の間で環境変数のスコープが適切に連携されます。 :localbuild
セクションは、Goのツールチェインをホストシステム向けにビルドする部分です。ここでは、GOOS
とGOARCH
を一時的にホストの値に設定します。以前はこれらの値をoldGOOS
とoldGOARCH
に保存し、ビルド後に手動で復元していましたが、このコミットではsetlocal
とendlocal
で囲むことで、この一時的な変更が:localbuild
ブロック内でのみ有効となるようにしました。これにより、コードが簡潔になり、環境変数の復元忘れといったヒューマンエラーを防ぐことができます。
- スクリプトの冒頭に、
これらの変更により、GoのWindowsビルドプロセスは、環境変数に関してより自己完結的で、外部環境への影響が少ないものになりました。これは、開発者の作業環境をクリーンに保ち、ビルドの再現性を向上させる上で非常に重要です。
関連リンク
- Go CL 5673048: https://golang.org/cl/5673048
参考にした情報源リンク
- Microsoft Docs:
setlocal
andendlocal
commands: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setlocal - Microsoft Docs:
set
command: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/set_1 - Go言語のビルドシステムに関する一般的な情報 (Goの公式ドキュメントやブログ記事など)