MinGW + MSYS 環境で MeCab 0.97 をビルドする

しばらく前に一応成功はしていたのだけど書くのが遅くなってしまった。
前に MeCab 0.96 をビルドする方法を書いたが、MeCab 0.97 はこれだけではうまくいかなかった(ビルド自体はできるのだが、実行するとエラーが出てしまう)。あまりきれいな方法ではないが動くようになったのでメモしておく。
mecab.h を修正するところまでは 0.96 と同じだが、このままビルドすると、MeCab 本体を実行した際、あるいは Perl モジュールを使った Perl スクリプトを実行した際に、

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

というエラーが出てしまった。エラーメッセージの意味はよくわからないが、どうもこのエラーは Microsoft Visual C++ Runtime library が出しているらしい。

    • disable-shared オプションをつけ、DLL を作らないようにしたら MeCab 本体は問題なく動くようになったので原因はライブラリにあるのだろうと当たりをつけ、0.96 との違いを調整して原因を調べていくと、libmecab.cpp の DllMain 関数の周りにつけられた extern "C" { ... } を外せばエラーが起こらなくなることがわかった。ということで、とりあえず libmecab.cpp を、以下のように修正。

 *** mecab-0.97-original/src/libmecab.cpp	Mon Nov 26 02:27:12 2007
--- mecab-0.97/src/libmecab.cpp Wed Feb 13 22:11:35 2008
***************
*** 50,56 ****
#if defined(_WIN32) && !defined(__CYGWIN__)
HINSTANCE DllInstance = 0;

! #ifdef __cplusplus
extern "C" {
#endif
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID) {
--- 50,56 ----
#if defined(_WIN32) && !defined(__CYGWIN__)
HINSTANCE DllInstance = 0;

! #if defined(__cplusplus) && !defined(__MINGW32__)
extern "C" {
#endif
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID) {
***************
*** 62,68 ****
std::locale::global(loc);
return TRUE;
}
! #ifdef __cplusplus
}
#endif
#endif
--- 62,68 ----
std::locale::global(loc);
return TRUE;
}
! #if defined(__cplusplus) && !defined(__MINGW32__)
}
#endif
#endif

この変更で、C からこのライブラリを使おうとするとうまくいかないということになると思われるが、幸い MeCab 本体も Perl モジュールも C++ で書かれているので問題ないようだ(というか 0.96 の時はなかったのだから大丈夫なはず)。
Dependency Walker でできた DLL を見てみると、extern "C" を外した場合には DllMain がエクスポートされているが、つけた場合(修正していない場合)はエクスポートされていないようだった。このあたりが原因なのだと思われるが、ほかに解決策が見つからなかったのでとりあえず。もっといい方法があれば修正していきたい。
これまでの経緯を別にまとめておいた