[インデックス 10951] ファイルの概要
このコミットは、Go言語のビルドスクリプトの安全性とWindows環境での互換性を向上させるための変更です。具体的には、ビルドプロセス中に生成されるスクリプトにおいて、環境変数の展開をより安全に行い、パス区切り文字を統一することで、異なるオペレーティングシステム間での一貫した動作を保証します。
コミット
commit a9b92013d2a14d58d8ed7dde1c90599703885e29
Author: Russ Cox <rsc@golang.org>
Date: Wed Dec 21 15:58:05 2011 -0500
buildscript: make script safer, same output on Windows
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/5502062
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a9b92013d2a14d58d8ed7dde1c90599703885e29
元コミット内容
このコミットの元のメッセージは「buildscript: make script safer, same output on Windows」です。これは、ビルドスクリプトの安全性を高め、特にWindows環境においてもUnix系システムと同じ出力を生成するように変更されたことを示しています。
変更の背景
Go言語の初期のビルドシステムは、シェルスクリプトを多用していました。これらのスクリプトは、GOROOT
やGOBIN
、WORK
といった環境変数を使用して、コンパイルやリンクのパスを決定していました。しかし、シェルスクリプトにおける変数の展開は、適切に引用符で囲まれていない場合、予期せぬ挙動を引き起こす可能性があります。例えば、パスにスペースが含まれている場合、シェルはそれを複数の引数として解釈してしまうことがあります。
また、Windows環境ではパス区切り文字としてバックスラッシュ(\
)が使用されるのに対し、Unix系システムではスラッシュ(/
)が使用されます。go install -n
コマンドが生成するスクリプトが、これらの環境差を吸収せずにそのまま出力されると、Windows上で実行した際にパスの解釈に問題が生じ、ビルドが失敗する可能性がありました。
このコミットは、これらの問題を解決し、ビルドスクリプトの堅牢性とクロスプラットフォーム互換性を向上させることを目的としています。
前提知識の解説
-
シェルスクリプトと変数の引用符: シェルスクリプトでは、変数(例:
$VAR
)が展開される際に、その値にスペースや特殊文字が含まれていると、シェルがそれらを単語の区切りやコマンドとして誤って解釈する可能性があります。これを防ぐためには、変数をダブルクォーテーション("
)で囲むことが推奨されます。例えば、mkdir $WORK
は$WORK
が/path/with spaces
の場合mkdir /path/with spaces
となりエラーになる可能性がありますが、mkdir "$WORK"
とすることでmkdir "/path/with spaces"
となり、単一の引数として正しく解釈されます。 -
パス区切り文字: Unix系オペレーティングシステム(Linux, macOS, FreeBSDなど)では、ファイルパスのディレクトリ区切り文字としてスラッシュ(
/
)が標準的に使用されます。一方、Windowsではバックスラッシュ(\
)が使用されます。クロスプラットフォームで動作するスクリプトを作成する際には、これらの違いを適切に処理する必要があります。 -
go install -n
:go install
コマンドはGoのパッケージをコンパイルし、インストールするコマンドです。-n
フラグを付けると、実際にコマンドを実行せずに、実行されるであろうコマンドを表示します。このコミットでは、この機能を利用して生成されるビルドコマンドをsed
で加工し、より安全なスクリプトを生成しています。 -
sed
コマンド:sed
(stream editor) は、テキストの変換を行うための強力なコマンドラインツールです。正規表現を使用して、入力ストリームからパターンを検索し、置換することができます。s/old/new/g
:old
というパターンをnew
に置換します。g
フラグは、行内の全てのマッチを置換することを意味します。s;\\;/;g
: セミコロン(;
)を区切り文字として使用しています。これは、正規表現や置換文字列にスラッシュ(/
)が含まれる場合に便利です。この例では、バックスラッシュ(\
)をスラッシュ(/
)に置換しています。バックスラッシュ自体が特殊文字であるため、\\
とエスケープする必要があります。
技術的詳細
このコミットの主要な変更点は、Goのビルドスクリプトが生成するコマンドラインにおいて、環境変数の展開を安全にし、Windows環境でのパスの互換性を確保することです。
具体的には、src/buildscript.sh
において、go install -a -n cmd/go
の出力に対してsed
コマンドをパイプで渡し、以下の変換を行っています。
-
変数の引用符付け:
$GOBIN
,$GOROOT
,$WORK
といった環境変数が展開される際に、その値がシェルによって誤って解釈されないように、ダブルクォーテーションで囲むように変更しています。s/$GOBIN/"$GOBIN"/g
s/$GOROOT/"$GOROOT"/g
s/$WORK/"$WORK"/g
これにより、例えばGOROOT=/path with spaces
のようなパスが設定されていても、cd "/path with spaces"/src/pkg/runtime
のように正しく解釈されるようになります。
-
Windowsパスの変換: Windows環境で問題となるバックスラッシュ(
\
)をスラッシュ(/
)に変換しています。s;\\\\;/;g
これは、go install -n
が生成するコマンドラインが、Windowsのパス形式(例:C:\Go\src
)を含んでいる場合に、Unix系シェルがそれを正しく解釈できるようにするためです。バックスラッシュはシェルにおいてエスケープ文字として扱われるため、sed
の正規表現内で\\
と記述することで、リテラルのバックスラッシュにマッチさせ、それを/
に置換しています。この変更により、Unix系システムとWindowsシステムで同じビルドスクリプトが生成され、実行時の挙動が統一されます。
これらの変更は、Goのビルドシステムが生成するスクリプトの堅牢性を高め、特にクロスプラットフォーム開発において、環境変数やパスの解釈に関する潜在的な問題を未然に防ぐ上で非常に重要です。
コアとなるコードの変更箇所
主要な変更はsrc/buildscript.sh
ファイルにあります。
--- a/src/buildscript.sh
+++ b/src/buildscript.sh
@@ -24,7 +24,17 @@ trap \"rm -rf $WORK\" EXIT SIGINT SIGTERM
set -e
\'
-\tgo install -a -n cmd/go
+\t# Save script printed by go install but make shell safe
+\t# by quoting variable expansions. On Windows, rewrite
+\t# \\ paths into / paths. This avoids the \\ being interpreted
+\t# as a shell escape but also makes sure that we generate the
+\t# same scripts on Unix and Windows systems.
+\tgo install -a -n cmd/go | sed \'
+\t\ts/$GOBIN/\"$GOBIN\"/g\n+\t\ts/$GOROOT/\"$GOROOT\"/g\n+\t\ts/$WORK/\"$WORK\"/g\n+\t\ts;\\\\;/;g\n+\t\'
\t)>$targ
\tchmod +x $targ
done
また、src/buildscript_*.sh
ファイル群(例: src/buildscript_darwin_386.sh
, src/buildscript_windows_386.sh
など)においても、mkdir -p $WORK/...
や cd $GOROOT/...
といった箇所が mkdir -p "$WORK"/...
や cd "$GOROOT"/...
のように、変数がダブルクォーテーションで囲まれるように変更されています。これは、src/buildscript.sh
の変更によって生成されるスクリプトが、これらの引用符を含むようになるためです。
コアとなるコードの解説
src/buildscript.sh
の変更は、go install -a -n cmd/go
コマンドの出力(Goのビルドステップを記述したシェルスクリプト)をsed
コマンドで加工する部分に集約されています。
go install -a -n cmd/go | sed '
s/$GOBIN/"$GOBIN"/g
s/$GOROOT/"$GOROOT"/g
s/$WORK/"$WORK"/g
s;\\\\;/;g
'
このsed
スクリプトは以下の処理を行います。
s/$GOBIN/"$GOBIN"/g
:$GOBIN
という文字列を"$GOBIN"
に置換します。これにより、GOBIN
環境変数の値がスペースを含んでいても、シェルがそれを単一のパスとして正しく解釈するようになります。s/$GOROOT/"$GOROOT"/g
: 同様に$GOROOT
を"$GOROOT"
に置換します。s/$WORK/"$WORK"/g
: 同様に$WORK
を"$WORK"
に置換します。s;\\\\;/;g
: これはWindowsパスのバックスラッシュをスラッシュに変換する最も重要な部分です。s;...;...;g
のように、s
コマンドの区切り文字としてスラッシュ(/
)の代わりにセミコロン(;
)を使用しています。これは、置換対象のパターンにスラッシュが含まれる場合に、エスケープの手間を省くためによく使われるテクニックです。\\\\
: 正規表現において、バックスラッシュ自体をマッチさせるためには、エスケープが必要です。\
は正規表現の特殊文字であるため、\\
と記述します。さらに、シェルがこの\
を解釈しないように、sed
コマンド全体をシングルクォーテーションで囲んでいるため、sed
に渡される文字列リテラルとして\\
を表現するために、さらにエスケープが必要となり、結果的に\\\\
となります。/
: 置換後の文字列はスラッシュです。g
: グローバル置換フラグで、行内の全てのマッチを置換します。
このsed
のパイプ処理によって、go install -n
が生成する生のビルドコマンドが、環境変数を安全に扱い、WindowsとUnixの両方で互換性のあるパス形式を使用する、より堅牢なスクリプトに変換されます。この変換されたスクリプトが$targ
ファイルに保存され、実行可能属性が付与されます。
結果として、各プラットフォーム固有のビルドスクリプト(buildscript_darwin_386.sh
など)内のmkdir
やcp
などのコマンドで使われているパスが、このsed
処理によって自動的に引用符で囲まれ、バックスラッシュがスラッシュに変換されるため、個々のスクリプトファイル自体は直接変更されず、生成されるスクリプトの挙動が改善されるという仕組みです。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- このコミットが属するGoの変更リスト (CL): https://golang.org/cl/5502062
参考にした情報源リンク
- Go言語の公式ドキュメント (特にビルドシステムや環境変数に関するセクション)
- シェルスクリプトの引用符付けに関する一般的な情報
sed
コマンドの利用方法に関するドキュメント