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

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

このコミットは、Go言語のビルドスクリプト src/buildscript.sh がWindows環境で正しく動作するように修正したものです。具体的には、sed コマンドの処理順序を変更することで、パスの変換と文字列置換が適切に行われるように改善されています。

コミット

  • コミットハッシュ: be7a04944ea9eeb7ffd5458d26a83c1693df657c
  • Author: Alex Brainman alex.brainman@gmail.com
  • Date: Tue Jan 31 09:42:33 2012 +1100

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/be7a04944ea9eeb7ffd5458d26a83c1693df657c

元コミット内容

buildscript.sh: now works correctly on windows

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5569092

変更の背景

Go言語のビルドプロセスは、クロスプラットフォーム対応を重視しており、様々なオペレーティングシステム上で動作する必要があります。src/buildscript.sh は、Goのツールチェインをビルドするためのシェルスクリプトであり、通常はUnix系システムで実行されます。しかし、Windows環境でGoをビルドする際には、CygwinやMinGW/MSYS2のようなUnixライクな環境が使われることが一般的です。

このコミット以前の buildscript.sh では、Windowsパスの表現(バックスラッシュ \ を使用)と、go バイナリの名前変更(go_bootstrap へのリネーム)に関する sed コマンドの適用順序に問題がありました。具体的には、$GOBIN/go$GOBIN/go_bootstrap に置換する処理が、パス内のバックスラッシュをスラッシュに変換する処理よりも前に実行されていたため、Windowsパスが絡む場合に意図した置換が行われない、または不正なパスが生成される可能性がありました。

この問題は、Windows環境でのGoのビルドが失敗したり、生成されるバイナリのパスが正しく認識されないといった形で現れていました。このコミットは、この問題を解決し、Windows上でのGoのビルドプロセスを安定させることを目的としています。

前提知識の解説

1. Go言語のビルドシステム

Go言語は、自身のコンパイラやツールチェインをGo自身で記述するという「セルフホスティング」の原則を採用しています。このため、GoのソースコードからGoのバイナリを生成する際には、既存のGoコンパイラ(またはブートストラップコンパイラ)が必要になります。src/buildscript.sh は、このブートストラッププロセスの一部として、Goのソースコードから最終的なGoツールチェインを構築するために使用されるスクリプトです。

2. buildscript.sh

buildscript.sh は、Goのソースツリーの src ディレクトリに存在するシェルスクリプトです。このスクリプトは、Goのビルドに必要な環境変数の設定、一時的なブートストラップコンパイラの構築、そして最終的なGoツールチェイン(go コマンド、コンパイラ、リンカなど)のビルドとインストールを行います。

3. 環境変数 (GOBIN, GOROOT, WORK)

  • GOBIN: Goの実行可能バイナリがインストールされるディレクトリを指定します。通常は $GOROOT/bin に設定されます。
  • GOROOT: Goのインストールルートディレクトリを指定します。Goのソースコード、標準ライブラリ、ツールなどがこのディレクトリ以下に配置されます。
  • WORK: ビルドプロセス中に一時ファイルや中間生成物が格納される作業ディレクトリを指定します。

これらの変数は、buildscript.sh 内でパスの構築やファイルの配置に使用されます。

4. sed コマンド

sed (stream editor) は、テキストファイルに対して変換処理を行うための強力なコマンドラインツールです。このコミットでは、sed を使用して特定の文字列パターンを別の文字列に置換しています。

sed の基本的な置換構文は s/pattern/replacement/flags です。

  • s: 置換コマンド (substitute) を意味します。
  • pattern: 検索する正規表現パターンです。
  • replacement: pattern にマッチした部分を置換する文字列です。
  • flags: 置換の動作を制御するオプションです。g は、行内でマッチしたすべてのパターンを置換することを意味します。

このコミットで使われている s;...;...;g の形式は、区切り文字としてスラッシュ / の代わりにセミコロン ; を使用しています。これは、パターンや置換文字列にスラッシュが含まれる場合に、エスケープの手間を省くためによく使われるテクニックです。

5. WindowsパスとUnixパス

Windowsではディレクトリの区切り文字としてバックスラッシュ \ が使用されます(例: C:\Users\User\Documents)。一方、Unix系システムではスラッシュ / が使用されます(例: /home/user/documents)。シェルスクリプトがWindows上でCygwinやMSYS2のような環境で実行される場合、内部的にはUnix形式のパスが扱われますが、Windowsネイティブのプログラムと連携する際にはパスの変換が必要になることがあります。

6. go_bootstrapgo-tool

Goのビルドプロセスでは、まず最小限のGoコンパイラ(ブートストラップコンパイラ)が構築されます。これは通常、go_bootstrap のような名前で一時的に存在します。その後、このブートストラップコンパイラを使用して、より完全なGoツールチェイン(go コマンド、go-tool など)がビルドされます。go-tool は、Goの内部ツール(アセンブラ、リンカなど)を指すことが多いです。

技術的詳細

このコミットの核心は、src/buildscript.sh 内の sed コマンドの順序変更です。

元のコードでは、以下の2つの sed コマンドがこの順序で実行されていました。

# Original order
s;\"\\$GOBIN\"/go;&_bootstrap;g  # (A) goをgo_bootstrapにリネーム
s;\\\\;/;g                     # (B) バックスラッシュをスラッシュに変換
  1. s;\"\\$GOBIN\"/go;&_bootstrap;g (A):

    • このコマンドは、"$GOBIN"/go という文字列を検索し、それを "$GOBIN"/go_bootstrap に置換します。
    • \" は引用符 " をエスケープしています。
    • \\ はバックスラッシュ \ をエスケープしています。これは、$GOBIN の値がWindowsパス(例: C:\Go\bin)である場合に、その中のバックスラッシュが正規表現の特殊文字として解釈されないようにするためです。
    • & はマッチした文字列全体を指します。つまり、"$GOBIN"/go_bootstrap を追加しています。
  2. s;\\\\;/;g (B):

    • このコマンドは、すべてのバックスラッシュ \ をスラッシュ / に置換します。
    • \\\\ は、正規表現として \ をマッチさせるために、\ 自体をエスケープし、さらに sed の正規表現エンジンが \ を特殊文字として解釈しないようにするために、合計4つのバックスラッシュが必要です。

問題点: Windows環境では、$GOBIN の値が C:\Go\bin のようにバックスラッシュを含むパスになることがあります。 元の順序では、まず (A) の置換が実行されます。もし "$GOBIN"/goC:\Go\bin\go のような形式だった場合、(A) は C:\Go\bin\go_bootstrap に置換しようとします。しかし、この時点ではまだバックスラッシュがスラッシュに変換されていないため、sed のパターンマッチングが期待通りに機能しない、または生成されるパスが不正になる可能性がありました。特に、正規表現のパターンにバックスラッシュが含まれる場合、その解釈が複雑になります。

修正内容: コミットでは、この2つの sed コマンドの順序を入れ替えています。

# New order
s;\\\\;/;g                     # (B) バックスラッシュをスラッシュに変換
s;\"\\$GOBIN\"/go;&_bootstrap;g  # (A) goをgo_bootstrapにリネーム
  1. s;\\\\;/;g (B) が先に実行されます。

    • これにより、$GOBIN の値に含まれるすべてのバックスラッシュがスラッシュに変換されます。例えば、C:\Go\binC:/Go/bin になります。
    • この変換は、後続の sed コマンドがUnix形式のパスを前提として動作するように、パスを正規化する役割を果たします。
  2. 次に s;\"\\$GOBIN\"/go;&_bootstrap;g (A) が実行されます。

    • この時点では、$GOBIN の値はすでにスラッシュ区切りのパスになっています(例: C:/Go/bin)。
    • したがって、"$GOBIN"/go というパターンは C:/Go/bin/go のように解釈され、正確にマッチして C:/Go/bin/go_bootstrap に置換されることが保証されます。

この順序変更により、Windowsパスの正規化が先に行われるため、その後の文字列置換が意図通りに機能し、Windows環境でのビルドスクリプトの信頼性が向上しました。

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

--- a/src/buildscript.sh
+++ b/src/buildscript.sh
@@ -33,8 +33,8 @@ set -e
 		s/\\$GOBIN/\"$GOBIN\"/g
 		s/\\$GOROOT/\"$GOROOT\"/g
 		s/\\$WORK/\"$WORK\"/g
-		s;\"\\$GOBIN\"/go;&_bootstrap;g
 		s;\\\\;/;g
+		s;\"\\$GOBIN\"/go;&_bootstrap;g
 		s/go_bootstrap-tool/go-tool/g
 		s;\"\\$GOBIN\"/go-tool;\"$GOROOT\"/bin/go-tool;g
 	\'

コアとなるコードの解説

変更されたのは、src/buildscript.sh 内の sed コマンドのブロックです。このブロックは、Goのビルドプロセス中に生成されるスクリプトや設定ファイル内のパスを調整するために使用されます。

元のコードでは、s;\"\\$GOBIN\"/go;&_bootstrap;g という行が s;\\\\;/;g の前にありました。 修正後のコードでは、この2行の順序が入れ替わっています。

  • s;\\\\;/;g: この行は、入力ストリーム内のすべてのバックスラッシュ \ をスラッシュ / に置換します。これは、WindowsパスをUnix形式のパスに変換する役割を果たします。
  • s;\"\\$GOBIN\"/go;&_bootstrap;g: この行は、$GOBIN 環境変数で指定されたパスに続く go という文字列を、go_bootstrap に置換します。例えば、C:/Go/bin/goC:/Go/bin/go_bootstrap に変更します。

この順序変更の重要性は、Windows環境におけるパスの扱いにあります。Windowsではパスの区切り文字としてバックスラッシュが使われますが、シェルスクリプト(特にUnix系ツールである sed)はスラッシュを期待します。

  1. 変更前: まず go のリネームが行われ、その後にバックスラッシュのスラッシュへの変換が行われます。もし $GOBINC:\Go\bin のようなパスだった場合、sedC:\Go\bin\go をパターンとして扱おうとします。このとき、バックスラッシュが正規表現の特殊文字として解釈される可能性があり、意図しないマッチングやエラーを引き起こす可能性がありました。

  2. 変更後: まずバックスラッシュがスラッシュに変換されます。これにより、C:\Go\binC:/Go/bin となり、パスがUnix形式に正規化されます。その後の go のリネーム処理では、すでに正規化されたパス(例: C:/Go/bin/go)に対してパターンマッチングが行われるため、正確かつ確実に置換が実行されます。

この修正により、Windows環境で buildscript.sh が実行される際に、パスの解釈に関する潜在的な問題が解消され、Goのビルドプロセスがより堅牢になりました。

関連リンク

参考にした情報源リンク