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

[インデックス 14284] ファイルの概要

このコミットは、Go言語のビルドシステムにおいて、ビルド制約(build constraint)としてコンパイラ名をサポートする変更を導入しています。これにより、特定のコンパイラ(例: gcgccgo)を使用している場合にのみコンパイルされるコードを記述できるようになります。特に、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 では正しく動作しない、あるいはその逆の状況が考えられます。

このような状況に対応するため、開発者は特定のコンパイラを使用している場合にのみ有効になるコードパスを定義したいというニーズがありました。このコミットは、そのニーズに応えるために、ビルド制約の対象に「使用中のコンパイラ」を追加することを目的としています。これにより、gcgccgo の間で異なる実装を容易に切り替えられるようになります。

前提知識の解説

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言語のコンパイラ: gcgccgo

Go言語には主に二つの主要なコンパイラ実装が存在します。

  1. gc (Go Compiler):

    • これはGoプロジェクトによって開発・メンテナンスされている公式のコンパイラです。
    • Go言語のソースコードを直接機械語にコンパイルします。
    • Goのツールチェイン(go build, go run など)のデフォルトコンパイラとして使用されます。
    • 高速なコンパイルと、Goランタイムとの密接な統合が特徴です。
  2. 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)を追加し、その名前がビルド制約として評価されるようにすることです。

具体的には、以下の点が変更されています。

  1. Context.Compiler フィールドの導入: Context 構造体には、現在のコンパイラ名を表す新しいフィールドが追加されたと推測されます(コミットのdiffからは直接見えませんが、ctxt.Compiler の参照から明らかです)。このフィールドには、gc または gccgo のいずれかの文字列が設定されます。
  2. Context.match メソッドの拡張: match メソッドは、与えられたビルド制約のタグが現在のビルドコンテキストに合致するかどうかを判定する役割を担っています。この変更により、name == ctxt.Compiler という条件が追加され、ビルド制約のタグが現在のコンパイラ名と一致する場合に true を返すようになりました。
  3. doc.go の更新: go/build パッケージのドキュメント(doc.go)が更新され、ビルド制約としてコンパイラ名(gc または gccgo)が利用可能になったことが明記されました。

これにより、開発者はGoのソースファイルに // +build gc// +build gccgo といったコメントを記述することで、特定のコンパイラでのみコンパイルされるコードブロックを作成できるようになります。これは、特に低レベルなシステムプログラミングや、コンパイラ固有の最適化、あるいはコンパイラ間の差異を吸収するためのコードを書く際に非常に強力な機能となります。

コアとなるコードの変更箇所

このコミットによって変更されたファイルは以下の2つです。

  1. src/pkg/go/build/build.go
  2. 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言語のソースコードリポジトリ
  • Go言語のビルド制約に関する一般的な情報源
  • GCCGoに関する情報源