[インデックス 11948] ファイルの概要
このコミットは、Go言語のビルドシステムにおけるWindowsバッチスクリプトの環境変数管理に関する改善です。具体的には、run.bat
スクリプトにsetlocal
コマンドを導入し、スクリプト内で設定される環境変数がそのスクリプトの実行範囲内でのみ有効となるように変更しています。これにより、run.bat
が呼び出し元の環境を意図せず変更してしまうことを防ぎ、ビルドプロセスの堅牢性を向上させています。同時に、--no-local
という新しい引数を導入し、特定のシナリオ(例: all.bat
からの呼び出し)で環境変数の変更が呼び出し元に伝播する必要がある場合に、このsetlocal
の動作を無効にできるようにしています。
コミット
commit 034c72a5573a8d6f97f7ab241de271a09c356817
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Thu Feb 16 10:44:55 2012 +1100
build: use setlocal in run.bat
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5672061
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/034c72a5573a8d6f97f7ab241de271a09c356817
元コミット内容
build: use setlocal in run.bat
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5672061
変更の背景
Windowsのバッチスクリプト(.bat
ファイル)では、スクリプト内でset
コマンドを使って環境変数を設定すると、その変更はスクリプトの呼び出し元の環境にも影響を与えます。これは、スクリプトが終了した後もその環境変数がシステムに残ってしまう「環境汚染」を引き起こす可能性があります。Go言語のビルドプロセスでは、複数のバッチスクリプトが連携して動作しており、run.bat
のようなスクリプトがビルドに必要な環境変数を設定することがあります。
このコミットの背景には、run.bat
が設定する環境変数が、その呼び出し元(特にall.bat
)や、さらにはシステム全体の環境に意図せず影響を与えてしまう可能性があったという問題意識があります。このような環境汚染は、ビルドの再現性を損なったり、他のプロセスに予期せぬ影響を与えたりする原因となります。
この問題を解決し、スクリプトの実行環境をより分離・独立させるために、setlocal
コマンドの導入が検討されました。これにより、run.bat
内で設定される環境変数が、そのスクリプトの実行中のみ有効となり、スクリプト終了時には自動的に元の環境に戻るようにすることが目的です。ただし、all.bat
のようにrun.bat
が設定する環境変数を必要とする呼び出し元も存在するため、その場合はsetlocal
の動作を無効にできるメカニズムも同時に必要とされました。
前提知識の解説
Windows バッチスクリプト (.bat
ファイル)
Windowsのコマンドプロンプトで実行されるスクリプトファイルです。一連のコマンドを記述し、自動化されたタスクを実行するために使用されます。
環境変数
オペレーティングシステムがプログラムの実行環境に関する情報を格納するために使用する動的な名前付き値です。例えば、PATH
環境変数は実行可能ファイルを探すディレクトリのリストを保持します。バッチスクリプトではset VARNAME=VALUE
のようにして設定します。
setlocal
コマンド
Windowsバッチスクリプトの重要なコマンドの一つです。setlocal
が実行されると、その時点での環境変数の状態が保存され、それ以降のスクリプト内での環境変数への変更(set
コマンドによる設定など)は、そのスクリプトのローカルなスコープに限定されます。スクリプトが終了するか、endlocal
コマンドが実行されると、setlocal
が実行された時点の環境変数の状態に自動的に復元されます。これにより、スクリプトがグローバルな環境を汚染するのを防ぎ、スクリプトの独立性と再利用性を高めることができます。
goto
コマンドとラベル
バッチスクリプト内で処理の流れを制御するために使用されます。goto LABELNAME
と記述すると、スクリプト内の:LABELNAME
という行に処理がジャンプします。
%1
, %2
などの引数
バッチスクリプトを実行する際に渡されるコマンドライン引数を参照するために使用されます。%1
は最初の引数、%2
は2番目の引数、といった具合です。
技術的詳細
このコミットの主要な変更点は、src/run.bat
スクリプトの冒頭にsetlocal
コマンドとその制御ロジックを追加したことです。
-
setlocal
の条件付き実行:src/run.bat
の冒頭に以下のロジックが追加されました。:: 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
このコードは、スクリプトに渡された最初の引数(
%1
)または2番目の引数(%2
)が--no-local
であるかどうかをチェックします。- もし
--no-local
引数が見つかった場合、goto nolocal
によってsetlocal
コマンドがスキップされ、スクリプト内で設定される環境変数は呼び出し元の環境にも影響を与えます。 --no-local
引数が見つからない場合、setlocal
コマンドが実行され、run.bat
内で設定される環境変数はこのスクリプトのローカルスコープに限定されます。これにより、スクリプト終了時に環境変数が自動的に元の状態に戻り、環境汚染を防ぎます。
- もし
-
src/all.bat
の変更:src/all.bat
はGoのビルドプロセス全体を管理するスクリプトの一つであり、run.bat
を呼び出しています。このコミットでは、all.bat
内のrun.bat
の呼び出しが以下のように変更されました。-call run.bat --no-rebuild +call run.bat --no-rebuild --no-local
これは、
all.bat
がrun.bat
を呼び出す際に、明示的に--no-local
引数を渡すようにしたことを意味します。この変更により、run.bat
内でsetlocal
がスキップされ、run.bat
が設定する環境変数がall.bat
の環境にも伝播するようになります。これは、all.bat
がrun.bat
によって設定される特定の環境変数を必要としているためと考えられます。
この変更により、run.bat
はデフォルトで環境変数をローカルに保つようになり、より独立した動作が可能になります。同時に、--no-local
というオプトアウトメカニズムを提供することで、特定の依存関係を持つスクリプト(この場合はall.bat
)が引き続き正しく機能するように配慮されています。
コアとなるコードの変更箇所
src/all.bat
--- a/src/all.bat
+++ b/src/all.bat
@@ -13,7 +13,7 @@ goto end
call make.bat --no-banner --no-local
if %GOBUILDFAIL%==1 goto end
-call run.bat --no-rebuild
+call run.bat --no-rebuild --no-local
if %GOBUILDFAIL%==1 goto end
go tool dist banner
src/run.bat
--- a/src/run.bat
+++ b/src/run.bat
@@ -3,6 +3,13 @@
:: license that can be found in the LICENSE file.\n @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
+
set GOBUILDFAIL=0
rem TODO avoid rebuild if possible
コアとなるコードの解説
src/all.bat
の変更
call run.bat --no-rebuild --no-local
この行は、all.bat
がrun.bat
を呼び出す際に、既存の--no-rebuild
引数に加えて、新しく--no-local
引数を渡すように変更されています。これにより、run.bat
はsetlocal
コマンドを実行せず、その中で設定される環境変数がall.bat
の環境に影響を与えることを許可します。これは、all.bat
がrun.bat
によって設定される特定の環境変数に依存しているため、その依存関係を維持するための変更です。
src/run.bat
の変更
:: 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
このブロックは、run.bat
の実行開始直後に評価されます。
if x%1==x--no-local goto nolocal
: 最初の引数(%1
)が--no-local
と等しい場合、nolocal
ラベルにジャンプします。x
を前置しているのは、引数が空の場合に構文エラーになるのを防ぐための一般的なバッチスクリプトのテクニックです(例:if x==x--no-local
)。if x%2==x--no-local goto nolocal
: 2番目の引数(%2
)が--no-local
と等しい場合、nolocal
ラベルにジャンプします。これは、--no-rebuild
のような他の引数と組み合わせて--no-local
が渡される可能性があるためです。setlocal
: 上記のif
文のどちらも真でなかった場合(つまり、--no-local
引数が渡されなかった場合)、このコマンドが実行されます。これにより、run.bat
内で設定されるすべての環境変数は、このスクリプトのローカルスコープに限定され、スクリプト終了時に自動的に元の環境に戻ります。:nolocal
:goto
コマンドのジャンプ先となるラベルです。--no-local
引数が存在した場合、処理はこのラベルから続行され、setlocal
コマンドはスキップされます。
この変更により、run.bat
はデフォルトで環境変数のスコープをローカルに保ち、よりクリーンな実行環境を提供します。しかし、必要に応じて呼び出し元がこの動作を無効にできる柔軟性も持ち合わせています。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Gerrit Code Review (Goプロジェクト): https://go-review.googlesource.com/
- このコミットのGerrit変更リスト: https://golang.org/cl/5672061
参考にした情報源リンク
- Windows Batch Script
setlocal
command: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setlocal - Windows Batch Script
goto
command: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/goto - Windows Batch Script command-line arguments (
%1
,%2
etc.): https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/call (indirectly, ascall
passes arguments) - Go言語のビルドシステムに関する一般的な情報 (Goの公式ドキュメントやソースコード): https://go.dev/doc/install/source (ビルドプロセスの概要)