【Ruby】OS XでDigest::MD5を使おうとすると「Symbol not found: _rb_Digest_MD5_Finish (LoadError)」なるエラーが出る問題

週末に久々に会った友人から「お前アナログゲーム以外のこともブログに書けよ」って言われたので、メモ代わりに最近が自分が嵌った落とし穴について。 YosemiteRuby 2.2を入れたところ、MD5を扱う標準ライブラリのDigest::MD5が使えなくて困った。

発生した問題

例えばこんな感じでRubyをインストールする。

$ rbenv install 2.2.1 # rbenvでCRuby 2.2.1をインストール
$ rbenv local 2.2.1   # 現在のディレクトリで2.2.1を使用

で、digest/md5requireすると……

$ ruby -e 'require "digest/md5"'
/Users/autopp/.rbenv/versions/2.2.1/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in
`require': dlopen(/Users/autopp/.rbenv/versions/2.2.1/lib/ruby/2.2.0/x86_64-darwin14/digest/md5.bundle,
9): Symbol not found: _rb_Digest_MD5_Finish (LoadError)
  Referenced from:
/Users/autopp/.rbenv/versions/2.2.1/lib/ruby/2.2.0/x86_64-darwin14/digest/md5.bundle
  Expected in: flat namespace
 in /Users/autopp/.rbenv/versions/2.2.1/lib/ruby/2.2.0/x86_64-darwin14/digest/md5.bundle
- /Users/autopp/.rbenv/versions/2.2.1/lib/ruby/2.2.0/x86_64-darwin14/digest/md5.bundle
from /Users/autopp/.rbenv/versions/2.2.1/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in
`require'
from -e:1:in `<main>'

あまり目にしない例外を吐いて死ぬ。 ここではrbenvを使っているが、恐らく他のツール野良ビルドでも発生する。 またRubyのバージョンは2.1でも発生することを確認している。

Digest::MD5はまあ色んな所で使われていて、例えばbundler/setupなんかも使えなくなってしまうため、これは無視できない問題である。

解決策

先ほどのエラーログではCのdlopenのエラー出力らしきものが含まれていることから「たぶんRuby自体のインストールに問題があったんだろうな」というところまでは検討が付くが、思い当たる節は特に無い。

ひたすらクエスチョンマークを頭から垂れ流しながらググっていてたら、次のstackoverflowの質問に行き着いた。

Mountain Lion - Rails - Symbol not found: _rb_Digest_MD5_Finish (LoadError)

これのアンサーによると、Mac OSRubyをインストールする時に環境変数C_INCLUDE_PATHが設定されているとマズイらしい。 なんじゃそりゃと思うような、まあそんなこともあるかと思うような……

手元の環境で確認してみると確かに定義されている。

$ if [[ $C_INCLUDE_PATH ]]; then echo yes; fi
yes

Rubyのインストール時にこの環境変数がセットされてさえいなければいいらしいので、以下の手順で再インストールすればよい。

$ rbenv uninstall 2.2.1 # 一度アンインストールして
$ unset C_INCLUDE_PATH  # 環境変数を一時的に削除して
$ rbenv install 2.2.1   # 再インストール

改めてdigest/md5requireしてみる。

$ rbenv local 2.2.1
$ ruby -e 'require "digest/md5"; puts "OK"'
OK

OK。

この問題、踏むと致命的なわりにはあまり情報が出てこなかった。 そもそもC_INCLUDE_PATHは普通はセットしないので、踏んだ人も少ないのだろうと推測(gccclangなら-Iオプションで十分なはず)。 正直なところ自分もいつC_INCLUDE_PATHなんかを設定したのか覚えが無いが、たぶん昔何かの都合で.bashrcに書いたのがずっと残っていたのだろう。


なんにせよアナログゲーム以外の記事も書いたので、友人(非エンジニア)の不満も解消できただろう。 これで次はアナログゲームの記事が書ける。