💁🏻 ※本記事は Mobility Technologies の前身である JapanTaxi 時代に公開していたもので、記事中での会社やサービスに関する記述は公開当時のものです。

社内のとあるプロジェクトで、C++で書かれたライブラリを使うことになりました。GoからCが使えることはよく知られています。こんな感じで。
// main.go package main import ( // #include "increment.h" "C" "fmt" ) func main() { i := 19 fmt.Println(C.increment(C.int(i))) }
// increment.h int increment(int i);
// increment.c #include "increment.h" int increment(int i) { return i + 1; }
実行すると「20」と表示されます。
C++もいけます。ただしextern “C”が必要です。
// increment.h #ifdef __cplusplus extern "C" { #endif int increment(int i); #ifdef __cplusplus } #endif
// increment.cpp #include "increment.h" int increment(int i) { std::random_device rnd; return i + rnd(); }
ここでひとつ困ったことがあります。extern “C”しなければいけないということは、C++で書いた独自のクラスをGoから使うことはできないということです。
使いたいライブラリの関数やクラスのひとつひとつを、純粋なCのコードでラップしていくのは、ちょっと面倒です。
そんなときはSWIGを使ってみましょう。
こんなクラスがあるとします。
// point/point.h class point { public: int x; int y; void increment() { x++; y++; } }; void increment(point *p);
// point/point.cpp #include "point.h" void increment(point *p) { p->x++; p->y++; }
そしたらこんなファイルを置いて。
// point/point.i
%module point
%{
#include "point.h"
%}
%include "point.h"
おもむろにこう。
$ (cd point && swig -go -c++ -cgo -intgosize 64 point.i)
するとpoint/point.goとpoint/point_wrap.cxxが生成されて、下記のコードが動くようになります。
// main.go package main import ( "sample/point" "fmt" ) func main() { p := point.NewPoint() fmt.Println(p.GetX()) point.Increment(p) fmt.Println(p.GetX()) p.Increment() fmt.Println(p.GetX()) }
晴れてC++のクラスがGoから使えるようになりました。めでたしめでたし。