[インデックス 14296] ファイルの概要
このコミットは、Go言語のmisc/cgo/test
ディレクトリ内のテストスイートにおいて、gccgo
コンパイラを使用した場合にテストが正しくパスするようにするための変更を導入しています。具体的には、cgo
テストの一部がgc
コンパイラとgccgo
コンパイラで異なる振る舞いをする可能性があったため、コンパイラ固有のビルドタグ(+build gc
と+build gccgo
)を活用して、それぞれのコンパイラに合わせた実装を提供することで、テストの互換性と信頼性を向上させています。
コミット
commit 538a58bb75ea86be27ba24597c4f45f0e84969ea
Author: Ian Lance Taylor <iant@golang.org>
Date: Thu Nov 1 13:54:09 2012 -0700
misc/cgo/test: changes to pass when using gccgo
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6821067
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/538a58bb75ea86be27ba24597c4f45f0e84969ea
元コミット内容
misc/cgo/test: changes to pass when using gccgo
変更の背景
Go言語には、主に2つの主要なコンパイラ実装が存在します。一つは公式のGoツールチェインでデフォルトで使用されるgc
(Go Compiler)であり、もう一つはGCC(GNU Compiler Collection)のフロントエンドとして実装されているgccgo
です。これら二つのコンパイラは、Go言語の仕様を実装していますが、内部的な最適化やランタイムの挙動に違いがある場合があります。
このコミットが行われた背景には、misc/cgo/test
ディレクトリ内のテストが、gc
コンパイラでは問題なく動作するものの、gccgo
コンパイラでは失敗する、あるいは意図しない結果を返すという問題があったと考えられます。特にcgo
(GoとC言語の相互運用機能)に関連するテストは、Cコンパイラとの連携や、GoランタイムとCランタイムの間のインタフェースに依存するため、コンパイラの実装の違いが顕著に現れやすい領域です。
このコミットの目的は、gccgo
環境下でもcgo
テストが期待通りに動作し、Go言語の異なるコンパイラ実装間での互換性とテストカバレッジを保証することにあります。これは、Go言語の堅牢性を維持し、異なるビルド環境での一貫した動作を保証するために不可欠な作業です。
前提知識の解説
1. Go言語のコンパイラ: gc
とgccgo
-
gc
(Go Compiler):- Go言語の公式ツールチェインに同梱されているデフォルトのコンパイラです。
- Go言語の設計思想に合わせて最適化されており、高速なコンパイルが特徴です。
- Go言語の新しい機能が最初に実装されることが多く、通常は
gccgo
よりもGo言語の最新機能への対応が先行します。 - 生成されるバイナリは通常、静的にリンクされ、Goランタイムを含みます。
-
gccgo
:- GCC(GNU Compiler Collection)の一部として提供されるGo言語のフロントエンドです。
- GCCの強力な最適化バックエンドを利用できるため、CPUバウンドなアプリケーションでは
gc
よりも高速な実行ファイルを生成する可能性があります。 - GCCがサポートする幅広いアーキテクチャやオペレーティングシステムに対応しています。
libgo
ライブラリを動的にリンクすることで、より小さなバイナリを生成することも可能です。
両コンパイラはGo言語の同じ仕様を実装していますが、内部的な実装やランタイムの挙動に差異があるため、特に低レベルな処理やC言語との連携(cgo
)においては、コンパイラ固有の調整が必要になることがあります。
2. cgo
cgo
は、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのGoツールです。Goのソースファイルがimport "C"
という擬似パッケージをインポートしている場合、そのファイルはcgo
によって処理されます。cgo
は、GoとCの間のデータ型変換や関数呼び出しの橋渡しを行い、GoプログラムにCライブラリの機能を取り込むことを可能にします。
3. Goのビルドタグ (// +build
または //go:build
)
Goのビルドタグ(またはビルド制約)は、Goソースファイルの先頭に記述される特別なコメントで、そのファイルが特定のビルド条件を満たす場合にのみコンパイル対象となるように指定します。これにより、オペレーティングシステム、アーキテクチャ、またはカスタムタグに基づいて、異なるコードパスを条件付きでコンパイルすることが可能になります。
- 構文:
- Go 1.17以降:
//go:build <expression>
- Go 1.16以前:
// +build <expression>
(後方互換性のために現在もサポートされています)
- Go 1.17以降:
- 例:
// +build linux
:Linuxシステムでのみコンパイル。// +build windows,amd64
:WindowsかつAMD64アーキテクチャでのみコンパイル。// +build gc
:gc
コンパイラでビルドされる場合のみコンパイル。// +build gccgo
:gccgo
コンパイラでビルドされる場合のみコンパイル。
このコミットでは、+build gc
と+build gccgo
というビルドタグが使用されており、それぞれのコンパイラに特化したコードを条件付きで含めることで、コンパイラ間の差異を吸収しています。
技術的詳細
このコミットの技術的な核心は、Goのビルドタグを利用して、gc
コンパイラとgccgo
コンパイラそれぞれに特化したruntime.c
の実装を提供することです。
Goのテストスイート、特にcgo
に関連するテストでは、Goランタイムの内部関数や挙動にアクセスする必要がある場合があります。しかし、gc
とgccgo
では、これらの内部関数の名前付け規則や、C言語からGoランタイムの関数を呼び出す際のアセンブリレベルでのリンケージが異なることがあります。
misc/cgo/test/backdoor
パッケージは、Goランタイムの特定の関数(この場合はruntime·lockedOSThread
)をC言語側から「バックドア」的に呼び出すためのテストユーティリティとして機能します。これは、Goランタイムの低レベルな挙動をテストするために用いられます。
このコミットでは、以下の戦略が取られています。
-
既存の
runtime.c
の限定: 既存のmisc/cgo/test/backdoor/runtime.c
ファイルに// +build gc
というビルドタグを追加することで、このファイルがgc
コンパイラでビルドされる場合にのみコンパイルされるように変更しました。これにより、gc
コンパイラ特有のランタイム関数へのアクセス方法がこのファイルにカプセル化されます。 -
gccgo
専用のruntime_gccgo.c
の導入: 新たにmisc/cgo/test/backdoor/runtime_gccgo.c
というファイルを作成し、これに// +build gccgo
というビルドタグを付与しました。このファイルはgccgo
コンパイラでビルドされる場合にのみコンパイルされます。このファイル内では、gccgo
のランタイムが提供する_Bool runtime_lockedOSThread(void);
という関数を、Go側から呼び出しやすいようにLockedOSThread
という名前でラップしています。asm(GOPKGPATH ".LockedOSThread")
という構文は、Goのリンカに対して、このC関数がGoパッケージのLockedOSThread
としてエクスポートされることを指示しています。
このアプローチにより、gc
でビルドする際にはruntime.c
が、gccgo
でビルドする際にはruntime_gccgo.c
がそれぞれコンパイルされ、各コンパイラのランタイム実装の差異を吸収し、LockedOSThread
という共通のインタフェースを通じてテストコードがランタイム機能にアクセスできるようになります。これにより、gccgo
環境下でもcgo
テストが正しく動作するようになります。
コアとなるコードの変更箇所
このコミットでは、以下の2つのファイルが変更されています。
-
misc/cgo/test/backdoor/runtime.c
:--- a/misc/cgo/test/backdoor/runtime.c +++ b/misc/cgo/test/backdoor/runtime.c @@ -6,6 +6,8 @@ // Must be in a non-cgo-using package so that // the go command compiles this file with 6c, not gcc. +// +build gc + typedef char bool; bool runtime·lockedOSThread(void);
- 6行目に
// +build gc
が追加されました。
- 6行目に
-
misc/cgo/test/backdoor/runtime_gccgo.c
: (新規ファイル)--- /dev/null +++ b/misc/cgo/test/backdoor/runtime_gccgo.c @@ -0,0 +1,18 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Expose some runtime functions for testing. +// This is the gccgo version of runtime.c. + +// +build gccgo + +_Bool runtime_lockedOSThread(void); + +_Bool LockedOSThread(void) asm(GOPKGPATH ".LockedOSThread"); + +_Bool +LockedOSThread(void) +{ + return runtime_lockedOSThread(); +}
- 新規ファイルとして追加され、
// +build gccgo
タグが付与されています。 runtime_lockedOSThread
を呼び出すLockedOSThread
関数が定義されています。
- 新規ファイルとして追加され、
コアとなるコードの解説
misc/cgo/test/backdoor/runtime.c
// +build gc
typedef char bool;
bool runtime·lockedOSThread(void);
このファイルは、Goのデフォルトコンパイラであるgc
でビルドされる場合にのみコンパイルされます。
// +build gc
という行がその役割を果たしています。
runtime·lockedOSThread
は、gc
コンパイラが生成するGoランタイムの内部関数runtime.lockedOSThread
に対応するC言語側の宣言です。Goの内部関数は、Goのリンカが認識できるように特殊な命名規則(パッケージ名·関数名
)を持つことがあります。この宣言により、CコードからGoランタイムのこの関数を呼び出すことが可能になります。
misc/cgo/test/backdoor/runtime_gccgo.c
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Expose some runtime functions for testing.
// This is the gccgo version of runtime.c.
// +build gccgo
_Bool runtime_lockedOSThread(void);
_Bool LockedOSThread(void) asm(GOPKGPATH ".LockedOSThread");
_Bool
LockedOSThread(void)
{
return runtime_lockedOSThread();
}
このファイルは、gccgo
コンパイラでビルドされる場合にのみコンパイルされます。
// +build gccgo
という行がその役割を果たしています。
_Bool runtime_lockedOSThread(void);
は、gccgo
コンパイラが生成するGoランタイムの内部関数runtime.lockedOSThread
に対応するC言語側の宣言です。gccgo
では、gc
とは異なるC言語の型(_Bool
)や命名規則が使用される場合があります。
_Bool LockedOSThread(void) asm(GOPKGPATH ".LockedOSThread");
の行は特に重要です。
_Bool LockedOSThread(void)
:LockedOSThread
というC関数を宣言しています。asm(GOPKGPATH ".LockedOSThread")
: これはGCCの拡張機能であり、このC関数がGoのパッケージパス(GOPKGPATH
)と関数名(.LockedOSThread
)を組み合わせたシンボル名でエクスポートされることをリンカに指示しています。これにより、Go側のテストコードがLockedOSThread
という名前でこのC関数を呼び出すことができるようになります。
そして、LockedOSThread
関数の実装は、単にgccgo
ランタイムのruntime_lockedOSThread
を呼び出してその結果を返しています。
これらの変更により、gc
とgccgo
という異なるコンパイラ環境下でも、misc/cgo/test/backdoor
パッケージ内のテストが、GoランタイムのlockedOSThread
機能に一貫した方法でアクセスできるようになり、テストの信頼性が向上しました。
関連リンク
- Go CL 6821067: https://golang.org/cl/6821067
参考にした情報源リンク
- Go言語のコンパイラ
gc
とgccgo
の比較:- https://go.dev/doc/install/source#gc-vs-gccgo
- https://stackoverflow.com/questions/10609000/what-is-the-difference-between-gc-and-gccgo
- https://wiki.archlinux.org/title/Go#Compilers
- https://caffeinatedwonders.com/go-compilers-gc-vs-gccgo/
- https://stackoverflow.com/questions/10609000/what-is-the-difference-between-gc-and-gccgo
- https://www.reddit.com/r/golang/comments/100000/gc_vs_gccgo_performance/
- Go
cgo
のドキュメント: - Go ビルドタグ (
// +build
または//go:build
) のドキュメント: