静的リンクで組み込んだ場合の設定ファイルの読み込み

MeCabをmake installできる環境であれば、例えば--prefix=/usrとしていたらならば、

  • /usr/lib/libmecab.so が配置され
  • /usr/lib/mecab に辞書が配置され
  • /usr/etc/mecabrc に設定ファイルが配置され

という感じになります。

このとき、mecabrcには辞書の位置が"/usr/lib/mecab/dicdir/dic/ipadic"ですよとか書いてあるので、mecabはmecabrcを通じて辞書の位置を特定できるのです。

ところが、libmecab.aを利用してmysqld等のELFバイナリに直接埋め込んでしまった場合、そしてそのバイナリを別の場所へ持っていって動かすような場合、mecabの関数はmysqldの中に埋め込まれているので問題ないですが、辞書が置いてきぼりをくらってしまいます。

そこで、辞書もいっしょにパッケージングしてあげる必要があるわけですが、ファイルレベルで同梱させたとしても、どこのパスにあるか分からない辞書をmecabは見つけることはできないわけです。

このとき、mecabコマンドには--rcfileというオプションがあり、コマンドを実行するのであれば--rcfile=$展開したディレクトリ/etc/mecabrcみたいに渡してあげれば解決ができます。またライブラリのmecab_new関数も同様に--rcfileが指定可能なので、MeCabを組み込むアプリケーションの開発者がmecab_new関数を呼び出す際に指定してあげればOKです。

とはいうものの、TritonnみたいにSenna経由でMeCabを使っている場合、そういうコードレベルでの対処は難しい場合もあります。Tritonnのためだけ、しかもバイナリパッケージングするときだけのために、Sennamecab_new呼出のコードをいじるのもちょっとオーバーな気がします。

自分でビルドしてmake installする場合はprefixの指定がうまくやってくれるのですが、バイナリパッケージングをする場合はprefixの助けを得ることができません。

そこで何か良い方法がないかと探していたのですが、MeCab本体にこんなパッチを当てると幸せになれることが分かりました。

--- src/utils.cpp       2007-06-10 21:28:37.000000000 +0900
+++ src/utils.cpp~      2007-10-01 15:05:28.000000000 +0900
@@ -223,6 +223,14 @@ namespace MeCab {
     }
 #endif
 
+#ifdef EMBEDDED_LIBRARY
+    if (rcfile.empty()) {
+      std::string s = "../etc/mecabrc";
+      std::ifstream ifs(s.c_str());
+      if (ifs) rcfile = s;
+    }
+#endif /* EMBEDDED_LIBRARY */
+
 #if defined(_WIN32) && !defined(__CYGWIN__)
     HKEY hKey;
     char v[BUF_SIZE];

これは、load_dictionary_resourceという関数なのですが、この関数は$HOME/.mecabrcとか$MECABRCとか、あるいはmecabのconfigure時に指定されたprefixの$prefix/etc/mecabrcとかの読み込みを順に試みる関数です。このパッチはこのload_dictionaly_resource関数に、"../etc/mecabrc"というパスも見てもらえるようにするためのパッチです。

例えば、こんなファイル構成での使用を考えています。

MySQLは起動時にpwdをデータディレクトリに書き換えます。ですから上記コードを実行する際のカレントディレクトリは/usr/local/mysql/dataとかです。この/usr/local/mysqlの部分は相対パスなのでなんでもいいです。

たぶんこのパッチを当てるとTritonnみたいにmecabを組み込んで使いたい場合に幸せになれるのではと思います。

このパッチは今日作ったばかりなので、これでいろいろビルドとかテストとかをまずは試してみたいと思います。

※patch使いの方は言わなくとも分かるとおもいますが、CPPFLAGS=-DEMBEDDED_LIBLRARYで有効にします。あとwindows向けに入れ子のifdefが必要な気もします。

Tritonnでの対応パタン

こっちのパタンもあり。sql/mysqld.ccのsen_init呼出付近で。

#ifdef ENABLE_MECAB
  const char *mecabrc = getenv("MECABRC");
  if (!mecabrc) setenv("MECABRC", "../etc/mecabrc", 1);
#endif /* ENABLE_MECAB */

既にMECABRCが設定されていれば何もしない。設定されてなかったら"../etc/mecabrc"を設定。

ただこの対応方法だと、mysqldの中からmecabの機能を使う分にはいいのだけれども、$MYSQL/binにmecab*コマンドを放りこんだ場合、それらが軒並mecabrcが読めない(--rcfile指定が必要)という状態に。