RMeCabが64bit版だけExceptionする場合の対処

RMeCabが64bit版だけExceptionする。 32bit版は何事もなく動く。

環境

下環境で発生


RとRStduioのインストール先

  • D:/Program/R
  • D:/Program/RStdio

MeCabインストール先


症状

library(RMeCab)
res <- RMeCabC("すもももももももものうち") #ここで落ちる

exceptionで特にエラーを吐かず落ちる

イベントログ(下記抜粋)

障害が発生しているアプリケーション名: rsession.exe 障害が発生しているモジュール名: R.dll、バージョン: 3.40.7034.0 例外コード: 0xc0000005 障害オフセット: 0x00000000000f3819

例外コード: 0xc0000005はメモリでアクセス違反だったような気がする。

twitterでの作成者(石田先生?)からの助言(抜粋)

twitterでつぶやいていたら、RMeCabを開発した方とおぼしき方から(石田先生?)有難い助言が!!!

先生の方の64bit版Win7は現象が再現しないとのこと。

先生の貴重な時間を割いて調べて頂けるなんてありがたや。 ここまでやってもらったら、自分でも頑張って少しは手がかりをつかまなくては!

Rを入れなおしてためす

基本に立ち戻り、再インストールから検証

  • R 3.4.0 再インストール 結果 ×

Rを最新にしてみる。

  • R 3.4.1 インストール 結果 ×

入れ直しでは治らなかった・・・そんな簡単じゃないよね!

Rのdebug機能を試す

アート・オブ・Rプログラミングの13章デバックを参考にどこでエラーが起きるか追いかける。

library(RMeCab)
debug(RMeCabC)
res <- RMeCabC("すもももももももものうち")

debugging in: RMeCabC("すもももももももものうち")
debug: {
    if (!is.character(str)) {
        str <- as.character(str)
    }
    if (nchar(str) < 1) {
        stop("first argument must be specified")
    }
    if (is.null(dic) || is.na(dic)) {
        dic = ""
    }
    else if ((xl <- nchar(dic)) > 0) {
        dic <- paste(dirname(dic), basename(dic), sep = "/")
        if (!(file.exists(dic))) {
            cat("specified dictionary file not found; result by default dictionary.\\n")
            dic = ""
        }
        else {
            dic <- paste("-u", dic)
        }
    }
    if (is.null(mecabrc) || is.na(mecabrc) || (nchar(mecabrc)) < 
        2) {
        mecabrc = ""
    }
    else {
        mecabrc <- paste(dirname(mecabrc), basename(mecabrc), 
            sep = "/")
        if (!(file.exists(mecabrc))) {
            cat("specified mecabrc not found; result by default mecabrc.\\n")
            mecabrc = ""
        }
        else {
            mecabrc <- paste("-r", mecabrc)
        }
    }
    opt <- paste(dic, mecabrc, etc)
    ret <- .Call("RMeCabC", as.character(str), as.integer(mypref), 
        as.character(opt), PACKAGE = "RMeCab")
    return(ret)
}
Browse[2]> n
debug: if (!is.character(str)) {
    str <- as.character(str)
}
Browse[2]> n
debug: if (nchar(str) < 1) {
    stop("first argument must be specified")
}
Browse[2]> n
debug: if (is.null(dic) || is.na(dic)) {
    dic = ""
} else if ((xl <- nchar(dic)) > 0) {
    dic <- paste(dirname(dic), basename(dic), sep = "/")
    if (!(file.exists(dic))) {
        cat("specified dictionary file not found; result by default dictionary.\\n")
        dic = ""
    }
    else {
        dic <- paste("-u", dic)
    }
}
Browse[2]> n
debug: if ((xl <- nchar(dic)) > 0) {
    dic <- paste(dirname(dic), basename(dic), sep = "/")
    if (!(file.exists(dic))) {
        cat("specified dictionary file not found; result by default dictionary.\\n")
        dic = ""
    }
    else {
        dic <- paste("-u", dic)
    }
}
Browse[2]> n
debug: if (is.null(mecabrc) || is.na(mecabrc) || (nchar(mecabrc)) < 
    2) {
    mecabrc = ""
} else {
    mecabrc <- paste(dirname(mecabrc), basename(mecabrc), sep = "/")
    if (!(file.exists(mecabrc))) {
        cat("specified mecabrc not found; result by default mecabrc.\\n")
        mecabrc = ""
    }
    else {
        mecabrc <- paste("-r", mecabrc)
    }
}
Browse[2]> n
debug: mecabrc = ""
Browse[2]> n
debug: opt <- paste(dic, mecabrc, etc)
Browse[2]> n

ということで、以下の部分に行く前に落ちることが分かった。

  ret <- .Call("RMeCabC", as.character(str), as.integer(mypref), 
    as.character(opt), PACKAGE = "RMeCab")

.Callはc++のDLLを呼ぶ関数。 やはり、c++のDLLを呼ぶところでエラーになるらしい。

ソースがないのでこれ以上追えない。

ソースからコンパイルする準備

Rtools34.exeをインストー
https://cran.r-project.org/bin/windows/Rtools/
から Rtools34.exe R 3.3.x and later をダウンロードして実行
インストール場所は

D:\Program\Rtools  

(※本当は標準のc:\Rtoolsに入れた方が楽)

Edit the system PATH.は Save version information to registry にチェック

次のSystem Path の編集は 64bitマシンなら 3行目を

D:\Program\R\R-3.4.1\bin
D:\Program\Rtools\bin
D:\Program\Rtools\mingw_32\bin
↓↓↓ 変更
D:\Program\R\R-3.4.1\bin
D:\Program\Rtools\bin
D:\Program\Rtools\mingw_64\bin

に変更


RのMakeconfを変更

※ 標準のc:\Rtoolsに入れた場合はこの作業はいらない。

D:\Program\R\R-3.4.1\etc\x64\Makeconf"

# 以下の二つ書き換え
#BINPREF ?= c:/Rtools/mingw_64/bin/
BINPREF ?= D:/Program/Rtools/mingw_64/bin/
#LOCAL_SOFT = d:/Compiler/gcc-4.9.3/local330
LOCAL_SOFT = D:/Program/Rtools/mingw_64

同じように編集32bit用も編集

D:\Program\R\R-3.4.1\etc\i386\Makeconf"

# 以下の二つ書き換え
#BINPREF ?= c:/Rtools/mingw_64/bin/
BINPREF ?= D:/Program/Rtools/mingw_64/bin/
#LOCAL_SOFT = d:/Compiler/gcc-4.9.3/local330
LOCAL_SOFT = D:/Program/Rtools/mingw_64

この後、一旦R再起動

RでPATHを確認

Sys.getenv('PATH')
[1] "D:\\Program\\Rtools\\bin;D:\\Program\\Rtools\\mingw_64\\bin";

コンパイラがRから呼び出せるか確認

system('g++ -v')
Using built-in specs.
COLLECT_GCC=D:\Program\Rtools\mingw_64\bin\G__~1.EXE
COLLECT_LTO_WRAPPER=D:/Program/Rtools/mingw_64/bin/../libexec/gcc/x86_64-w64-mingw32/4.9.3/lto-wrapper.exe
Target: x86_64-w64-mingw32
Configured with: ../../../src/gcc-4.9.3/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64 --with-gxx-include-dir=/mingw64/x86_64-w64-mingw32/include/c++ --enable-static --disable-shared --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-isl-version-check --disable-cloog-version-check --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-mpc=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-isl=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --with-cloog=/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static --enable-cloog-backend=isl --with-pkgversion='x86_64-posix-seh, Built by MinGW-W64 project' --with-bugurl=http://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -I/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -I/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/include -I/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS= LDFLAGS='-pipe -L/home/Jeroen/mingw-gcc-4.9.3/x86_64-493-posix-seh-rt_v3-s/mingw64/opt/lib -L/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-zlib-static/lib -L/home/Jeroen/mingw-gcc-4.9.3/prerequisites/x86_64-w64-mingw32-static/lib '
Thread model: posix
gcc version 4.9.3 (x86_64-posix-seh, Built by MinGW-W64 project) 

RでMAKEがどこに設定されているか確認

system('where make')
D:\Program\Rtools\bin\make.exe

ソースからコンパイル

その1

一旦既存のパッケージは削除
MacLinuxと同じタイプでやってみる。

remove.packages("RMeCab")
install.packages("RMeCab", repos = "http://rmecab.jp/R", type = "source") 

D:/Program/Rtools/mingw_32/bin/../lib/gcc/i686-w64-mingw32/4.9.3/../../../../i686-w64-mingw32/bin/ld.exe: cannot find -lmecab
collect2.exe: error: ld returned 1 exit status
DLLは生成されませんでした 
ERROR: compilation failed for package 'RMeCab'
* removing 'D:/Program/R/R-3.4.1/library/RMeCab'

 ダウンロードされたパッケージは、以下にあります 
        ‘C:\Users\kuma\AppData\Local\Temp\RtmpOWFHXp\downloaded_packages’ 
 警告メッセージ: 
1:  命令 '"D:/Program/R/R-3.4.1/bin/x64/R" CMD INSTALL -l "D:\Program\R\R-3.4.1\library" C:\Users\kuma\AppData\Local\Temp\RtmpOWFHXp/downloaded_packages/RMeCab_0.99997.tar.gz' の実行は状態 1 を持ちました  
2:  install.packages("RMeCab", repos = "http://rmecab.jp/R", type = "source"): 
   パッケージ ‘RMeCab’ のインストールは、ゼロでない終了値をもちました 

失敗、インストールできなかった。

その2

ソースのダウンロード
https://github.com/IshidaMotohiro/RMeCab
D:\RMeCabに解凍しておく

パッケージのチェック コマンドプロンプトで以下実行

cd /d D:\
R CMD check RMeCab  --no-manual --no-install
* using log directory 'D://RMeCab.Rcheck'
* using R version 3.4.1 (2017-06-30)
* using platform: x86_64-w64-mingw32 (64-bit)

* DONE
Status: 4 WARNINGs, 2 NOTEs
See
  'D://RMeCab.Rcheck/00check.log'
for details.

WARNINGがいくつかあるが、Errorはないので平気? D://RMeCab.Rcheck/00check.logにログが残る。

パッケージのビルド

R CMD build RMeCab
 * checking for file 'RMeCab/DESCRIPTION' ... OK
 * preparing 'RMeCab':
 * checking DESCRIPTION meta-information ... OK
 * cleaning src
 * checking for LF line-endings in source and make files
 * checking for empty or unneeded directories
 * building 'RMeCab_0.99997.tar.gz'

tar.gzファイルができる。

Windows用パッケージのビルド、インストー

R CMD INSTALL --build RMeCab_0.99997.tar.gz

///途中省略

D:/Program/Rtools/mingw_32/bin/g++ -shared -s -static-libgcc -o RMeCab.dll tmp.d
ef Ngram.o NgramDF.o NgramDF2.o RMeCab.o RMeCabC.o RMeCabDoc.o RMeCabFreq.o RMeC
abMx.o RMeCabText.o collocate.o docDF.o docMatrix2.o docMatrixDF.o docNgram2.o d
ocNgramDF.o setMeCabMap.o -lmecab -LD:/Program/Rtools/mingw_32/lib/i386 -LD:/Pro
gram/Rtools/mingw_32/lib -LD:/Program/R/R-3.4.1/bin/i386 -lR
D:/Program/Rtools/mingw_32/bin/../lib/gcc/i686-w64-mingw32/4.9.3/../../../../i68
6-w64-mingw32/bin/ld.exe: cannot find -lmecab
collect2.exe: error: ld returned 1 exit status
DLLヘカャウワケナオス
ERROR: compilation failed for package 'RMeCab'
* removing 'D:/Program/R/R-3.4.1/library/RMeCab'

最後にコンパイルがこける。 エラーメッセージからMeCabのDLLを探しているらしいので

mecabのインストール先から “C:\Program Files (x86)\MeCab\bin\libmecab.dll” をコピーして以下にコピー D:\Program\R\R-3.4.1\bin\i386

ただし、このままだと64bit版のMeCabのDLLがない。

64bit版MeCabのDLL作成

以下記事を参考に作成 (ちなみに思考停止して作成したので内容はよくわかってないです。) http://qiita.com/tobesan/items/6b6f3a025fdd177ef52a

MeCabのソースをダウンロード

https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE

事前準備

事前に準備でコピー

ダウンロードしたmecab-0.996.tar.gz を展開します。 ここでは以下に展開しました。 - D:\Download\mecab-0.996

MeCabソースの修正、ビルド

mecab-0.996/srcフォルダ内のいくつかのファイルを修正します。 (旧)以下を(新)以下に変更してください

Makefile.msvc.in 内を Windows 7 64bit用に修正 6行目 /MACHINE:X86 → /MACHINE:X64

(旧)LDFLAGS = /nologo /OPT:REF /OPT:ICF /LTCG /NXCOMPAT /DYNAMICBASE /MACHINE:X86 ADVAPI32.LIB
(新)LDFLAGS = /nologo /OPT:REF /OPT:ICF /LTCG /NXCOMPAT /DYNAMICBASE /MACHINE:X64 ADVAPI32.LIB

8行目 -DDIC_VERSION=@DIC_VERSION@ → -DDIC_VERSION=102

 (旧)-DDLL_EXPORT -DHAVE_GETENV -DHAVE_WINDOWS_H -DDIC_VERSION=@DIC_VERSION@ \
 (新)-DDLL_EXPORT -DHAVE_GETENV -DHAVE_WINDOWS_H -DDIC_VERSION=102 \

9行目 -DVERSION=“\”@VERSION@“\”“ → -DVERSION=”\“0.996\”"

 (旧) -DVERSION="\"@VERSION@\"" -DPACKAGE="\"mecab\"" \
 (新) -DVERSION="\"0.996\"" -DPACKAGE="\"mecab\"" \

11行目 "\“c:\Program Files\mecab\etc\mecabrc\”“ →  ”\“c:\mecab\etc\mecabrc\”"

mecabrcの場所を指定してください
 (旧) -DMECAB_DEFAULT_RC="\"c:\\Program Files\\mecab\\etc\\mecabrc\""
 (新) -DMECAB_DEFAULT_RC="\"c:\\mecab\\etc\\mecabrc\""

356行目 size_t → unsigned int

feature_index.cpp
 (旧)case 't':  os_ << (size_t)path->rnode->char_type;     break;
 (新)case 't':  os_ << (unsigned int)path->rnode->char_type;     break;

writer.cpp 260行目 size_t → unsigned int

 (旧)case 'L': *os << (size_t)lattice->size(); break;
 (新)case 'L': *os << (unsigned int)lattice->size(); break;

mecab.h 1125行目 #ifndef SIWG → #ifndef SWIG

 (旧) #ifndef SIWG
 (新) #ifndef SWIG

common.h include部分に追記 #include

(新) #include <iterator>

Build Tools for Visual Studio 2017

コンパイルに必要なので以下ダウンロードしてインストーhttps://www.visualstudio.com/ja/thank-you-downloading-visual-studio/?sku=BuildTools&rel=15

ツールを実行し、Visual C++ Build Toolsを選択して

場所は(サイズが3.39GBとでかすぎるので)
D:\Program\Microsoft Visual Studio\2017\BuildTools
に変更してインストー

コンパイル

コマンドプロンプトを管理者権限で立ち上げて以下実行

cd /d D:\Download\mecab-0.996\src
call "D:\Program\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64
nmake -f Makefile.msvc.in

これで、直下にlibmecab.dllができるので、以下にコピー
D:\Program\R\R-3.4.1\bin\x64

ふたたびRMeCabコンパイル

D:\Program\R\R-3.4.1\bin\x64にコンパイルした64bitのlibmecab.dll
D:\Program\R\R-3.4.1\bin\i386にはMeCabに元からある32bitのlibmecab.dll
があるのを確認後、ビルド

cd /d D:\
R CMD INSTALL --build RMeCab_0.99997.tar.gz

# 最後に以下のような表示になればインストール成功
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
*** arch - i386
*** arch - x64
* MD5 sums
packaged installation of 'RMeCab' as RMeCab_0.99997.zip
* DONE (RMeCab)

動作確認

Rの64ビット版で以下実行

library(RMeCab)
res <- RMeCabC("すもももももももものうち")
res
[[1]]
    名詞 
"すもも" 

[[2]]
助詞 
"も" 

[[3]]
  名詞 
"もも" 

[[4]]
助詞 
"も" 

[[5]]
  名詞 
"もも" 

[[6]]
助詞 
"の" 

[[7]]
  名詞 
"うち" 

うごいた!

まとめ

RMeCabの64bit版は64bit用にコンパイルしたMeCabが使われている。 したがって、32bitと64bitでは違うDLLなので、 32bit版だけ動いて64bit版だけ動かないのは有りうる。

機種依存の原因はわからなかったが、 RMeCabの方のソースはいじっていないので、 おそらくコンパイラのバージョンが違うとかMeCabコンパイラの仕方が 違うなどが原因として考えられる。

けどまあ、初学者なので自分はっきりいって、

        |\           /|
        |\\       //|
       :  ,> `´ ̄`´ <  ′
.       V            V
.       i{ ●      ● }i
       八    、_,_,     八    わけがわからないよ 
.       / 个 . _  _ . 个 ',
   _/   il   ,'    '.  li  ',__

おしまい