[インデックス 11518] ファイルの概要
このコミットは、Go言語のコマンドラインツール cmd/go における gccgo 標準ライブラリの取り扱いに関するバグ修正です。具体的には、go ツールが gccgo を使用して標準ライブラリをビルドしようとするのを防ぐためのロジックが導入されています。
コミット
commit d7172084d09b845a5decdbe97ee39f02cfe1cd03
Author: Rémy Oudompheng <oudomphe@phare.normalesup.org>
Date: Tue Jan 31 19:41:38 2012 +0100
cmd/go: fix handling of gccgo standard library.
The previous logic was mainly non-working. It only needs to
ensure that the go tool doesn't try to build the standard
library with gccgo.
R=golang-dev, rsc
CC=golang-dev, remy
https://golang.org/cl/5580051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/d7172084d09b845a5decdbe97ee39f02cfe1cd03
元コミット内容
cmd/go: fix handling of gccgo standard library.
The previous logic was mainly non-working. It only needs to ensure that the go tool doesn't try to build the standard library with gccgo.
変更の背景
Go言語には、公式のGoコンパイラ(gc)と、GCC(GNU Compiler Collection)をベースにしたgccgoという2つの主要なコンパイラ実装が存在します。goコマンド(cmd/go)は、Goプロジェクトのビルド、テスト、インストールなどを管理するための主要なツールです。
このコミットが行われた2012年当時、goツールはgccgoツールチェインを使用している場合に、標準ライブラリのビルドを不適切に扱っていました。gccgoは通常、独自の標準ライブラリのバージョンを管理しており、goツールがそれを再ビルドしようとすると、不要な処理やエラーが発生する可能性がありました。
コミットメッセージによると、「以前のロジックはほとんど機能していなかった」とあり、goツールがgccgoで標準ライブラリをビルドしようとしないようにすることが唯一の要件であったことが示唆されています。これは、gccgoが既にコンパイル済みの標準ライブラリを提供しているため、goツールがその部分に介入する必要がないという設計思想に基づいています。
前提知識の解説
- Goツールチェイン: Go言語のプログラムを開発・実行するために必要な一連のツール群を指します。これには、コンパイラ(
gcまたはgccgo)、アセンブラ、リンカ、デバッガ、そしてgoコマンド自体が含まれます。 cmd/go: Go言語のビルドシステムの中核をなすコマンドラインツールです。ソースコードのコンパイル、パッケージの管理、テストの実行、依存関係の解決など、Go開発における多くのタスクを自動化します。gc(Go Compiler): Go言語の公式かつ主要なコンパイラです。Go言語のソースコードをネイティブバイナリにコンパイルします。gccgo: GCCのフロントエンドとして実装されたGo言語のコンパイラです。gcとは異なるコンパイラバックエンドを使用するため、生成されるバイナリの特性や最適化が異なる場合があります。gccgoはGCCの既存の最適化インフラストラクチャを活用できるという利点があります。- 標準ライブラリ: Go言語に標準で付属する豊富なパッケージ群です。ファイルI/O、ネットワーク通信、暗号化、データ構造など、様々な機能を提供します。これらのライブラリは通常、Goツールチェインのインストール時に事前にコンパイルされた形式で提供されます。
buildMode:cmd/go内部で使用される概念で、ビルドのモード(例: 通常のビルド、テストビルドなど)を定義します。Package: Goのソースコードの単位であり、関連するGoファイルとリソースの集合です。action:cmd/goが実行するビルドアクションを表す内部構造体です。buildToolchain: 現在使用されているGoツールチェイン(gcまたはgccgo)を表すインターフェースまたは構造体です。gccgoToolchain:buildToolchainインターフェースを実装するgccgo固有のツールチェインを表す型です。p.Standard:Package構造体のフィールドで、そのパッケージがGoの標準ライブラリの一部であるかどうかを示すブール値です。p.target: ビルドされたパッケージの出力パス(ターゲットファイル名)です。
技術的詳細
このコミットは、cmd/goがgccgoツールチェインを使用している場合に、標準ライブラリのビルドプロセスをスキップするように変更します。
以前のロジックでは、pkg.go内で標準ライブラリ(p.Standardがtrue)かつgccgoToolchainが使用されている場合に、p.targetをgoToolchain{}.pkgpath(dir, p)に設定し直していました。これは、gccgoが標準ライブラリを「通常の」Goツールチェインが配置する場所と同じ場所にインストールするという前提に基づいていたようです。しかし、このロジックは「ほとんど機能していなかった」とされており、goツールがgccgoの標準ライブラリをビルドしようとするのを防ぐという本来の目的を達成できていませんでした。
新しいロジックでは、build.goのaction関数内で、パッケージが標準ライブラリ(p.Standardがtrue)であり、かつgccgoToolchainが使用されている場合に、ビルドアクションを早期に終了させるように変更されています。具体的には、action構造体のtargetフィールドにp.targetを設定し、そのままactionを返します。これにより、goツールはgccgoの標準ライブラリに対して実際のビルド操作を行わず、「フェイクパッケージ」(ビルド不要なパッケージ)として扱います。cgo(C言語との連携)を使用する場合にはターゲット名が必要となるため、a.target = p.targetという行が追加されています。
この変更により、goツールはgccgoの標準ライブラリに対して不必要なビルド試行を行わなくなり、ビルドプロセスの効率化と安定化が図られます。
コアとなるコードの変更箇所
このコミットでは、以下の2つのファイルが変更されています。
-
src/cmd/go/build.go:func (b *builder) action(...)メソッド内に新しいロジックが追加されました。- 標準ライブラリかつ
gccgoToolchainの場合に、ビルドをスキップする条件が追加されています。
-
src/cmd/go/pkg.go:func scanPackage(...)メソッドから、gccgoの標準ライブラリに関する古いロジックが削除されました。
src/cmd/go/build.go の変更点
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -349,6 +349,12 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
// Fake packages - nothing to build.
return a
}
+ // gccgo standard library is "fake" too.
+ if _, ok := buildToolchain.(gccgoToolchain); ok {
+ // the target name is needed for cgo.
+ a.target = p.target
+ return a
+ }
}
if !p.Stale && !buildA && p.target != "" {
src/cmd/go/pkg.go の変更点
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -295,14 +295,6 @@ func scanPackage(ctxt *build.Context, t *build.Tree, arg, importPath, dir string
dir = filepath.Join(filepath.Dir(dir), "gccgo", filepath.Base(dir))
}
p.target = buildToolchain.pkgpath(dir, p)
-
- // NB. Currently we have gccgo install the standard libraries
- // in the "usual" location, where the Go toolchain puts them.
- if p.Standard {
- if _, ok := buildToolchain.(gccgoToolchain); ok {
- p.target = goToolchain{}.pkgpath(dir, p)
- }
- }
}
var built time.Time
コアとなるコードの解説
src/cmd/go/build.go の変更
action関数は、特定のパッケージに対して実行すべきビルドアクションを決定します。
追加されたコードブロックは以下の通りです。
// gccgo standard library is "fake" too.
if _, ok := buildToolchain.(gccgoToolchain); ok {
// the target name is needed for cgo.
a.target = p.target
return a
}
if _, ok := buildToolchain.(gccgoToolchain); ok: これは型アサーションと型スイッチの組み合わせです。現在使用されているbuildToolchainがgccgoToolchain型であるかどうかをチェックしています。okがtrueであれば、gccgoが使用されていることを意味します。- この
ifブロックは、外側のif p.Standardブロック(変更前のコードのコンテキストから推測)の内側に存在するため、このロジックは「標準ライブラリ」かつ「gccgoツールチェイン」の場合にのみ適用されます。 a.target = p.target:action構造体のtargetフィールドに、現在のパッケージのターゲットパスを設定します。これは、cgoを使用する場合に必要となる情報です。return a: この行が重要です。この行により、gccgoの標準ライブラリに対するビルド処理がここで早期に終了し、それ以降の実際のビルドステップがスキップされます。これにより、goツールはgccgoの標準ライブラリを「ビルド不要なもの」として扱います。
src/cmd/go/pkg.go の変更
scanPackage関数は、パッケージの情報をスキャンし、そのターゲットパスなどを決定します。
削除されたコードブロックは以下の通りです。
// NB. Currently we have gccgo install the standard libraries
// in the "usual" location, where the Go toolchain puts them.
if p.Standard {
if _, ok := buildToolchain.(gccgoToolchain); ok {
p.target = goToolchain{}.pkgpath(dir, p)
}
}
- このコードは、
gccgoが標準ライブラリをgcツールチェインと同じ場所にインストールするという前提に基づいて、gccgo使用時に標準ライブラリのターゲットパスをgoToolchainのパスに上書きしていました。 - コミットメッセージにある「The previous logic was mainly non-working.」という記述から、このロジックが意図した通りに機能していなかったか、あるいは
goツールがgccgoの標準ライブラリをビルドしようとするのを防ぐという目的には不適切であったことが示唆されます。 - このコードを削除することで、
goツールはgccgoの標準ライブラリのターゲットパスを特別に操作する必要がなくなり、build.goで導入された新しい早期終了ロジックに一貫性がもたらされます。
これらの変更により、goツールはgccgoツールチェインを使用している場合に、標準ライブラリのビルドを適切にスキップし、gccgoが提供する既存の標準ライブラリを使用するようになります。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- GCCGoプロジェクトページ: https://gcc.gnu.org/onlinedocs/gccgo/
- Goのビルドシステムに関する議論(古いものも含む)は、GoのメーリングリストやIssueトラッカーで確認できます。
参考にした情報源リンク
- Go言語のソースコード(特に
src/cmd/goディレクトリ) - Go言語のコミット履歴
- Go言語のメーリングリスト(golang-dev)のアーカイブ
- GCCGoのドキュメント