社内のとあるプロジェクトで、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から使えるようになりました。めでたしめでたし。
Mobility Technologies では共に日本のモビリティを進化させていくエンジニアを募集しています。話を聞いてみたいという方は、是非 募集ページ からご相談ください!