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

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

動作環境
=======

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

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

```go
// #cgo CFLAGS: -Ihoge/include
// #cgo LDFLAGS: -Lhoge/lib -lhoge
// #include <hoge.h>
import "C"
```
しかし、これではリンクできませんでした。
以下2つはちゃんとリンクできた記述です。

```go
// #cgo CFLAGS: -Ihoge/include
// #cgo LDFLAGS: hoge/lib/libhoge.a
// #include <hoge.h>
import "C"
```

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

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

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

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

```go
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"
```
出力されるエラーは

```shell-session
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`を握り潰します

```go
// int _get_output_format( void ){ return 0; }
```
`_get_output_format mingw`でググると、いくつか似た症例が見つかること、
Mingw64でビルドしたらエラーが出なかったのでMingw側の問題かもしれません。

次に`hypot`を握り潰しますが、[_hypotを使ってくれ](https://msdn.microsoft.com/ja-jp/library/ms235360.aspx)とあるので_hypotを呼び出すよう実装します。

```go
// double hypot( double a, double b ){ return _hypot(a, b); }
```
ちなみに`hypot`は`hypot(a,b) = √(a*a+b*b)`。三平方の定理のアレっすね。

mrubyをリンクする(完成編)
=======================
エラーを握り潰すコードとmrubyのサンプルコードを追加した

```go: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)
}

```

```shell-session:実行結果
Hello World From mruby.
hypot(m, m+1) = 5.0
```

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

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