[インデックス 14284] ファイルの概要
このコミットは、Go言語のビルドシステムにおいて、ビルド制約(build constraint)としてコンパイラ名をサポートする変更を導入しています。これにより、特定のコンパイラ(例: gc
や gccgo
)を使用している場合にのみコンパイルされるコードを記述できるようになります。特に、gccgo
を使用する際に異なる .c
や .s
(アセンブリ) コードを条件付きでビルドする用途が想定されています。
コミット
commit f07f9de8ec65763498410bb3c8778a87317278aa
Author: Ian Lance Taylor <iant@golang.org>
Date: Thu Nov 1 11:12:15 2012 -0700
go/build: support compiler as build constraint
This supports writing different .c/.s code when using gccgo.
R=golang-dev, dsymonds, iant, rsc
CC=golang-dev
https://golang.org/cl/6823055
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f07f9de8ec65763498410bb3c8778a87317278aa
元コミット内容
このコミットの元のメッセージは以下の通りです。
go/build: support compiler as build constraint
This supports writing different .c/.s code when using gccgo.
これは、go/build
パッケージがビルド制約としてコンパイラをサポートするように変更されたことを示しています。主な目的は、gccgo
コンパイラを使用している場合に、異なる .c
(C言語) や .s
(アセンブリ言語) のソースコードを条件付きでビルドできるようにすることです。
変更の背景
Go言語のビルドシステムでは、特定の環境(OS、アーキテクチャ、Cgoの有無など)に特化したコードを条件付きでコンパイルするために「ビルド制約(build constraints)」または「ビルドタグ(build tags)」と呼ばれる仕組みが提供されています。これは、ソースファイルの先頭に // +build tag
のようなコメントを記述することで実現されます。
このコミットが導入された背景には、Go言語の公式コンパイラである gc
以外に、GCC (GNU Compiler Collection) をベースにした gccgo
という別のGoコンパイラが存在することが挙げられます。両者はGo言語の仕様に準拠していますが、内部的な実装や生成されるコードには違いがあります。
特に、C言語やアセンブリ言語で書かれたコード(通常、Goのパッケージ内でCgoを通じて利用されるか、あるいはGoランタイムの一部として組み込まれる)は、コンパイラに依存する場合があります。例えば、gc
コンパイラ用に最適化されたアセンブリコードが gccgo
では正しく動作しない、あるいはその逆の状況が考えられます。
このような状況に対応するため、開発者は特定のコンパイラを使用している場合にのみ有効になるコードパスを定義したいというニーズがありました。このコミットは、そのニーズに応えるために、ビルド制約の対象に「使用中のコンパイラ」を追加することを目的としています。これにより、gc
と gccgo
の間で異なる実装を容易に切り替えられるようになります。
前提知識の解説
Go言語のビルド制約(Build Constraints / Build Tags)
Go言語のビルド制約は、特定の条件に基づいてソースファイルをコンパイルに含めるか除外するかを制御するためのメカニズムです。これは、クロスプラットフォーム開発や、特定のハードウェア、OS、または環境に依存するコードを扱う際に非常に有用です。
ビルド制約は、Goソースファイル(.go
)、Cソースファイル(.c
)、アセンブリソースファイル(.s
)などの先頭に、// +build tag
または //go:build tag
(Go 1.17以降) の形式でコメントとして記述されます。
例:
// +build linux darwin
: LinuxまたはmacOSでのみコンパイルされる。// +build !windows
: Windows以外でコンパイルされる。// +build debug
:debug
タグが有効な場合にのみコンパイルされる(go build -tags debug
で有効化)。// +build cgo
: Cgoが有効な場合にのみコンパイルされる。
これらの制約は論理AND (
) や論理OR (,
) で組み合わせることも可能です。例えば、// +build linux,amd64
はLinuxかつAMD64アーキテクチャの場合にのみコンパイルされます。
Go言語のコンパイラ: gc
と gccgo
Go言語には主に二つの主要なコンパイラ実装が存在します。
-
gc
(Go Compiler):- これはGoプロジェクトによって開発・メンテナンスされている公式のコンパイラです。
- Go言語のソースコードを直接機械語にコンパイルします。
- Goのツールチェイン(
go build
,go run
など)のデフォルトコンパイラとして使用されます。 - 高速なコンパイルと、Goランタイムとの密接な統合が特徴です。
-
gccgo
:- GCC (GNU Compiler Collection) のフロントエンドとして実装されたGoコンパイラです。
- GCCのバックエンドを利用するため、GCCがサポートする多くのアーキテクチャや最適化技術を利用できます。
- C/C++などの他の言語とGoコードを混在させる場合に、GCCのリンカやツールチェインとの互換性が高いという利点があります。
- 通常、
gc
よりもコンパイルに時間がかかる傾向がありますが、生成されるバイナリのパフォーマンスがgc
とは異なる場合があります。
これらのコンパイラは、Goの標準ライブラリやアプリケーションのビルドにおいて、それぞれ異なる特性を持つため、特定のコンパイラに依存する低レベルなコード(特にアセンブリやCgo関連)を記述する際には、コンパイラごとの条件分岐が必要となることがあります。
技術的詳細
このコミットは、go/build
パッケージの Context
構造体と、その match
メソッドの挙動を拡張することで、コンパイラ名をビルド制約として認識できるようにしています。
go/build
パッケージは、Goのソースコードを解析し、ビルド可能なパッケージを特定するためのロジックを提供します。このパッケージは、go build
コマンドなどの基盤となっています。
変更の核心は、Context
構造体が持つビルド環境情報に、現在使用しているコンパイラの名前(gc
または gccgo
)を追加し、その名前がビルド制約として評価されるようにすることです。
具体的には、以下の点が変更されています。
Context.Compiler
フィールドの導入:Context
構造体には、現在のコンパイラ名を表す新しいフィールドが追加されたと推測されます(コミットのdiffからは直接見えませんが、ctxt.Compiler
の参照から明らかです)。このフィールドには、gc
またはgccgo
のいずれかの文字列が設定されます。Context.match
メソッドの拡張:match
メソッドは、与えられたビルド制約のタグが現在のビルドコンテキストに合致するかどうかを判定する役割を担っています。この変更により、name == ctxt.Compiler
という条件が追加され、ビルド制約のタグが現在のコンパイラ名と一致する場合にtrue
を返すようになりました。doc.go
の更新:go/build
パッケージのドキュメント(doc.go
)が更新され、ビルド制約としてコンパイラ名(gc
またはgccgo
)が利用可能になったことが明記されました。
これにより、開発者はGoのソースファイルに // +build gc
や // +build gccgo
といったコメントを記述することで、特定のコンパイラでのみコンパイルされるコードブロックを作成できるようになります。これは、特に低レベルなシステムプログラミングや、コンパイラ固有の最適化、あるいはコンパイラ間の差異を吸収するためのコードを書く際に非常に強力な機能となります。
コアとなるコードの変更箇所
このコミットによって変更されたファイルは以下の2つです。
src/pkg/go/build/build.go
src/pkg/go/build/doc.go
それぞれの変更箇所は以下の通りです。
src/pkg/go/build/build.go
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -897,6 +897,8 @@ func splitQuoted(s string) (r []string, err error) {
// $GOARCH
// cgo (if cgo is enabled)
// !cgo (if cgo is disabled)
+// ctxt.Compiler
+// !ctxt.Compiler
// tag (if tag is listed in ctxt.BuildTags)
// !tag (if tag is not listed in ctxt.BuildTags)
// a comma-separated list of any of these
@@ -928,7 +930,7 @@ func (ctxt *Context) match(name string) bool {
if ctxt.CgoEnabled && name == "cgo" {
return true
}
- if name == ctxt.GOOS || name == ctxt.GOARCH {
+ if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler {
return true
}
src/pkg/go/build/doc.go
--- a/src/pkg/go/build/doc.go
+++ b/src/pkg/go/build/doc.go
@@ -88,6 +88,7 @@
//
// - the target operating system, as spelled by runtime.GOOS
// - the target architecture, as spelled by runtime.GOARCH
+// - the compiler being used, currently either "gc" or "gccgo"
// - "cgo", if ctxt.CgoEnabled is true
// - any additional words listed in ctxt.BuildTags
//
コアとなるコードの解説
src/pkg/go/build/build.go
の変更
このファイルでは、Context
構造体の match
メソッドが変更されています。
-
変更前:
if name == ctxt.GOOS || name == ctxt.GOARCH { return true }
この行は、ビルド制約のタグ
name
が現在のOS (ctxt.GOOS
) またはアーキテクチャ (ctxt.GOARCH
) と一致する場合にtrue
を返していました。 -
変更後:
if name == ctxt.GOOS || name == ctxt.GOARCH || name == ctxt.Compiler { return true }
変更後では、既存の条件に加えて
|| name == ctxt.Compiler
が追加されています。これは、ビルド制約のタグname
が現在のコンパイラ名 (ctxt.Compiler
) と一致する場合にもtrue
を返すように拡張されたことを意味します。ctxt.Compiler
は、go/build
パッケージがビルドコンテキストを初期化する際に、現在使用されているGoコンパイラ(例:gc
またはgccgo
)の文字列を保持するフィールドです。この変更により、// +build gc
や// +build gccgo
といったビルド制約が正しく評価されるようになります。
また、コメントブロックも更新され、ctxt.Compiler
および !ctxt.Compiler
がビルド制約として利用可能になったことが示されています。
src/pkg/go/build/doc.go
の変更
このファイルは go/build
パッケージのドキュメントです。
- 追加行:
この行が追加されたことで、+// - the compiler being used, currently either "gc" or "gccgo"
go/build
パッケージのビルド制約に関する公式ドキュメントに、「使用中のコンパイラ、現在はgc
またはgccgo
のいずれか」がビルド制約として利用可能であることが明記されました。これにより、開発者はこの新しい機能の存在と使用方法をドキュメントを通じて知ることができます。
これらの変更により、Goのビルドシステムは、OSやアーキテクチャだけでなく、使用しているコンパイラの種類に基づいてコードのコンパイルを条件付けできるようになり、より柔軟なクロスコンパイラ開発が可能になりました。
関連リンク
- Go言語のビルド制約に関する公式ドキュメント(Go 1.17以降の
//go:build
構文を含む): - Go言語のコンパイラ
gc
とgccgo
について: - Goのコードレビューシステム (Gerrit) の変更リスト:
参考にした情報源リンク
- Go言語の公式ドキュメント
- Go言語のソースコードリポジトリ
- Go言語のビルド制約に関する一般的な情報源
- GCCGoに関する情報源