Mac OS Xで動的ライブラリのバージョン違いの警告が出た
たまに、nokogiri.gem
を使っているときに、
と言われて凹むことがあります、というか、先日ありました。原因は多分Mac OS X 10.7.3にしたことなんですがこういう時に何をすればいいのかという話です。
nokogiri.gem
はlibxml2
を使ったRubyのXML/HTMLパーサーなんですが、ビルド時に利用したlibxml2
のバージョンを覚えていて、実行時に違うバージョンを使うと文句を垂れます。というのも特定のlibxml2
はバグがアレすぎてnokogiri.gem
がまともに動かないのでそれを排除する目的でそういうことをしているんだと思います。
さて、こうなった時には誰が違うバージョンのlibxml2
をnokogiri.gem
より 先に ロードしているのを知る必要があります。普通は他のgemが明らかにlibxml2
を使っていたりして、あぁ、こいつが違うバージョンのlibxml2
をロードしてるのかー って気がつけることもあるのですが、まったく見当がつかない場合が問題です。
そこで、Mac OS Xで動的ライブラリのいろいろを司ってるのはdyld
ですが、その環境変数で便利なDYLD_PRINT_LIBRARIES
を使います。詳しくはman 1 dyld
。
とすると、ロードされたライブラリがずらずら出てきますので、どのタイミングで期待してないlibxml2
がロードされているのか眺めます。例えば、こんな感じ。
おや、ここでMac OS Xのlibxml2
が呼ばれていますね。これが原因っぽい。じゃあこれをロードした奴は誰だってことになるので、これより上でロードしているライブラリをotool -L
で調べていきます。
ほう、libxar-nossl.dylib
がlibxml2
をロードした犯人っぽいですね。で、
ほう、Security.framework
がlibxar-nossl.dylib
をロードしていますね。という感じで掘り進めます。で、この依存関係を呼ばれる逆順に書き出すとこうなります。
なんと、お前かー! まさか、memcached.gem
がlibxml2
をロードしているとは思いもよりませんでした。memcached.gem
はmemcached
のクライアントですがXMLを使う余地など無いのでパッと見さっぱりわからないですね。
多分、10.7.3でどこかの誰かがこの依存関係を創り上げたのではないかと思っていますが、今後SASL関係のやつらが全部libxml2
をロードすると思うとげんなりです。
で、この場合、解決策はnokogiri.gem
を素直に/usr/lib/libxml2.2.dylib
を使うようにビルドしなおせばいいのですがまあ、最適解はそれぞれの状況に応じて変わるのでなんとも言えません。
というわけで、原因がわかってめでたしめでたし!
おまけ - gdbで追いかける
最初、DYLD_PRINT_LIBRARIES
なんて気が付かなかったのでgdb
してdlopen
でブレイクポイント立ててロードしている奴らを知ろうと思いました。結果から言えばdlopen
だけではすべてのdyld
のロードを見られるわけではないので失敗したのですが、忘れないようにやり方をメモしておきます。この場合は、dtrace
しても良いんだけど。
ここでのポイントはdlopen
はデバッグ情報がないのでそのままではgdb
で引数が表示できないこと。そこでx86_64
の場合、rdiレジスタ
から順にrsi
、rdx
、rcx
、r8
、r9
に引数が入ってるので、それを見ていきます。こんな感じ。
便利ですね!
多分もっとかっこいい方法があるはずなので、是非@niwまで教えてください!