きりかノート 3冊め

おあそびプログラミング

MacPortsのrubyがsslのエラーで落ちる

rabbitユーザとかは注意。お知らせしてくれた@masarakkiさん、@nahiさん、ありがとうざいます。

たとえばこんな感じ。

 % rabbit --help
 Xlib:  extension "RANDR" missing on display "/tmp/launch-AQLo1z/org.x:0".
 /opt/local/lib/ruby/1.8/openssl/ssl-internal.rb:30: [BUG] Segmentation fault
 ruby 1.8.7 (2010-08-16 patchlevel 302) [i686-darwin10]

 zsh: abort      rabbit --help
 %

いろいろ詰めていくと、最小の再現パターンはこんな感じ。

 % ruby -rglib2 -ropenssl -e ''

glib2とopensslの順番を入れ替えるとだいじょぶだったりする。原因はrubyの拡張ライブラリopenssl.bundleがリンクしているport:opensslのlibcrypto.1.0.0.dylibとglib2がCarbon経由で参照しているMac組み込みの/usr/lib/libcrypto.0.9.8.dylibの両方をロードしてしまうため。

回避方法は次のいずれか

  1. rubyのext/opensslがリンクするlibsslを0.9.8にするようにする
  2. glib2からCarbonをリンクしないようにする
  3. twolevel_namespaceで別々のlibsslをロードしても大丈夫にする

希望としてはglib2での対処なんだけど、他の人を説得できる自信はあんまない。twolevel_namespaceのは考えただけで本当に解決するかはわからない。

最初のは、すでにMacPortsで0.9.8がインストールされている場合はこんなふうにすればよい。

 % sudo port -f deactivate openssl
 % sudo port activate openssl @0.9.8o_0
 % sudo port -n upgrade --force ruby

これを英語にしてmacports-devに投げる予定。はあ、、

(2010/08/27 追記)また、opensslがすでに1.0.0系しかない場合は、MacPortsのopensslにリンクしないrubyを使うようにすることで回避できます。

   % sudo port -f deactivate openssl       # opensslを一時的に無効に
   % sudo port edit ruby                   # rubyの依存関係からopensslを外す
 Index: ruby/Portfile
 ===================================================================
 --- ruby/Portfile	(revision 70788)
 +++ ruby/Portfile	(working copy)
 @@ -31,7 +31,6 @@

  depends_lib		port:libiconv \
                                 port:readline \
 -				port:openssl \
                                 port:zlib \
                                 port:ncurses
   % sudo port -n upgrade --force ruby                # rubyを再コンパイル
   % sudo port activate openssl @1.0.0a_0+universal   # opensslを戻す
   % otool -L /opt/local/lib/ruby/1.8/i686-darwin10/openssl.bundle
   /opt/local/lib/ruby/1.8/i686-darwin10/openssl.bundle:
           /opt/local/lib/libruby.dylib (compatibility version 1.8.0, current version 1.8.7)
           /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8)
           /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 0.9.8)
           /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.0)
           /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 227.0.0)

おぼえがき、今回の調べかた

ext/openssl単体をrequireしたとき("ruby -ropenssl -e ''")では問題が起きないことから、ほかのライブラリとの組み合わせっぽいとこまでは早めに推測できた。で、拡張ライブラリをいろいろ使ってるrabbitで試してみて、ruby-gnome2のモジュールを試してみたら、glib2がアウトらしいことを見つけた。

次はglib2からリンクしているどのライブラリ・フレームワークが影響しているかを調べる。

実行時のライブラリ読み込みは、環境変数 DYLD_PRINT_LIBRARIES_POST_LAUNCH (see man dyld(1))を有効にして様子を見る。

 % DYLD_PRINT_LIBRARIES_POST_LAUNCH=1 ruby -rglib2 -ropenssl -e ''
 dyld: loaded: /opt/local/lib/ruby/1.8/i686-darwin10/thread.bundle
 dyld: loaded: /opt/local/lib/ruby/vendor_ruby/1.8/i686-darwin10/glib2.bundle
 dyld: loaded: /opt/local/lib/libgobject-2.0.0.dylib
 dyld: loaded: /opt/local/lib/libgthread-2.0.0.dylib
 dyld: loaded: /opt/local/lib/libglib-2.0.0.dylib
 dyld: loaded: /opt/local/lib/libintl.8.dylib
 dyld: loaded: /opt/local/lib/libiconv.2.dylib
 dyld: loaded: /System/Library/Frameworks/Carbon.framework/Versions/A/Carbon
 dyld: loaded: /usr/lib/libresolv.9.dylib
   :
 dyld: loaded: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib
 dyld: loaded: /usr/lib/libcrypto.0.9.8.dylib
 dyld: loaded: /System/Library/PrivateFrameworks/TrustEvaluationAgent.framework/Versions/A/TrustEvaluationAgent
   :
 dyld: loaded: /opt/local/lib/ruby/1.8/i686-darwin10/openssl.bundle
 dyld: loaded: /opt/local/lib/libssl.1.0.0.dylib
 dyld: loaded: /opt/local/lib/libcrypto.1.0.0.dylib

ここはもうてきとーにotool -Lで試し打ちして確認。/opt/local/lib/*.dylibには該当がないことは確認。で、/System/Library/Frameworksとかになるとリンク関係が深いので手作業だとキツイ。[otool recursive]で検索してでてきたpythonスクリプトを利用して、Carbon.frameworkが原因であることを見つけた。