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

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

このコミットは、Go言語のWindowsビルドプロセスにおいて、環境変数の変更がビルドスクリプトのローカルスコープに限定されるように修正するものです。具体的には、all.batmake.batという2つのバッチスクリプトにsetlocalendlocalコマンドを導入し、ビルド中に設定された環境変数が、スクリプトの実行終了後にシステム全体に影響を与えないようにしています。これにより、ビルドプロセスの独立性とクリーンさが保たれます。

コミット

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.batmake.bat)では、ビルド中にPATHGOOSGOARCHといった環境変数を変更していました。しかし、これらの変更がスクリプトの実行終了後もシステム全体に永続的に影響を与えてしまう可能性がありました。

これは、特に開発者が複数のGoバージョンを切り替えたり、異なるビルド設定で作業したりする場合に問題となります。例えば、あるビルドスクリプトがGOOS=windowsと設定した後、その設定がシステム全体に残ってしまうと、その後のGoコマンドの実行や別のビルドスクリプトの動作に予期せぬ影響を与える可能性があります。

このコミットは、このような環境変数の「汚染」を防ぎ、ビルドスクリプトが自身の実行スコープ内でのみ環境変数を変更するようにすることで、ビルドプロセスの独立性と再現性を高めることを目的としています。

前提知識の解説

1. Windowsバッチスクリプトと環境変数

Windowsのバッチスクリプト(.batファイル)は、コマンドプロンプトで実行される一連のコマンドを記述したテキストファイルです。バッチスクリプト内でsetコマンドを使用すると、環境変数の値を設定できます。

例:

set MY_VAR=Hello
echo %MY_VAR%

2. setlocalendlocalコマンド

setlocalendlocalは、Windowsバッチスクリプトにおいて環境変数のスコープを管理するための重要なコマンドです。

  • setlocal: このコマンドが実行されると、現在の環境変数の状態が保存されます。setlocal以降にスクリプト内で環境変数を変更しても、その変更はsetlocalが有効なブロック内でのみ有効となります。
  • endlocal: このコマンドが実行されると、setlocalが実行された時点の環境変数の状態が復元されます。つまり、setlocalendlocalの間で行われた環境変数の変更は、endlocalの実行によって元に戻されます。

setlocalendlocalを使用しない場合、バッチスクリプト内で行われた環境変数の変更は、スクリプトの実行終了後もコマンドプロンプトのセッションに永続的に影響を与えます。

3. Go言語のビルドプロセス(Windowsにおけるall.batmake.bat

Go言語のソースコードからGoツールチェインをビルドする際には、プラットフォーム固有のスクリプトが使用されます。Windows環境では、主にsrc/all.batsrc/make.batがその役割を担います。

  • src/all.bat: Goのビルドとテストを実行するためのトップレベルのスクリプトです。通常、このスクリプトを実行することで、Goのツールチェイン全体がビルドされ、テストが実行されます。
  • src/make.bat: 実際のビルド作業を行うスクリプトです。Goのコンパイラや標準ライブラリなどをビルドするために、内部で様々な環境変数を設定し、Goツールを実行します。

これらのスクリプトは、ビルドの過程でGOOS(ターゲットOS)、GOARCH(ターゲットアーキテクチャ)、PATH(実行可能ファイルの検索パス)などの環境変数を一時的に変更することがあります。

技術的詳細

このコミットの技術的な核心は、Windowsバッチスクリプトにおける環境変数の「スコープ」を適切に管理することにあります。

Goのビルドスクリプト(all.batmake.bat)は、ビルドの特定の段階で、一時的に異なるGOOSGOARCH、あるいはPATHを設定する必要があります。例えば、クロスコンパイルを行う場合、ホストOSとは異なるターゲットOS/アーキテクチャ向けにツールをビルドするために、これらの環境変数を変更します。

しかし、setlocalを使用しない場合、これらの環境変数の変更は、スクリプトが終了した後も、そのスクリプトを呼び出した親のコマンドプロンプトセッションに引き継がれてしまいます。これは、以下のような問題を引き起こす可能性があります。

  1. 環境の汚染: ビルドスクリプトが終了した後も、開発者のコマンドプロンプト環境がビルド時の特定の設定(例: GOOS=windows)で上書きされたままになり、その後の開発作業に影響を与える。
  2. 再現性の低下: 同じコマンドプロンプトセッション内で複数のビルドを連続して実行した場合、前のビルドの環境変数の変更が次のビルドに影響を与え、予期せぬ結果やエラーを引き起こす可能性がある。
  3. デバッグの困難さ: 環境変数の状態が予測不能になるため、問題の特定とデバッグが難しくなる。

このコミットでは、setlocalコマンドをスクリプトの冒頭に配置することで、スクリプト内で変更されるすべての環境変数が、そのスクリプトの実行スコープ内でのみ有効となるようにしています。endlocalは通常、setlocalと対で使用され、setlocalが有効なブロックの終了時に環境変数を元の状態に戻しますが、バッチスクリプトの実行が終了すると暗黙的にendlocalが実行されるため、トップレベルのスクリプトでは明示的なendlocalは不要な場合もあります。

make.batでは、--no-localという新しい引数を導入し、setlocalの実行を制御しています。これは、make.batall.batから呼び出される際に、all.batが既にsetlocalを設定しているため、make.bat内でさらにsetlocalをネストする必要がない、あるいは特定のシナリオで環境変数の変更を意図的に永続化させたい場合に柔軟性を持たせるためと考えられます。しかし、このコミットではall.batからmake.batを呼び出す際に--no-localを渡すことで、make.bat内のトップレベルのsetlocalをスキップさせています。

また、make.bat内のlocalbuildセクションでは、GOOSGOARCHを一時的に変更する際に、以前はoldGOOSoldGOARCHという一時変数に退避させていましたが、これもsetlocalendlocalで置き換えられています。これにより、変数の退避と復元を手動で行う必要がなくなり、コードがよりクリーンで堅牢になっています。

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

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がスクリプトの冒頭に追加されました。
  • PATHGOOLDPATHに保存し、スクリプト終了時に復元するロジックが削除されました。これは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セクションで、oldGOOSoldGOARCHを使った環境変数の退避・復元ロジックがsetlocalendlocalに置き換えられました。

コアとなるコードの解説

このコミットの主要な変更は、Windowsバッチスクリプトのsetlocalendlocalコマンドを戦略的に使用することで、環境変数のスコープを限定している点です。

  1. src/all.batの変更:

    • スクリプトの冒頭にsetlocalが追加されました。これにより、all.bat内で設定されるすべての環境変数(例: GOBUILDFAILPATHの変更など)は、このスクリプトの実行が終了すると自動的に元の状態に戻されます。以前はPATHを手動で保存・復元していましたが、setlocalの導入によりその手間が不要になり、より堅牢な管理が可能になりました。
    • call make.bat --no-bannercall make.bat --no-banner --no-localに変更されました。これは、all.batが既にsetlocalで環境変数のスコープを管理しているため、make.bat内でさらにトップレベルのsetlocalをネストする必要がないことをmake.batに伝えています。
  2. src/make.batの変更:

    • スクリプトの冒頭に、--no-local引数の有無をチェックするロジックが追加されました。もし--no-localが渡された場合(all.batからの呼び出し時など)、setlocalは実行されず、環境変数の変更は親のスコープ(この場合はall.batsetlocalスコープ)に引き継がれます。これにより、all.batmake.batの間で環境変数のスコープが適切に連携されます。
    • :localbuildセクションは、Goのツールチェインをホストシステム向けにビルドする部分です。ここでは、GOOSGOARCHを一時的にホストの値に設定します。以前はこれらの値をoldGOOSoldGOARCHに保存し、ビルド後に手動で復元していましたが、このコミットではsetlocalendlocalで囲むことで、この一時的な変更が:localbuildブロック内でのみ有効となるようにしました。これにより、コードが簡潔になり、環境変数の復元忘れといったヒューマンエラーを防ぐことができます。

これらの変更により、GoのWindowsビルドプロセスは、環境変数に関してより自己完結的で、外部環境への影響が少ないものになりました。これは、開発者の作業環境をクリーンに保ち、ビルドの再現性を向上させる上で非常に重要です。

関連リンク

参考にした情報源リンク