[インデックス 10897] ファイルの概要
コミット
このコミットは2011年12月20日にMaxim Pimenov氏によって作成されたもので、Go言語のcgoツールにおけるビルトイン型のexport機能をサポートするための重要な修正です。コミットハッシュは7be6229f9fa404eaac0d98951c2b6c970a3ee8d9
で、Issue #2462を解決しています。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7be6229f9fa404eaac0d98951c2b6c970a3ee8d9
元コミット内容
commit 7be6229f9fa404eaac0d98951c2b6c970a3ee8d9
Author: Maxim Pimenov <mpimenov@google.com>
Date: Tue Dec 20 09:28:45 2011 -0800
cgo: support export for built-in types
This change doesn't pay attention to structs
so they still cannot be exported, see Issue 2552.
Fixes #2462.
R=dvyukov, rsc, iant
CC=golang-dev
https://golang.org/cl/5487058
変更の背景
2011年当時、Go言語のcgoツールには深刻な制約がありました。Goの関数をC言語から呼び出せるようにする//export
ディレクティブが存在していたものの、Goのビルトイン型(byte
, bool
, rune
, error
など)を戻り値型として使用する関数をエクスポートしようとすると、コンパイルエラーが発生していました。
具体的には、以下のようなコードでエラーが発生していました:
package byterune
import "C"
//export f
func f() byte {
return 0
}
このコードをコンパイルしようとすると、「unrecognized Go type byte」というエラーメッセージが表示されていました。同様の問題がbool
, rune
, error
型でも発生していました。
これは、cgoの内部実装でGoのビルトイン型とC言語の型の対応関係が完全に定義されていなかったことが原因でした。この問題はGo言語のコミュニティからIssue #2462として報告され、cgoの実用性を大幅に制限していました。
前提知識の解説
CGOとは
CGO(C Go)は、Go言語でC言語のコードを呼び出したり、Go言語の関数をC言語から呼び出したりするためのツールです。2009年のGo言語リリース初期から存在していましたが、2011年時点でもまだ発展途上の機能でした。
//exportディレクティブ
//export
ディレクティブは、Go言語の関数をC言語から呼び出せるようにするためのコメント形式の指示です。このディレクティブが付加された関数は、C言語のヘッダーファイルに対応する関数宣言が生成され、C言語のコードから呼び出すことができるようになります。
Goのビルトイン型
Go言語には以下のようなビルトイン型があります:
bool
: 真偽値型byte
: 8ビット符号なし整数(uint8
のエイリアス)rune
: Unicode文字を表現する32ビット符号付き整数(int32
のエイリアス)error
: エラーを表現するインターフェース型int
,uint
,int8
,uint8
,int16
,uint16
,int32
,uint32
,int64
,uint64
: 各種整数型float32
,float64
: 浮動小数点数型complex64
,complex128
: 複素数型
C言語との型対応
cgoでは、Go言語の型とC言語の型の間で適切な変換が必要です:
bool
→unsigned char
byte
→unsigned char
rune
→int
error
→GoInterface
構造体int
→int
uint
→unsigned int
技術的詳細
このコミットでは、src/cmd/cgo/out.go
ファイルのgoTypes
マップにビルトイン型の定義を追加し、cgoType
関数でerror型の特別な処理を追加しています。
goTypesマップの拡張
var goTypes = map[string]*Type{
"bool": {Size: 1, Align: 1, C: c("uchar")},
"byte": {Size: 1, Align: 1, C: c("uchar")},
"int": {Size: 4, Align: 4, C: c("int")},
"uint": {Size: 4, Align: 4, C: c("uint")},
"rune": {Size: 4, Align: 4, C: c("int")},
// ...その他の型定義
}
GoInterfaceサイズの修正
インターフェース型のサイズが3 * p.PtrSize
から2 * p.PtrSize
に修正されました。これは、Goのインターフェースが実際には2つのポインタ(型情報と値)で構成されているためです。
error型の特別処理
if t.Name == "error" {
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
}
error型は特別にGoInterfaceとして扱われるようになりました。
コアとなるコードの変更箇所
1. misc/cgo/test/issue2462.go(新規ファイル)
このファイルは、修正された機能のテストケースを含んでいます。各ビルトイン型に対応するexport関数が定義されています:
//export exportbyte
func exportbyte() byte {
return 0
}
//export exportbool
func exportbool() bool {
return false
}
//export exportrune
func exportrune() rune {
return 0
}
//export exporterror
func exporterror() error {
return nil
}
2. src/cmd/cgo/out.go(修正)
goTypes
マップにビルトイン型の定義を追加し、cgoType
関数でerror型の処理を追加しています。
3. misc/cgo/test/basic.go(修正)
変数名の競合を避けるため、uint
, ulong
, char
をcuint
, culong
, cchar
に変更しています。
コアとなるコードの解説
Type構造体の定義
type Type struct {
Size int
Align int
C *TypeRepr
}
この構造体は、Go言語の型をC言語の型に変換する際に必要な情報を保持しています:
Size
: 型のサイズ(バイト単位)Align
: メモリアライメントC
: C言語での型表現
型変換テーブル
各ビルトイン型について、適切なサイズ、アライメント、C言語での表現が定義されています:
bool
とbyte
は1バイトのunsigned charrune
は4バイトのinterror
は2つのポインタサイズを持つGoInterface
インターフェース型の構造
Goのインターフェース型は内部的に以下のような構造を持ちます:
typedef struct { void *t; void *v; } GoInterface;
t
: 型情報へのポインタv
: 実際の値へのポインタ
関連リンク
- Go Issue #2462 - 元の問題報告
- Go CL 5487058 - Code Reviewページ
- Go Issue #2552 - 構造体のexportに関する関連問題
- CGO Documentation - CGOの公式ドキュメント