natto-py もいけるんちゃうか、と思うも…。
前回のは、はなから「python バインディング」にしか興味がない、って考えでやったけれど、あの setup.py が書けるなら、当然「64bit 版 MeCab」を作れる:
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 と同じインターフェイスのラッパーを書く」。けどかなり大変そう。一日二日じゃ無理だな。難し過ぎるてほどでもなさそうではあるけれども。