環境
- Windows Vista Business(64ビット)SP2
- JDK 1.6.0_16(64ビット)
- MinGW-w64 (mingw-w64-bin_i686-mingw_20100702_sezero.zip)
- MSYS (MSYS-20100707.zip)
- Make (make-3.82-20100827.zip)
- libiconv(libiconv-1.13.1.tar.gz)
- MeCab用IPA辞書(mecab-ipadic-2.7.0-20070801.tar.gz)
- MeCab(mecab-0.98.tar.gz)
- MeCab Java バインディング(mecab-java-0.98.tar.gz)
MinGW 環境は、これまで色々ビルドしているので、他にも必要なライブラリなどがあるかもしれないが、今回やった手順しか書かないので注意。
libiconv のビルド
tar zxvf libiconv-1.13.1.tar.gz cd libiconv-1.13.1 ./configure --prefix=/mingw --enable-static --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 make make installlibiconv のビルドは、スンナリできた。
MeCab 用 IPA 辞書のビルド
tar zxvf mecab-ipadic-2.7.0-20070801.tar.gz cd mecab-ipadic-2.7.0-20070801 ./configure --prefix=/mingw --with-charset=utf-8 make
MeCab のビルド
パッチファイル(MeCab_0.98_MinGW.patch)については後述する。
以下の手順でビルドすると、 libgcc_s_sjlj-1.dll が実行時に必要となる。このファイルは MinGWディレクトリの ”x86_64-w64-mingw32/bin/”に入っている。パスを通すか、実行ファイルと同じディレクトリにコピーしておく必要がある。依存を無くそうと悶絶してみたが、私のレベルでは、どうしてもできなかった。ちなみに私のレベルは5である。スライムぐらいには勝てる・・・・
tar zxvf /f/Archive/mecab-0.98.tar.gz cd mecab-0.98 patch -p0 < MeCab_0.98_MinGW.patch CPPFLAGS='-I/mingw/include' LIBS=-liconv ./configure --prefix=/mingw --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --enable-utf8-only --with-charset=utf8 make
MeCab のパッチファイル
このパッチファイルこそが、今回の血と汗と涙の結晶。若干の説明をおこなう。
【config.h.in】
49 行目
#undef HAVE_PTHREAD_H ↓ //#undef HAVE_PTHREAD_Hこれは、pthread を利用しないようにするため。インストールされていなければいらない。うちの環境では、以前 pthread をインストールしていて、それを使うと MeCab.exe 実行して、1行入力後に固まるようなので、利用しないようにした。pthread を利用しない場合は、WindowsAPI の同様の機能を利用するようだ。
【src/feature_index.cpp】
311 行目
case 't': os_ << (size_t)path->rnode->char_type; break; ↓ case 't': os_ << static_cast<unsigned int>((size_t)path->rnode->char_type); break;あいまいなキャストだったので、修正。これが正しいのかは神のみぞ知る・・・
【src/libmecab.cpp】
53 行目
#ifdef __cplusplus ↓ #if defined(__cplusplus) && !defined(__MINGW32__)
65 行目
#ifdef __cplusplus ↓ #if defined(__cplusplus) && !defined(__MINGW32__)ここは、偉大なる先人の知恵。
【src/Makefile.in】
260 行目
INCLUDES = -DDIC_VERSION=$(DIC_VERSION) $(MECAB_WITHOUT_SHARE_DIC) $(MECAB_WITHOUT_MUTEX_LOCK) $(MECAB_USE_UTF8_ONLY) -DMECAB_DEFAULT_RC="\"$(MECAB_DEFAULT_RC)\"" ↓ INCLUDES = -DDIC_VERSION=$(DIC_VERSION) $(MECAB_WITHOUT_SHARE_DIC) $(MECAB_WITHOUT_MUTEX_LOCK) $(MECAB_USE_UTF8_ONLY) -DMECAB_DEFAULT_RC='"$(MECAB_DEFAULT_RC)"'ここの修正は、苦肉の策。どうもうちの環境では、変数の展開に問題があるらしく、思ったようにならない(バックスラッシュだらけになり、バックスラッシュの個数も1個足りないとか・・・)。よって、この値を利用している、src/utils.cpp を修正した。ここは、コンパイルが通るようにしただけで、理想の対処とは程遠い。
【src/mecab.h】
131 行目
#ifdef _WIN32 ↓ #if defined(_WIN32) && !defined(__MINGW32__)
254 行目
#ifndef SIWG ↓ #ifndef SWIGここも、偉大なる先人の知恵。
【src/utils.cpp】
282 行目
if (rcfile.empty()) rcfile = MECAB_DEFAULT_RC; ↓ if (rcfile.empty()) rcfile = "C:\\appli\\MeCab_utf8\\etc\\mecabrc";ここは、mecabrc ファイル格納デフォルトディレクトリをハードコーディングした。各自の環境に合わせて、変更する必要がある。
ソースを読むと、ホームディレクトリの”.mecabrc”か、MECABRC 環境変数の値か、レジストリ”HKEY_LOCAL_MACHINE\software\mecab”の”mecabrc”の値か、レジストリ”HKEY_CURRENT_USER\software\mecab”の”mecabrc”の値か、MeCab.dll と同じディレクトリの”mecabrc”を探すらしい。それでも見つからないときにこの値を利用するようだ。
本来的には、Make の変数展開を何とかするべきなんだろうが、LV5 ではなんとも・・・
【src/writer.cpp】
236 行目
case 'L': *os << std::strlen(sentence); break; ↓ case 'L': *os << static_cast<unsigned int>(std::strlen(sentence)); break;あいまいなキャストってコンパイラに怒られたので、適当にキャストしてみた(おいっ)。いいのかなぁいいのかなぁ。
MeCab Java バインディングのビルド
tar zxvf mecab-java-0.98.tar.gz cd mecab-java-0.98
先ほどビルドした MeCab から必要なファイルを Java バインディングのディレクトリにコピーする。
cp ../mecab-0.98/src/mecab.h . cp ../mecab-0.98/src/.libs/libmecab.a .
Java の bin ディレクトリをパスに追加
export PATH=/c/appli/Java/jdk1.6/bin:$PATH
Makefile を修正
TARGET=MeCab JAVAC=javac JAVA=java JAR=jar CXX=c++ INCLUDE=c:/appli/Java/jdk1.6/include PACKAGE=org/chasen/mecab LIBS=-L. -L/mingw/lib -lmecab -liconv INC=-I$(INCLUDE) -I$(INCLUDE)/win32 all: $(CXX) -O3 -c -fpic $(TARGET)_wrap.cxx $(INC) $(CXX) -shared -static $(TARGET)_wrap.o -o $(TARGET).dll $(LIBS) $(JAVAC) -encoding utf-8 $(PACKAGE)/*.java $(JAVAC) -encoding utf-8 test.java $(JAR) cfv $(TARGET).jar $(PACKAGE)/*.class test: LD_LIBRARY_PATH=. MECABRC=./mecabrc $(JAVA) -Djava.file.encoding=euc-jp test clean: rm -fr *.jar *.o *.dll *.class $(PACKAGE)/*.class cleanall: rm -fr $(TARGET).java *.cxx
java のコンソール出力が文字化けするので、ファイルにログを吐いておく。、
make > build.log 2>&1
出来上がったもののテストをしてみる。
設定ファイルを作る
cp ../mecab-0.98/mecabrc .
コピーした mecabrc を修正する。辞書ディレクトリを指定する部分に、先ほどビルドした辞書のディレクトリを設定する。
dicdir = ..\mecab-ipadic-2.7.0-20070801
テストを実施
コンソール出力は、文字化けするのでファイルに吐いて確かめる。
make test > test.log 2>&1
テスト結果
LD_LIBRARY_PATH=. MECABRC=./mecabrc java -Djava.file.encoding=euc-jp test 0.98 太郎 名詞,固有名詞,人名,名,*,*,太郎,タロウ,タロー は 助詞,係助詞,*,*,*,*,は,ハ,ワ 二郎 名詞,固有名詞,人名,名,*,*,二郎,ジロウ,ジロー に 助詞,格助詞,一般,*,*,*,に,ニ,ニ この 連体詞,*,*,*,*,*,この,コノ,コノ 本 名詞,一般,*,*,*,*,本,ホン,ホン を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ 渡し 動詞,自立,*,*,五段・サ行,連用形,渡す,ワタシ,ワタシ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOS BOS/EOS,*,*,*,*,*,*,*,* EOS
ちなみに、辞書を指定せずに実行すると、以下のようなログが出力される。
LD_LIBRARY_PATH=. MECABRC=./mecabrc java -Djava.file.encoding=euc-jp test 0.98 Exception in thread "main" java.lang.RuntimeException: tagger.cpp(151) [load_dictionary_resource(param)] param.cpp(71) [ifs] no such file or directory: ./mecabrc at org.chasen.mecab.MeCabJNI.new_Tagger__SWIG_1(Native Method) at org.chasen.mecab.Tagger.<init>(Tagger.java:128) at test.main(test.java:17) make: *** [test] Error 1
文字コードの違う辞書を指定してしまうと、文字が化け化けになる。指定しているつもりが無くとも、MeCab をインストーラーでインストールしたことがあると、レジストリに設定ファイルの場所が設定されてしまうので、こういう事態に陥りやすいので注意。
MeCab の設定ファイルの指定方法は複数あるが、今回は、環境変数で指定してある。DLL と同じディレクトリに入れる方法もあるのだが、レジストリでの指定より優先順位が低いので、環境によって問題がある。
これでめでたく Java から MeCab を利用することが出来る。
いや、長かった・・・・この手順も長いが、実はかなり遠回りをしてしまい、実際にはここに書かれていない作業を延々としてしまった。GLib コンパイルしたりとか、gettext コンパイルしたりとか・・・
まあ、いろんな意味でレベルは上がった。怪我の功名というやつですな。次は Python バインディングか・・・・