go-mrubyでmrubyをC共有ライブラリに突っ込む
Go1.5から、C共有ライブラリを生成するオプションが追加されたらしい。
そこで、Goにmrubyを組み込んでC共有ライブラリを作成し、使ってみた。 環境は、
まずは、go-mrubyをダウンロード。
go get -d github.com/mitchellh/go-mruby
続いて、リポジトリのreadme通りmrubyをビルド。(ここで独自にmrbgemを組み込みたい場合は、makeしないで自前でビルドしたほうがよい)
cd $GOPATH/src/github.com/mitchellh/go-mruby make
次に、試しに以下のようなコードを任意の場所に用意。 LoadString()で、引数の文字列をmrubyのコードとして実行し戻り値を受け取っている。
// example.go package main import ( "C" "github.com/mitchellh/go-mruby" ) //export example func example() { mrb := mruby.NewMrb() defer mrb.Close() _, err := mrb.LoadString(`5.times {|num| puts "*" * num}`) if err != nil { ¦ panic(err.Error()) } } func main() { }
上記example.goと同ディレクトリに、最初に生成しておいた静的ライブラリ(libmruby.a)を置くことも忘れない。
cp -p $GOPATH/src/github.com/mitchellh/go-mruby/libmruby.a /path/to/example
最後に、以下でsoが生成されるぞお!
go build -buildmode=c-shared -o example.so example.go
と思ったら、エラーが発生した。
# command-line-arguments /path/to/linker: running clang failed: exit status 1 clang: error: no such file or directory: 'libmruby.a'
いろいろ試してみたけど、これは、 go-mrubyのmruby.go内で、cgoのインポート時にLDFLAGSに指定しているlibmruby.aが見つからないと言っているので、
とりあえず、以下のようにmruby.go自体を書き換えてしまう。
@@ -3,7 +3,7 @@ package mruby import "unsafe" // #cgo CFLAGS: -Ivendor/mruby/include -// #cgo LDFLAGS: libmruby.a -lm +// #cgo LDFLAGS: /full/path/to/libmruby.a -lm // #include <stdlib.h> // #include "gomruby.h" import "C"
再度ビルドして、example.soが生成された!
example()がエクスポートされているかを確認する。よさそう。
$ nm example.so | grep -i example 0000000000071a90 T __cgoexp_a4c9f6073c4b_example 00000000000026e0 T _example 0000000000071ad0 t main.example 00000000001fc400 s main.example.f
ということで、例によってpythonのREPLでexample()を実行してみる。出た!
>>> import ctypes >>> lib = ctypes.CDLL("./example.so") >>> lib.example() * ** *** **** 1
以上、非常に手軽にgoでC共有ライブラリを書けて、実は中身はmrubyでした!! ということができました。
次に、LoadString()でmrubyを読みこむ部分を、ファイルから読めるようにすると良いかなと思う。 そうすればリビルドすることなく挙動をコントロールできるという恩恵が得られます。
それは次回のエントリにしよう。。。