LoginSignup
10
9

More than 5 years have passed since last update.

Ruby拡張ライブラリ間でシンボル名が衝突する(OS X限定)

Posted at

RubyはともかくCで書かれた拡張ライブラリになるとかなりOS固有の部分がでてきます。
例えばfoo_ext.bundleとbar_ext.bundleが同名の関数fを定義していると、シンボルの束縛がうまくいかず、意図したfが呼ばれないことがあります。

確認方法

DYLD_PRINT_BINDINGS環境変数をYESにして実行すると、各シンボルがどのように解決されているかを確認できます。

$ DYLD_PRINT_BINDINGS=YES ruby app.rb 2>&1 | grep _f
dyld: lazy bind: foo_ext.bundle:0x105C55010 = foo_ext.bundle:_f, *0x105C55010 = 0x105C54E90
dyld: lazy bind: bar_ext.bundle:0x105C88010 = foo_ext.bundle:_f, *0x105C88010 = 0x105C54E90

上記の例だと、foo_ext内のfbar_ext内のfも、foo_extfに束縛されていることが分かります。

参考: dyld(1) OS X Manual Page

なぜ発生するのか

MacOS Xの利用しているMach-Oファイルフォーマットにはflat namespaceとtwo-level namespaceがある。
Rubyがデフォルトで利用しているのはflat namespaceだが、これには複数のライブラリが同名のシンボルを含めれない制限がある。

In the flat namespace, two or more libraries cannot contain symbols with different implementations that share the same name because the dynamic linker cannot know which library contains the preferred implementation.

-- 引用元: Executing Mach-O Files

ちなみにflat namespaceに含まれているシンボル一覧はdyldinfoコマンドで確認できる。

$ dyldinfo -lazy_bind foo_ext.bundle
lazy binding information (from lazy_bind part of dyld info):
segment section          address    index  dylib            symbol
__DATA  __la_symbol_ptr  0x00001010 0x0000 flat-namespace   _f

解決方法

flat namespaceではなくtwo-level namespaceを使うようにextconf.rbを修正する。

case RbConfig::CONFIG['host_os'].downcase
when /darwin/
  $DLDFLAGS.gsub!("-Wl,-flat_namespace","")
end

関連リンク

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9