Go から Cを呼び出す
Go には2つコンパイラの系統がある。6gなどのgcと呼ばれるものとgccgoと呼ばれるもの。前者はcと呼び出しのコンベンションが違うので、Cのライブラリを直接呼び出すことはできない。後者はgccへのトランスレータ?なので呼び出すことができるようだ。
6g系列でCのライブラリを呼びだすにはラッパとなるgoプログラムを書き、それをcgoというプログラムで処理して中間となる.goと.cをつくって、.cから.soをつくりそれをインストールしておくという手間がかかる。でもこれを自動化してくれる Makefileが用意されているのでこれを使えばよい。
Cの関数の用意
まず呼び出されるCの関数を用意する。今回は足し算。ヘッダファイルと本体。
/* add.h */ int add(int a, int b);
/* add.c */ #include "add.h" int add(int a, int b) { return a + b; }
これをコンパイルしてadd.oを作っておく。
呼び出しラッパ
この関数をパッケージでラップしてやる。ここではforeignTestというパッケージにした。
package foreignTest /* #include <stdio.h> #include "add.h" */ import "C" func Add(a int, b int) int { return int(C.add(C.int(a), C.int(b))) }
ポイントは3つ。
インポート文直前のコメント
import "C" の直前に書いたコメントはCのコードとして解釈される。ここではインポート文を書いたが、普通の関数定義なんかも書ける。
Cパッケージ
Cの関数は"C"というパッケージの関数として見える。したがって、C.add がCでのaddの呼び出しになる。
型変換
add を呼び出している部分で、C.int(a) などとしているのは、goのintからCのintへの型変換。同様に戻り値もint()でgoのintに戻している。
Makefile
Makefileはこんな感じ。CGO_LDFLAGS で Cのライブラリを指定している。
include $(GOROOT)/src/Make.inc TARG=foreignTest CGOFILES=\ foreignTest.go CLEANFILES+=foreignTest CGO_LDFLAGS=add.o include $(GOROOT)/src/Make.pkg %: install %.go $(GC) $*.go $(LD) -o $@ $*.$O
つぎのようにするとパッケージがビルドされ、インストールされる。
gomake install
テスト
テストプログラムはこんな感じ。
package main import "foreignTest" import "fmt" func main() { fmt.Printf("%d\n", foreignTest.Add(1, 2)); }
これで
gomake main
でOK。
所感
結構面倒だが、ツールがよくできているのでそれほどストレスは無いかな。でもCからGoを呼び出すのはどうやるんだろう?できないのかな?