[インデックス 11499] ファイルの概要
このコミットは、Go言語のビルドシステムにおけるクロスコンパイルの問題を修正するものです。具体的には、新しいクロスコンパイルのバイナリターゲットが、buildscript.sh
が実行されたシステム以外でビルドを壊してしまう問題を解決しています。
コミット
commit fdb80ea1801889c804907007b980b4fb21b647b8
Author: Russ Cox <rsc@golang.org>
Date: Tue Jan 31 00:06:33 2012 -0500
build: fix again
The new cross-compiling bin target was breaking
everything but the system where buildscript.sh ran.
TBR=golang-dev
CC=golang-dev
https://golang.org/cl/5598055
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fdb80ea1801889c804907007b980b4fb21b647b8
元コミット内容
このコミットは、Go言語のビルドプロセスにおける以前の修正("fix again")をさらに修正するものです。以前の修正で導入された新しいクロスコンパイルのバイナリターゲットが、buildscript.sh
が実行された環境(ホストシステム)以外でのビルドを失敗させるという問題が発生していました。このコミットは、その問題を解決することを目的としています。
変更の背景
Go言語は、異なるオペレーティングシステムやアーキテクチャ向けにバイナリを生成する「クロスコンパイル」機能を強力にサポートしています。Goのビルドシステムは、GOROOT
(Goのインストールディレクトリ)やGOBIN
(Goのバイナリがインストールされるディレクトリ)といった環境変数を利用して、ビルドされたツールやバイナリの配置を管理します。
このコミットが行われた当時、Goのビルドシステムに新しいクロスコンパイルのバイナリターゲットが導入されました。しかし、この変更には副作用があり、buildscript.sh
というビルドスクリプトが実行されるホストシステム上では問題なく動作するものの、それ以外のターゲットシステム(例えば、WindowsマシンでLinux向けバイナリをビルドする場合のLinux環境)ではビルドが失敗するという問題が発生していました。これは、ビルドスクリプト内で生成されるパスが、ホストシステムのパス形式に依存してしまい、ターゲットシステムでは不正なパスとして扱われたためと考えられます。
このコミットは、このクロスコンパイル時のパス解決の問題を修正し、Goのビルドシステムがより堅牢に、様々な環境でクロスコンパイルを行えるようにするために導入されました。
前提知識の解説
このコミットを理解するためには、以下のGo言語のビルドシステムと関連する概念についての知識が必要です。
- Go言語のビルドプロセス: Go言語のソースコードから実行可能なバイナリを生成する一連のプロセス。これには、コンパイル、リンク、そして必要に応じてブートストラップ(自己ホスト型コンパイラをビルドするプロセス)が含まれます。
- クロスコンパイル (Cross-compilation): あるプラットフォーム(ホスト)上で、別のプラットフォーム(ターゲット)向けの実行可能ファイルをビルドするプロセス。Goは
GOOS
(ターゲットOS)とGOARCH
(ターゲットアーキテクチャ)環境変数を設定することで、簡単にクロスコンパイルが可能です。 GOROOT
: Goのインストールディレクトリを指す環境変数。Goの標準ライブラリやツールチェーン(コンパイラ、リンカなど)がここに配置されます。GOBIN
:go install
コマンドでビルドされた実行可能ファイルがインストールされるディレクトリを指す環境変数。通常、$GOPATH/bin
または$GOROOT/bin
に設定されます。buildscript.sh
: Goのソースコードリポジトリに含まれる、Goのツールチェーン全体をビルドするためのシェルスクリプト。Goの初期バージョンでは、このスクリプトがGoのコンパイラやその他のツールをブートストラップするために重要な役割を果たしていました。go install
: Goのパッケージをコンパイルし、インストールするコマンド。実行可能ファイルの場合はGOBIN
に、ライブラリの場合はpkg
ディレクトリにインストールされます。sed
: Stream EDitorの略で、テキストストリームに対して変換を行うコマンドラインユーティリティ。正規表現を用いて文字列の置換などを行います。このコミットでは、ビルドスクリプト内で生成されるパスの形式を調整するために使用されています。- Goツールチェーンのコンポーネント:
8g
,6g
,5g
: Goの初期のコンパイラ。8g
は386アーキテクチャ(32-bit x86)、6g
はamd64アーキテクチャ(64-bit x86)、5g
はARMアーキテクチャ向けのコンパイラでした。現在ではgo tool compile
に統合されています。8l
,6l
,5l
: Goの初期のリンカ。コンパイラと同様に、それぞれ対応するアーキテクチャ向けのリンカでした。現在ではgo tool link
に統合されています。pack
: Goのアーカイブツール。オブジェクトファイルやライブラリを.a
ファイル(アーカイブファイル)にまとめるために使用されました。現在ではgo tool pack
に統合されています。
mkdir -p
: ディレクトリを作成するコマンド。-p
オプションは、親ディレクトリが存在しない場合でも、それらも同時に作成します。cp
: ファイルやディレクトリをコピーするコマンド。
技術的詳細
このコミットの核心は、Goのビルドプロセスにおけるパスの正規化と、クロスコンパイルされたバイナリの配置方法の変更にあります。
以前のビルドシステムでは、クロスコンパイルされたバイナリ(例えば、go_bootstrap
)が、$GOBIN/OS_ARCH/
のようなOSとアーキテクチャ固有のサブディレクトリに配置されていました。例えば、darwin_386
(macOS 32-bit)向けのバイナリは$GOBIN/darwin_386/go
に、linux_amd64
(Linux 64-bit)向けのバイナリは$GOBIN/linux_amd64/go
に配置されていました。
このアプローチは、buildscript.sh
が実行されるホストシステム上では問題なく機能しましたが、クロスコンパイルのシナリオでは問題を引き起こしました。具体的には、go install
コマンドが生成する内部的なパスや、buildscript.sh
内でsed
コマンドによって処理されるパス文字列が、ホストシステムのパス区切り文字(Unix系では/
、Windowsでは\
)や、$GOBIN
の構造に依存しすぎていたため、ターゲットシステムでのビルドが失敗していました。
このコミットでは、以下の2つの主要な変更によってこの問題を解決しています。
-
buildscript.sh
におけるパスの正規化の順序変更と追加:- 以前は、
go install
の出力に対して、まずs;\\;/;g
(バックスラッシュをスラッシュに置換)を実行し、その後に$GOBIN
のパスを引用符で囲む処理を行っていました。 - このコミットでは、
s;\\;/;g
を最初に移動し、さらに新しいsed
コマンドs;\\$GOBIN/[a-z0-9]*_[a-z0-9]*/;\\$GOBIN/;g
を追加しています。この新しいsed
コマンドは、$GOBIN/OS_ARCH/
のようなOSとアーキテクチャ固有のサブディレクトリパスを、単に$GOBIN/
に正規化する役割を果たします。これにより、go install
が生成する内部パスが、OS/アーキテクチャに依存しない形式に統一されます。 - この変更により、
go install
の出力がより汎用的なパス形式になり、後続の処理や異なる環境での解釈が容易になります。
- 以前は、
-
クロスコンパイルされたバイナリの配置場所の変更:
- 各
src/buildscript/OS_ARCH.sh
ファイルにおいて、mkdir -p "$GOBIN"/OS_ARCH/
というOS/アーキテクチャ固有のサブディレクトリを作成する行が削除され、代わりにmkdir -p "$GOBIN"/
というGOBIN
直下にディレクトリを作成する行に変更されています。 - 同様に、
cp "$WORK"/cmd/go/_obj/a.out "$GOBIN"/OS_ARCH/go
(またはWindowsの場合はgo.exe
)という、OS/アーキテクチャ固有のサブディレクトリにバイナリをコピーする行が、cp "$WORK"/cmd/go/_obj/a.out "$GOBIN"/go_bootstrap
(またはWindowsの場合はgo_bootstrap.exe
)という、GOBIN
直下にgo_bootstrap
という名前でコピーする行に変更されています。 - この変更により、クロスコンパイルされたブートストラップGoバイナリ(
go_bootstrap
)は、OSやアーキテクチャに関わらず、常に$GOBIN
の直下に配置されるようになります。これにより、ビルドスクリプトが特定のOS/アーキテクチャのサブディレクトリ構造に依存する必要がなくなり、クロスコンパイルの堅牢性が向上します。
- 各
これらの変更は、Goのビルドシステムが、ホストシステムとターゲットシステムの間でパスの解釈に一貫性を持たせ、クロスコンパイルのプロセスをよりスムーズに行えるようにするために不可欠でした。
コアとなるコードの変更箇所
src/buildscript.sh
--- a/src/buildscript.sh
+++ b/src/buildscript.sh
@@ -30,10 +30,11 @@ set -e
# as a shell escape but also makes sure that we generate the
# same scripts on Unix and Windows systems.
go install -a -n -t cmd_go_bootstrap cmd/go | sed '
+\t\ts;\\\\;/;g
+\t\ts;\\$GOBIN/[a-z0-9]*_[a-z0-9]*/;\\$GOBIN/;g
\t\ts/\\$GOBIN/\"$GOBIN\"/g
\t\ts/\\$GOROOT/\"$GOROOT\"/g
\t\ts/\\$WORK/\"$WORK\"/g
-\t\ts;\\\\;/;g
\t\ts;\"\\$GOBIN\"/go;&_bootstrap;g
\t\ts/go_bootstrap-tool/go-tool/g
\t\ts;\"\\$GOBIN\"/go-tool;\"$GOROOT\"/bin/go-tool;g
src/buildscript/darwin_386.sh
(代表例)
--- a/src/buildscript/darwin_386.sh
+++ b/src/buildscript/darwin_386.sh
@@ -494,5 +494,5 @@ cd "$GOROOT"/src/cmd/go
"$GOROOT"/bin/go-tool/8g -o "$WORK"/cmd/go/_obj/_go_.8 -p cmd/go -I "$WORK" ./bootstrap.go ./build.go ./clean.go ./fix.go ./fmt.go ./get.go ./help.go ./list.go ./main.go ./pkg.go ./run.go ./test.go ./testflag.go ./tool.go ./vcs.go ./version.go ./vet.go
"$GOROOT"/bin/go-tool/pack grc "$WORK"/cmd/go.a "$WORK"/cmd/go/_obj/_go_.8
"$GOROOT"/bin/go-tool/8l -o "$WORK"/cmd/go/_obj/a.out -L "$WORK" "$WORK"/cmd/go.a
-mkdir -p "$GOBIN"/darwin_386/
-cp "$WORK"/cmd/go/_obj/a.out "$GOBIN"/darwin_386/go
+mkdir -p "$GOBIN"/
+cp "$WORK"/cmd/go/_obj/a.out "$GOBIN"/go_bootstrap
他のsrc/buildscript/*.sh
ファイルも同様の変更が適用されています。
コアとなるコードの解説
src/buildscript.sh
の変更点
このファイルでは、go install
コマンドの出力(Goのビルドプロセスで生成される内部的なシェルコマンドのリスト)をsed
コマンドでパイプ処理し、パスの変換を行っています。
s;\\\\;/;g
の移動: 以前はs;\\\\;/;g
(バックスラッシュをスラッシュに置換)が後の方にありましたが、これが一番最初に移動されました。これにより、Windowsパス形式(C:\path\to\file
)のようなバックスラッシュを含むパスが、他のsed
処理の前にUnix形式(C:/path/to/file
)に変換され、後続の正規表現処理がより一貫して行えるようになります。s;\\$GOBIN/[a-z0-9]*_[a-z0-9]*/;\\$GOBIN/;g
の追加:- この正規表現は、
$GOBIN/
の後に続く「OS名_アーキテクチャ名/」のようなパターン(例:darwin_386/
,linux_amd64/
)を捕捉し、それを削除して単に$GOBIN/
に置換します。 [a-z0-9]*_[a-z0-9]*
は、darwin_386
やlinux_amd64
のようなパターンにマッチします。- この置換により、
go install
が生成するパス文字列から、OS/アーキテクチャ固有のサブディレクトリ情報が取り除かれ、パスが正規化されます。これは、クロスコンパイルされたバイナリが特定のサブディレクトリに依存しないようにするための重要なステップです。
- この正規表現は、
これらのsed
コマンドの変更により、go install
が生成するビルドコマンドのパスが、クロスコンパイル環境においてより汎用的かつ正確に解釈されるようになります。
src/buildscript/OS_ARCH.sh
ファイル群の変更点
これらのファイルは、特定のOSとアーキテクチャ向けのGoツールチェーンのブートストラップビルドプロセスを定義するシェルスクリプトです。
mkdir -p "$GOBIN"/OS_ARCH/
からmkdir -p "$GOBIN"/
への変更:- 以前は、ビルドされたGoバイナリを格納するために、
$GOBIN
の下にdarwin_386
やlinux_amd64
といったOS/アーキテクチャ固有のサブディレクトリを作成していました。 - 変更後は、単に
$GOBIN
の直下にディレクトリを作成するようになりました。これにより、バイナリの配置がフラット化され、OS/アーキテクチャに依存しないパス構造になります。
- 以前は、ビルドされたGoバイナリを格納するために、
cp "$WORK"/cmd/go/_obj/a.out "$GOBIN"/OS_ARCH/go
からcp "$WORK"/cmd/go/_obj/a.out "$GOBIN"/go_bootstrap
への変更:- 以前は、コンパイルされたブートストラップGoバイナリ(
a.out
またはa.out.exe
)を、OS/アーキテクチャ固有のサブディレクトリにgo
(またはgo.exe
)という名前でコピーしていました。 - 変更後は、このバイナリを
$GOBIN
の直下にgo_bootstrap
(またはgo_bootstrap.exe
)という名前でコピーするようになりました。 go_bootstrap
という名前は、これがGoツールチェーンのブートストラップバージョンであることを明確に示しています。この変更とbuildscript.sh
でのパス正規化が連携することで、ビルドシステム全体でgo_bootstrap
バイナリへの参照が一貫して行われるようになります。
- 以前は、コンパイルされたブートストラップGoバイナリ(
これらの変更は、Goのビルドシステムがクロスコンパイルされたバイナリをより適切に管理し、異なる環境間でのパスの不整合を解消するために不可欠でした。
関連リンク
参考にした情報源リンク
- Go言語の公式ドキュメント (Goのビルドシステム、環境変数、クロスコンパイルに関する情報)
sed
コマンドのドキュメント- シェルスクリプトの基本 (環境変数、
mkdir
,cp
コマンドなど) - Go言語の初期のビルドプロセスに関する議論やドキュメント (Goのブートストラッププロセスに関する情報)