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

[インデックス 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コマンドとその制御ロジックを追加したことです。

  1. 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内で設定される環境変数はこのスクリプトのローカルスコープに限定されます。これにより、スクリプト終了時に環境変数が自動的に元の状態に戻り、環境汚染を防ぎます。
  2. 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.batrun.batを呼び出す際に、明示的に--no-local引数を渡すようにしたことを意味します。この変更により、run.bat内でsetlocalがスキップされ、run.batが設定する環境変数がall.batの環境にも伝播するようになります。これは、all.batrun.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.batrun.batを呼び出す際に、既存の--no-rebuild引数に加えて、新しく--no-local引数を渡すように変更されています。これにより、run.batsetlocalコマンドを実行せず、その中で設定される環境変数がall.batの環境に影響を与えることを許可します。これは、all.batrun.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はデフォルトで環境変数のスコープをローカルに保ち、よりクリーンな実行環境を提供します。しかし、必要に応じて呼び出し元がこの動作を無効にできる柔軟性も持ち合わせています。

関連リンク

参考にした情報源リンク