LoginSignup
8
8

More than 5 years have passed since last update.

Go言語@Windowsでmrubyを静的リンクする

Last updated at Posted at 2015-01-26

Go言語のcgoは静的リンクが上手く扱えないらしい(@Windows)んだけど
最近はどうなんだろう?と思って試してみました。
ここでは参考までにmrubyを静的リンクしてみようと思います。

動作環境

Go 1.4.1 32bit
gcc 4.9.2(TDM) 32bit
OS Windows8.1 64bit

cgoで静的リンク

普段C言語を書く人は、cgoでライブラリを使う場合、以下のように書くと思います。

// #cgo CFLAGS: -Ihoge/include
// #cgo LDFLAGS: -Lhoge/lib -lhoge
// #include <hoge.h>
import "C"

しかし、これではリンクできませんでした。
以下2つはちゃんとリンクできた記述です。

// #cgo CFLAGS: -Ihoge/include
// #cgo LDFLAGS: hoge/lib/libhoge.a
// #include <hoge.h>
import "C"
// #cgo CFLAGS: -Ihoge/include
// #cgo LDFLAGS: -Lhoge/lib -Wl,-lhoge
// #include <hoge.h>
import "C"

1つ目の例とやってることは同じはずなのに、なぜこれでリンクできるのかは調べられていません。
cgoの#cgoディレクティブのパース部分がどうなってるかコードを読む必要あるかも…

mrubyをリンクする(失敗編)

とりあえず、ライブラリの静的リンクの方法が分かったので本題のmrubyのリンクです。
mrubyのビルドは割愛しますが、makeするだけで特別なオプションなどは必要ありません。

さて、以下のコード(コード片)はエラー出てビルドできません。
これでいけると思ったのですがダメでした。

package main

// #cgo CFLAGS: -II:/FreeSpace/C/mruby/include
// #cgo LDFLAGS: -LI:/FreeSpace/C/mruby/build/host/lib -Wl,-lmruby
// #include <windows.h>
// #include <math.h>
// #include <mruby.h>
// #include <mruby/compile.h>
import "C"

出力されるエラーは

main(.text): hypot: not defined
main(.text): _get_output_format: not defined
main(.text): undefined: hypot
main(.text): undefined: _get_output_format

hypotと_get_output_formatがundefinedって言われてますね。
調べたのですが原因が分からなかったので
吐き出されるエラーをdirtyに潰してコンパイルを通します!(なんだって!?)

追記

割と大切な事を書き忘れてました。
上記の2つの関数はmsvcrtがexportしてるので、-lmsvcrtを追加するとコンパイルは出るのですが
実行時にエラーが出てクラッシュしてします。

コンパイルエラーを潰す

まず、_get_output_formatを握り潰します

// int _get_output_format( void ){ return 0; }

_get_output_format mingwでググると、いくつか似た症例が見つかること、
Mingw64でビルドしたらエラーが出なかったのでMingw側の問題かもしれません。

次にhypotを握り潰しますが、_hypotを使ってくれとあるので_hypotを呼び出すよう実装します。

// double hypot( double a, double b ){ return _hypot(a, b); }

ちなみにhypothypot(a,b) = √(a*a+b*b)。三平方の定理のアレっすね。

mrubyをリンクする(完成編)

エラーを握り潰すコードとmrubyのサンプルコードを追加した

mruby_static_link/main.cpp
package main

// #cgo CFLAGS: -II:/FreeSpace/C/mruby/include
// #cgo LDFLAGS: -LI:/FreeSpace/C/mruby/build/host/lib -Wl,-lmruby
// #include <windows.h>
// #include <math.h>
// #include <mruby.h>
// #include <mruby/compile.h>
// int _get_output_format( void ){ return 0; }
// double hypot( double a, double b ){ return _hypot(a, b); }
import "C"
import "unsafe"

func main() {
    mrb := C.mrb_open()
    defer C.mrb_close(mrb)
    cxt := C.mrbc_context_new(mrb)
    defer C.mrbc_context_free(mrb, cxt)

    mrb_code0 := C.CString("puts 'Hello World ' + 'From mruby.'; m = 3")
    defer C.free(unsafe.Pointer(mrb_code0))
    mrb_code1 := C.CString("puts 'hypot(m, m+1) = ' + Math.hypot(m,m+1).to_s")
    defer C.free(unsafe.Pointer(mrb_code1))

    C.mrb_load_string_cxt(mrb, mrb_code0, cxt)
    C.mrb_load_string_cxt(mrb, mrb_code1, cxt)
}

実行結果
Hello World From mruby.
hypot(m, m+1) = 5.0

おわりに

とりあえず、リンクできましたが
いまいち動作が分かってないけど静的リンクできるようになった点、
なぜ、いくつかの関数がundefinedになってしまうか分かってない点
を踏まえると、かなり実験レベルの内容です。
サンプルのmrubyコード以外は動かない可能性もありますが、その辺はご了承ください。

ところでdeferの使い方ってこれであってるのかな?
mattnさんにご教示頂き
mrb_closemrbc_context_freedeferで処理するよう修正しました。

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8