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

[インデックス 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言語の初期のビルドシステムは、シェルスクリプトを多用していました。これらのスクリプトは、GOROOTGOBINWORKといった環境変数を使用して、コンパイルやリンクのパスを決定していました。しかし、シェルスクリプトにおける変数の展開は、適切に引用符で囲まれていない場合、予期せぬ挙動を引き起こす可能性があります。例えば、パスにスペースが含まれている場合、シェルはそれを複数の引数として解釈してしまうことがあります。

また、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コマンドをパイプで渡し、以下の変換を行っています。

  1. 変数の引用符付け: $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のように正しく解釈されるようになります。
  2. 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スクリプトは以下の処理を行います。

  1. s/$GOBIN/"$GOBIN"/g: $GOBINという文字列を"$GOBIN"に置換します。これにより、GOBIN環境変数の値がスペースを含んでいても、シェルがそれを単一のパスとして正しく解釈するようになります。
  2. s/$GOROOT/"$GOROOT"/g: 同様に$GOROOT"$GOROOT"に置換します。
  3. s/$WORK/"$WORK"/g: 同様に$WORK"$WORK"に置換します。
  4. s;\\\\;/;g: これはWindowsパスのバックスラッシュをスラッシュに変換する最も重要な部分です。
    • s;...;...;g のように、sコマンドの区切り文字としてスラッシュ(/)の代わりにセミコロン(;)を使用しています。これは、置換対象のパターンにスラッシュが含まれる場合に、エスケープの手間を省くためによく使われるテクニックです。
    • \\\\: 正規表現において、バックスラッシュ自体をマッチさせるためには、エスケープが必要です。\は正規表現の特殊文字であるため、\\と記述します。さらに、シェルがこの\を解釈しないように、sedコマンド全体をシングルクォーテーションで囲んでいるため、sedに渡される文字列リテラルとして\\を表現するために、さらにエスケープが必要となり、結果的に\\\\となります。
    • /: 置換後の文字列はスラッシュです。
    • g: グローバル置換フラグで、行内の全てのマッチを置換します。

このsedのパイプ処理によって、go install -nが生成する生のビルドコマンドが、環境変数を安全に扱い、WindowsとUnixの両方で互換性のあるパス形式を使用する、より堅牢なスクリプトに変換されます。この変換されたスクリプトが$targファイルに保存され、実行可能属性が付与されます。

結果として、各プラットフォーム固有のビルドスクリプト(buildscript_darwin_386.shなど)内のmkdircpなどのコマンドで使われているパスが、このsed処理によって自動的に引用符で囲まれ、バックスラッシュがスラッシュに変換されるため、個々のスクリプトファイル自体は直接変更されず、生成されるスクリプトの挙動が改善されるという仕組みです。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (特にビルドシステムや環境変数に関するセクション)
  • シェルスクリプトの引用符付けに関する一般的な情報
  • sedコマンドの利用方法に関するドキュメント