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を呼び出すのはどうやるんだろう?できないのかな?