libyamlとmacのsharedライブラリについて

先日Ruby Yamlの脆弱性対策(CVE-2014-2525) - rochefort's blog を行ったのですが
よくわからないことがあり調べてみました。  
 

2つの疑問

1つ目。どうして再ビルドが不要か。
sharedライブラリを使っているんだろうけど、どこでどう使っている?
 
2つ目。前回rbenv install時に RUBY_CONFIGURE_OPTS で enable-shared や with-libyaml-dir
を指定していないのにlibyamlの更新で事足りたのか。
(指定無しでもsharedライブラリとして扱われているのか?)
そもそも with-libyaml-dir っているんだろうか。
 

2つ目の方はまだよくわかってません。
psychのextconf.rbとかちらっと見たりしたのですが未解決。
 

とりあえず

psych.so

1つ目の方ですが、psych.rbの最初にpsych.soをrequireしています。 ./rbenv/versions/2.1.1/lib/ruby/2.1.0/psych.rb

require 'psych.so'

こいつをロードしていて、きっとlddとかしちゃうとhomebrewで入れたlibyamlを参照してるんだな
と予想してみたのですが、いくら探してもpsych.soファイルがありません。
 
 
./versions/2.1.1/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle
探している最中 psych.bundle というファイルを見つけました。
なんか怪しい。
試しにrenameしてrequireしてみるとエラーになりました。

$ ruby -e "puts require('psych.so')"
/Users/rochefort/.rbenv/versions/2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- psych.so (LoadError)
  from /Users/rochefort/.rbenv/versions/2.1.1/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'
  from -e:1:in `<main>'

こいつですね。
 
 

Macのsharedライブラリ

bundleとかsoとかの関係が分からなかったので調べてみると
.soや.dylibや.aファイル、共有ライブラリなどについて調べてみた - kanonjiの日記
 

MacではDynamic LinkingとDynamic Loadingは厳密に区別されている。
・Dynamic Loadingに当たるものは、Mac側ではバンドルと呼ばれる。
・Dynamic Linkingな共有ライブラリは.soではなく.dylibファイル。
・Dynamic Loadingの方は.bundleが推奨されるが、Linuxからの移植の場合、拡張子は.soのままな事が多い。

psych.rbでは、psych.bundleをDynamic Loadingしていて
bundleの方はlibyaml系をDiyamic Linkingしているという理解でいいんでしょうか。  
 

ldd

とりあえずbunldleをlddしてみようと思ったのですが
macにはlddは無いようで、代わりにotoolというコマンドが提供されているようです。
manを見ると、いろいろoptionはあるようですが、sharedライブラリの参照であれば -L でokです。

$ otool -L ./versions/2.1.1/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle
psych.bundle:
    /Users/rochefort/.rbenv/versions/2.1.1/lib/libruby.2.1.0.dylib (compatibility version 2.1.0, current version 2.1.0)
    /usr/local/lib/libyaml-0.2.dylib (compatibility version 3.0.0, current version 3.4.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
    /usr/local/lib/libgmp.10.dylib (compatibility version 12.0.0, current version 12.3.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
$ ll /usr/local/lib/libyaml-0.2.dylib
lrwxr-xr-x  1 rochefort  staff  45  3 30 18:46 /usr/local/lib/libyaml-0.2.dylib@ -> ../Cellar/libyaml/0.1.6/lib/libyaml-0.2.dylib

このdylibはsymlinkなので、当初の予想通りsharedライブラリで
libyamlはrubyの実行時に読み込まれるものでした。
めでたし、めでたし。
 
 

おまけ

細かい検証はしていないので、私の環境はこうだったというレベルの話です。
(する元気がない。。)

enable-shared や with-libyaml-dir 指定無しのruby2.1.0

$ otool -L ./versions/2.1.0/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle
./versions/2.1.0/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle:
    /usr/local/lib/libyaml-0.2.dylib (compatibility version 3.0.0, current version 3.2.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
    /usr/local/lib/libgmp.10.dylib (compatibility version 12.0.0, current version 12.3.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)

enable-shared や with-libyaml-dir を指定したruby2.1.1

$ otool -L ./versions/2.1.1/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle
./versions/2.1.1/lib/ruby/2.1.0/x86_64-darwin13.0/psych.bundle:
    /Users/rochefort/.rbenv/versions/2.1.1/lib/libruby.2.1.0.dylib (compatibility version 2.1.0, current version 2.1.0)
    /usr/local/lib/libyaml-0.2.dylib (compatibility version 3.0.0, current version 3.4.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
    /usr/local/lib/libgmp.10.dylib (compatibility version 12.0.0, current version 12.3.0)
    /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)

libruby.2.1.0.dylib が2.1.1にはあります。
多分これがenable-sharedの差だとは思うのですが、with-libyaml-dir はよくわかりません。  
ちなみに、build時のconfigureオプションは下記で見れます。
ruby2.1.0

$ ruby -rpp -rrbconfig -e "pp RbConfig::CONFIG['configure_args'].split(\"' '\")"
[" '--prefix=/Users/rochefort/.rbenv/versions/2.1.0",
 "--with-openssl-dir=/usr/local/opt/openssl",
 "--with-readline-dir=/usr/local/opt/readline",
 "CFLAGS= -O3 -Wno-error=shorten-64-to-32 ",
 "LDFLAGS=-L/Users/rochefort/.rbenv/versions/2.1.0/lib ",
 "CPPFLAGS=-I/Users/rochefort/.rbenv/versions/2.1.0/include '"]

 
ruby2.1.1

$ ruby -rpp -rrbconfig -e "pp RbConfig::CONFIG['configure_args'].split(\"' '\")"
[" '--prefix=/Users/rochefort/.rbenv/versions/2.1.1",
 "--enable-shared",
 "--with-readline-dir=/usr/local/opt/readline",
 "--with-openssl-dir=/usr/local/opt/openssl",
 "--with-libyaml-dir=/usr/local/opt/libyaml",
 "CFLAGS= -O3 -Wno-error=shorten-64-to-32 ",
 "LDFLAGS=-L/Users/rochefort/.rbenv/versions/2.1.1/lib ",
 "CPPFLAGS=-I/Users/rochefort/.rbenv/versions/2.1.1/include '"]

 
 

See Also

.soや.dylibや.aファイル、共有ライブラリなどについて調べてみた - kanonjiの日記
rubyをビルドしたときのconfigureオプションを表示する - Qiita
Ruby Yamlの脆弱性対策(CVE-2014-2525) - rochefort's blog