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

[インデックス 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つの主要な変更によってこの問題を解決しています。

  1. 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の出力がより汎用的なパス形式になり、後続の処理や異なる環境での解釈が容易になります。
  2. クロスコンパイルされたバイナリの配置場所の変更:

    • 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_386linux_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_386linux_amd64といったOS/アーキテクチャ固有のサブディレクトリを作成していました。
    • 変更後は、単に$GOBINの直下にディレクトリを作成するようになりました。これにより、バイナリの配置がフラット化され、OS/アーキテクチャに依存しないパス構造になります。
  • 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のビルドシステム、環境変数、クロスコンパイルに関する情報)
  • sedコマンドのドキュメント
  • シェルスクリプトの基本 (環境変数、mkdir, cpコマンドなど)
  • Go言語の初期のビルドプロセスに関する議論やドキュメント (Goのブートストラッププロセスに関する情報)