どうせ和布蕪るなら、の続き、にちゃんとなりそう? (ライブラリとしての利用?)

natto-py もいけるんちゃうか、と思うも…。

前回のは、はなから「python バインディング」にしか興味がない、って考えでやったけれど、あの setup.py が書けるなら、当然「64bit 版 MeCab」を作れる:

Makefile.msvc
 1 CC = cl.exe
 2 CXXC = cl.exe
 3 LINK=link.exe
 4 
 5 CFLAGS = -EHsc -O2 -GL -GA -Ob2 -nologo -W3 -MD -Zi -wd4800 -wd4305 -wd4244 -wd4267
 6 LDFLAGS = -nologo -OPT:REF -OPT:ICF -LTCG -NXCOMPAT -DYNAMICBASE ADVAPI32.LIB
 7 DEFS =  -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE \
 8         -DMECAB_USE_THREAD \
 9         -DDLL_EXPORT -DHAVE_GETENV -DHAVE_WINDOWS_H -DDIC_VERSION=102 \
10         -DVERSION="\"0.996\"" -DPACKAGE="\"mecab\"" \
11         -DUNICODE -D_UNICODE \
12         -DHAVE_UNSIGNED_LONG_LONG_INT \
13         -DMECAB_DEFAULT_RC="\"c:\\Program Files (x86)\\mecab\\etc\\mecabrc\""
14 INC = -I. -I..
15 DEL = del
16 
17 OBJ =   feature_index.obj param.obj  learner.obj string_buffer.obj \
18 	char_property.obj         learner_tagger.obj    tagger.obj \
19 	connector.obj             tokenizer.obj \
20 	context_id.obj            dictionary.obj  utils.obj \
21 	dictionary_compiler.obj   viterbi.obj \
22 	dictionary_generator.obj  writer.obj iconv_utils.obj \
23 	dictionary_rewriter.obj   lbfgs.obj eval.obj nbest_generator.obj
24 
25 .c.obj:
26 	$(CC) $(CFLAGS) $(INC) $(DEFS) -c  $<
27 
28 .cpp.obj:
29 	$(CC) $(CFLAGS) $(INC) $(DEFS) -c  $<
30 
31 all: libmecab mecab mecab-dict-index mecab-dict-gen mecab-cost-train mecab-system-eval mecab-test-gen
32 
33 mecab: $(OBJ) mecab.obj
34 	$(LINK) $(LDFLAGS) -out:$@.exe mecab.obj libmecab.lib
35 
36 mecab-dict-index: $(OBJ) mecab-dict-index.obj
37 	$(LINK) $(LDFLAGS) -out:$@.exe mecab-dict-index.obj libmecab.lib
38 
39 mecab-dict-gen: $(OBJ) mecab-dict-gen.obj
40 	$(LINK) $(LDFLAGS) -out:$@.exe mecab-dict-gen.obj libmecab.lib
41 
42 mecab-cost-train: $(OBJ) mecab-cost-train.obj
43 	$(LINK) $(LDFLAGS) -out:$@.exe mecab-cost-train.obj libmecab.lib
44 
45 mecab-system-eval: $(OBJ) mecab-system-eval.obj
46 	$(LINK) $(LDFLAGS) -out:$@.exe mecab-system-eval.obj libmecab.lib
47 
48 mecab-test-gen: mecab-test-gen.obj
49 	$(LINK) $(LDFLAGS) -out:$@.exe mecab-test-gen.obj libmecab.lib
50 
51 libmecab: $(OBJ) libmecab.obj
52 	$(LINK) $(LDFLAGS) -out:$@.dll $(OBJ) libmecab.obj -dll
53 
54 clean:
55 	$(DEL) *.exe *.obj *.dll *.a *.lib *.o *.exp *.def

最適化オプションとか余計なの取っ払いたいなぁ、みたいなのは放置して、最小限の改変ね。

これで 64bit 版 MeCab になる。んで、これを「手作業で」システムにインストールしたやつの場所に「上書き的に」置く。(無論「bin_x86、sdk_x86 みたいに元のは残しておく。)れば、mecab.exe はこれまで通り問題なく動いた。

で、natto-py はインストーラが書き込んだレジストリの値をみて libmecab.dll をロードするので、同じ場所に置いたんだから、動けば動こう、と思うも…。

状況は変わらず。具体的には:

 1 Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit (AMD64)] on win32
 2 Type "help", "copyright", "credits" or "license" for more information.
 3 >>> from natto import MeCab
 4 >>> with MeCab() as nm:
 5 ...     print(nm.parse('この星の一等賞になりたいの卓球で俺は、そんだけ!'))
 6 ...
 7 Could not initialize MeCab: cannot load library 'C:\Program Files (x86)\MeCab\bin\libmecab.dll': error 0xc1
 8 Traceback (most recent call last):
 9   File "C:\Python35\lib\site-packages\natto\mecab.py", line 149, in __init__
10     self.__mecab = self.__ffi.dlopen(env.libpath)
11   File "C:\Python35\lib\site-packages\cffi\api.py", line 146, in dlopen
12     lib, function_cache = _make_ffi_library(self, name, flags)
13   File "C:\Python35\lib\site-packages\cffi\api.py", line 828, in _make_ffi_library
14     backendlib = _load_backend_lib(backend, libname, flags)
15   File "C:\Python35\lib\site-packages\cffi\api.py", line 824, in _load_backend_lib
16     return backend.load_library(path, flags)
17 OSError: cannot load library 'C:\Program Files (x86)\MeCab\bin\libmecab.dll': error 0xc1
18 
19 During handling of the above exception, another exception occurred:
20 
21 Traceback (most recent call last):
22   File "<stdin>", line 1, in <module>
23   File "C:\Python35\lib\site-packages\natto\mecab.py", line 222, in __init__
24     raise MeCabError(err)
25 natto.api.MeCabError: cannot load library 'C:\Program Files (x86)\MeCab\bin\libmecab.dll': error 0xc1

0xc1 ってのは Access Violation、のはず。コンパイラが書き込んでる保護コード(DEBUGBREAK)にヒットしてる、とか確かそんなんだったと思う。んでこれは置き換え前とまったくおんなじ。うーん、ffi が何をしてるのか良くわからんからなぁ、措置の想像がつかんわ。これも 32bit/64bit な ABI 問題なんだとしたら、ffi はいったいどこから何をみて 64bit/32bit を決めているのだろう? CPython が amd64 なんだから、ffi も芋づるで amd64 前提になってないとおかしいはずで、であるなら置き換えればうまくいっても良さそうなもんで…。

てなわけで、これはお手上げ、てことにしとく。

で、公式 MeCab の公式 python バインディングを頑張って探るか、という話になるんだけれど、おそらく natto-py のノリから考えると、「natto-py と同じことを(ffiでなく)「公式 MeCab の公式 python バインディング相手に」やるのが良さげ。つまり「生の API だけでなく、natto-py と同じインターフェイスのラッパーを書く」。けどかなり大変そう。一日二日じゃ無理だな。難し過ぎるてほどでもなさそうではあるけれども。



Related Posts