mecab で Java Binding

ここにもあるように、Mac ではデフォルトで mecab が入っている模様。

hyakushiki:~ takashi$ pkgutil --file-info /usr/lib/libmecab.dylib 
volume: /
path: usr/lib/libmecab.dylib

pkgid: com.apple.pkg.BaseSystem
pkg-version: 10.5.0.1.1.1188305148
install-time: 1203610626
uid: 0
gid: 0
mode: 120755

com.apple.pkg.BaseSystem というのは、コアパッケージっぽい。すごいなぁ。。

とはいえ、mecabJava Binding を試してみたかった為、別途インストールしてみます。が、極力楽したいので、まずは mac ports でインストールした後、Java Binding のみをインストールする方針で Go。

hyakushiki:~ takashi$ sudo port install mecab +utf8 mecab-ipadic-utf8
hyakushiki:~ takashi$ port info mecab
mecab 0.96, textproc/mecab (Variants: universal, darwin_7, darwin_8, sjis, utf8, utf8only)
http://mecab.sourceforge.net/
:

無事インストール後、0.96 の Java Binding のソースを落としてきて、ぱっと目につく Include や Java のパスを修正してビルドしようとするとMakefile の以下の部分で、

        $(CXX) -shared  $(TARGET)_wrap.o -o lib$(TARGET).so $(LIBS)

こんなエラーが発生。

Undefined symbols:
  "_main", referenced from:
      start in crt1.10.5.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
make: *** [all] Error 1

crt1.10.5.o はあるし、何だろうと思っていたら、man g++ をして衝撃の事実。

       -shared
           Produce a shared object which can then be linked with other objects to form an executable.  Not all systems support this option.
           For predictable results, you must also specify the same set of options that were used to generate code (-fpic, -fPIC, or model
           suboptions) when you specify this option.[1]

           This option is not supported on Mac OS X.

どうやら、これに該当しそうなオプションは -dynamiclib というのが正解の模様です。という事で、最終的に以下のように Makefile を書き換えて、make test まで成功。

hyakushiki:mecab-java-0.96 takashi$ diff -u Makefile.org Makefile
--- Makefile.org	2007-06-10 23:32:44.000000000 +0900
+++ Makefile	2008-07-15 02:57:25.000000000 +0900
@@ -1,27 +1,29 @@
+JAVA_BASE=/System/Library/Frameworks/JavaVM.framework/Versions/1.5
+JAVA_HOME=$(JAVA_BASE)/Home
 TARGET=MeCab
-JAVAC=javac
-JAVA=java
-JAR=jar
-CXX=c++
-INCLUDE=/usr/local/jdk/include
+JAVAC=$(JAVA_HOME)/bin/javac -encoding eucjp
+JAVA=$(JAVA_HOME)/bin/java
+JAR=$(JAVA_HOME)/bin/jar
+CXX=g++
+INCLUDE=$(JAVA_BASE)/Headers
 
 PACKAGE=org/chasen/mecab
 
 LIBS=`mecab-config --libs`
-INC=`mecab-config --cflags` -I$(INCLUDE) -I$(INCLUDE)/linux
+INC=`mecab-config --cflags` -I$(INCLUDE) 
 
 all:
-	$(CXX) -O3 -c -fpic $(TARGET)_wrap.cxx  $(INC)
-	$(CXX) -shared  $(TARGET)_wrap.o -o lib$(TARGET).so $(LIBS)
+	$(CXX) -O3 -c -fPIC $(TARGET)_wrap.cxx  $(INC)
+	$(CXX) -dynamiclib  $(TARGET)_wrap.o -o lib$(TARGET).dylib $(LIBS)
 	$(JAVAC) $(PACKAGE)/*.java
 	$(JAVAC) test.java
 	$(JAR) cfv $(TARGET).jar $(PACKAGE)/*.class
 
 test:
-	env LD_LIBRARY_PATH=. $(JAVA) test
+	env DYLD_LIBRARY_PATH=. $(JAVA) test
 
 clean:
-	rm -fr *.jar *.o *.so *.class $(PACKAGE)/*.class
+	rm -fr *.jar *.o *.dylib *.class $(PACKAGE)/*.class
 	
 cleanall:
 	rm -fr $(TARGET).java *.cxx


ポイントは以下の通り。

  • JAVA_HOME 周りは適宜設定
  • INCLUDE はヘッダのディレクトリを指定
  • JAVAC にソースのエンコーディングを追加
  • INC で、linux では $(INCLUDE)/linux を指定しているけれど、ここにあるヘッダは $(JAVA_BASE)/Headers に含まれているので問題なし
  • -fpic はないと怒られるので -fPIC で
  • -shared の代わりに -dynamiclib で、拡張子も dylib に
  • 実行時の環境変数は LD_LIBRARY_PATH から DYLD_LIBRARY_PATH へ


余談。Linux/Solaris などでおなじみの ldd はない模様。代わりに otool を発見。

hyakushiki:mecab-java-0.96 takashi$ otool -L libMeCab.dylib 
libMeCab.dylib:
	libMeCab.dylib (compatibility version 0.0.0, current version 0.0.0)
	/opt/local/lib/libmecab.1.dylib (compatibility version 2.0.0, current version 2.0.0)
	/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.4.0)
	/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.1)