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

[インデックス 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言語の型の間で適切な変換が必要です:

  • boolunsigned char
  • byteunsigned char
  • runeint
  • errorGoInterface構造体
  • intint
  • uintunsigned 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, charcuint, culong, ccharに変更しています。

コアとなるコードの解説

Type構造体の定義

type Type struct {
    Size  int
    Align int
    C     *TypeRepr
}

この構造体は、Go言語の型をC言語の型に変換する際に必要な情報を保持しています:

  • Size: 型のサイズ(バイト単位)
  • Align: メモリアライメント
  • C: C言語での型表現

型変換テーブル

各ビルトイン型について、適切なサイズ、アライメント、C言語での表現が定義されています:

  • boolbyteは1バイトのunsigned char
  • runeは4バイトのint
  • errorは2つのポインタサイズを持つGoInterface

インターフェース型の構造

Goのインターフェース型は内部的に以下のような構造を持ちます:

typedef struct { void *t; void *v; } GoInterface;
  • t: 型情報へのポインタ
  • v: 実際の値へのポインタ

関連リンク

参考にした情報源リンク