[インデックス 11933] ファイルの概要
このコミットは、Go言語のビルドツールである cmd/dist
におけるクロスコンパイル時のパッケージターゲットパスの指定に関する修正です。具体的には、Goライブラリ(パッケージ)のインストールパスを決定する際に、ホスト環境のOSとアーキテクチャ(gohostos
, gohostarch
)ではなく、ターゲット環境のOSとアーキテクチャ(goos
, goarch
)を使用するように変更しています。これにより、クロスコンパイルされたバイナリが正しいディレクトリに配置され、Goのビルドシステムが期待通りに動作するようになります。
コミット
commit def2022bc08f0326503df4f661eeaca3809dd5f0
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Wed Feb 15 09:02:45 2012 -0500
cmd/dist: use correct package target when cross-compiling
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5672050
---
src/cmd/dist/build.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
index e115e3c322..67860cdf33 100644
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -605,10 +605,10 @@ install(char *dir)
// Go library (package).
vadd(&link, bpathf(&b, "%s/pack", tooldir));
vadd(&link, "grc");
- p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, gohostos, gohostarch, dir+4);
+ p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4);
*xstrrchr(p, '/') = '\0';
xmkdirall(p);
- vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, gohostos, gohostarch, dir+4));
+ vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir+4));
} else if(streq(dir, "cmd/go") || streq(dir, "cmd/cgo")) {
// Go command.
vadd(&link, bpathf(&b, "%s/%sl", tooldir, gochar));
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/def2022bc08f0326503df4f661eeaca3809dd5f0
元コミット内容
このコミットの目的は、Go言語のビルドシステムの一部である cmd/dist
ツールが、クロスコンパイル時にGoライブラリ(パッケージ)をインストールする際のターゲットディレクトリを正しく決定するように修正することです。以前は、ホスト環境のOSとアーキテクチャ(gohostos
, gohostarch
)に基づいてパスを構築していましたが、これはクロスコンパイルのシナリオでは誤りでした。クロスコンパイルでは、生成されるバイナリはターゲット環境向けであるため、そのパッケージはターゲット環境のOSとアーキテクチャ(goos
, goarch
)に対応するディレクトリに配置されるべきです。この修正により、Goのビルドプロセスにおけるクロスコンパイルの正確性が向上します。
変更の背景
Go言語は、異なるオペレーティングシステムやCPUアーキテクチャ向けにバイナリを生成する「クロスコンパイル」機能を強力にサポートしています。GoのソースコードからGoコンパイラや標準ライブラリをビルドする際には、cmd/dist
ツールが中心的な役割を担います。
このコミットが行われた2012年当時、Goのビルドシステムはまだ進化の途中にありました。クロスコンパイルの際に、Goの標準ライブラリやユーザーが作成したパッケージのアーカイブファイル(.a
ファイル)が GOROOT/pkg
ディレクトリ以下に配置されます。この配置パスは通常、$GOROOT/pkg/$GOOS_$GOARCH/
の形式を取ります。
しかし、このコミット以前の cmd/dist
の実装では、クロスコンパイル時にパッケージのインストールディレクトリを決定する際に、誤ってビルドを実行している「ホスト」環境のOSとアーキテクチャ(gohostos
, gohostarch
)を使用していました。例えば、Linux上でWindows向けのGoバイナリをクロスコンパイルする場合、生成されるパッケージは pkg/linux_amd64/
のようなホスト環境のディレクトリに置かれてしまっていました。これは、Windows向けのパッケージが pkg/windows_amd64/
のようなターゲット環境のディレクトリに置かれるべきというGoのビルドシステムの期待と矛盾します。
この不整合は、クロスコンパイルされたGoプログラムが正しくリンクできなかったり、Goツールチェインが期待通りに動作しなかったりする原因となります。このコミットは、この問題を解決し、クロスコンパイルされたパッケージが常に正しいターゲット環境のディレクトリに配置されるようにするために導入されました。
前提知識の解説
Goのビルドシステムと cmd/dist
Go言語のビルドシステムは非常に洗練されており、特にクロスコンパイルの容易さが特徴です。
GOROOT
: Goのインストールディレクトリのルートパスを指す環境変数です。Goの標準ライブラリやツールチェインがここに配置されます。GOPATH
: Goのワークスペースのルートパスを指す環境変数です。ユーザーが開発するGoプロジェクトのソースコード、パッケージ、バイナリがここに配置されます。cmd/dist
: GoのソースコードからGoコンパイラ、アセンブラ、リンカ、標準ライブラリなどをビルドし、インストールするための内部ツールです。Goのリリースビルドや、ユーザーがGoのソースからGoをビルドする際に使用されます。make.bash
(Unix系) やmake.bat
(Windows) スクリプトの内部で呼び出されます。
クロスコンパイルと環境変数
Goは、GOOS
と GOARCH
という環境変数を設定することで、簡単にクロスコンパイルを行うことができます。
GOOS
: ターゲットとなるオペレーティングシステム(例:linux
,windows
,darwin
,freebsd
など)。GOARCH
: ターゲットとなるCPUアーキテクチャ(例:amd64
,arm
,arm64
,386
など)。
これらの変数を設定して go build
や go install
を実行すると、指定されたOSとアーキテクチャ向けのバイナリが生成されます。
一方で、Goのビルドプロセスには、ビルドを実行している「ホスト」環境を示すための内部的な変数も存在します。
GOHOSTOS
: ビルドを実行しているホストのオペレーティングシステム。GOHOSTARCH
: ビルドを実行しているホストのCPUアーキテクチャ。
これらの変数は、Goツールチェイン自体をビルドする際に、ホスト環境に依存するツール(例: cmd/dist
の一部)の動作を制御するために使用されます。しかし、生成される「ターゲット」バイナリやパッケージのパスを決定する際には、GOOS
と GOARCH
を使用するのが正しい挙動です。
Goのパッケージパス
Goのビルドシステムでは、コンパイルされたGoパッケージのアーカイブファイル(通常 .a
拡張子を持つ)は、$GOROOT/pkg/$GOOS_$GOARCH/
ディレクトリ以下に配置されます。例えば、Linux AMD64向けのパッケージは $GOROOT/pkg/linux_amd64/
に、Windows AMD64向けのパッケージは $GOROOT/pkg/windows_amd64/
に格納されます。これにより、Goツールチェインは特定のターゲット環境向けのパッケージを効率的に見つけることができます。
技術的詳細
このコミットは、src/cmd/dist/build.c
ファイル内の install
関数に焦点を当てています。この関数は、Goの標準ライブラリやその他のGoパッケージをビルドし、適切なディレクトリにインストールする役割を担っています。
問題の箇所は、Goライブラリ(パッケージ)のインストールパスを構築する部分です。Goのパッケージは、$GOROOT/pkg/$GOOS_$GOARCH/
という形式のディレクトリに配置されることが期待されます。ここで $GOOS
と $GOARCH
は、そのパッケージが対象とするOSとアーキテクチャを示します。
しかし、修正前のコードでは、このパスを構築する際に gohostos
と gohostarch
という変数が使用されていました。これらの変数は、Goのビルドを実行している「ホスト」環境のOSとアーキテクチャを表します。
例えば、Linux (ホスト) 上でWindows (ターゲット) 向けのGoをビルドする場合、
gohostos
はlinux
gohostarch
はamd64
(またはホストのアーキテクチャ)goos
はwindows
goarch
はamd64
(またはターゲットのアーキテクチャ)
となります。
修正前のコードでは、パッケージのパスが $GOROOT/pkg/linux_amd64/...
のように構築されてしまい、これはWindows向けのパッケージとしては不適切でした。
このコミットでは、gohostos
を goos
に、gohostarch
を goarch
に置き換えることで、生成されるパッケージが常にターゲット環境のOSとアーキテクチャに対応するディレクトリに配置されるように修正しています。これにより、クロスコンパイルされたGoツールチェインが、自身が生成するパッケージを正しく管理できるようになります。
bprintf
は、Goの内部ビルドツールで使用される文字列フォーマット関数で、bpathf
はパスをフォーマットするためのヘルパー関数です。xmkdirall
はディレクトリを再帰的に作成する関数、xstrrchr
は文字列内で指定された文字の最後の出現位置を検索する関数です。これらの関数は、Goのビルドシステム内でパスの構築やディレクトリの作成を行うために利用されています。
コアとなるコードの変更箇所
--- a/src/cmd/dist/build.c
+++ b/src/cmd/dist/build.c
@@ -605,10 +605,10 @@ install(char *dir)
// Go library (package).\n vadd(&link, bpathf(&b, "%s/pack", tooldir));\n vadd(&link, "grc");\n- p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, gohostos, gohostarch, dir+4);\n+ p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4);\n *xstrrchr(p, '/') = '\0';\n xmkdirall(p);\n- vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, gohostos, gohostarch, dir+4));\n+ vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir+4));
コアとなるコードの解説
変更は src/cmd/dist/build.c
ファイルの install
関数内の2行に集中しています。
-
ディレクトリパスの構築:
- p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, gohostos, gohostarch, dir+4); + p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir+4);
この行は、Goパッケージがインストールされるディレクトリのパスを構築しています。
goroot
: Goのインストールルートディレクトリ。%s/pkg/
:goroot
の下のpkg
ディレクトリ。%s_%s/
: ここが変更点です。- 変更前:
gohostos
とgohostarch
を使用していました。これはビルドを実行しているホストのOSとアーキテクチャです。 - 変更後:
goos
とgoarch
を使用しています。これらはビルドのターゲットとなるOSとアーキテクチャです。
- 変更前:
%s
: パッケージの相対パス(dir+4
はsrc/
を取り除いた部分)。
この変更により、例えばWindows向けのパッケージをLinux上でクロスコンパイルする場合、パスは
GOROOT/pkg/windows_amd64/
のように正しく構築されるようになります。*xstrrchr(p, '/') = '\0';
は、パスの最後のスラッシュ以降をヌル終端してディレクトリ部分のみを取得し、xmkdirall(p);
でそのディレクトリを作成しています。 -
アーカイブファイルパスの構築:
- vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, gohostos, gohostarch, dir+4)); + vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir+4));
この行は、コンパイルされたGoパッケージのアーカイブファイル(
.a
)の最終的なパスを構築し、それをリンカに渡すためのlink
リストに追加しています。 ここでも同様に、gohostos
とgohostarch
がgoos
とgoarch
に置き換えられています。これにより、生成されるアーカイブファイルが、ターゲット環境に対応する正しいディレクトリに配置されることが保証されます。
これらの変更は、Goのクロスコンパイル機能の正確性と信頼性を向上させる上で非常に重要です。これにより、Goのビルドシステムは、異なるプラットフォーム向けのバイナリとパッケージをより一貫性のある方法で管理できるようになりました。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Goのクロスコンパイルに関する情報: https://go.dev/doc/install/source#environment (環境変数
GOOS
とGOARCH
について) - Goのソースコードリポジトリ: https://github.com/golang/go
参考にした情報源リンク
- Goの公式ドキュメントおよびソースコード
- Goのビルドシステムに関するコミュニティの議論やブログ記事 (具体的なURLは時間の経過により変動するため、一般的な情報源として記載)
- Goの環境変数に関するStack OverflowなどのQ&Aサイト