【Red Data Tools開発者に聞け!】(第12回)Ruby とバイナリレベルの互換性、ABI (Application Binary Interface) について

Red Data Tools

今回から私も参加させていただいている Red Data Tools の youtube チャンネルで毎週ライブ配信中の【Red Data Tools開発者に聞け!】の振り返り記事を書いていきます。

基本的には動画内で解説されている内容を記載したものになりますが、クイックに動画内でどんなことに触れられているのかな?ということを知れるイントロダクションになれば良いなと思います!

Red Data Tools開発者に聞け!第12回 (Rubyバインディングに新機能を追加するシリーズpart7)

今回やったこと

  • irb を実行してその中で apache/arrow のライブラリを実行してみる
  • その際に遭遇したエラー2つの解消
    • エラー①: 'require': incompatible library version
    • エラー②: 'require': cannot load such file -- arrow.so (LoadError)

エラー①: 'require': incompatible library version の解消

このエラーは実行した irb 内で arrow を require する際に発生したものです。こちらは相互に利用されるプログラム同士が互換性がないことを意味します。

プログラムの互換性は ABI (Application Binary Interface) にて定義されています。プログラムのソースコードはコンピューターで実行されるときに、一旦バイナリコードに変換されます。ここには実際にコンピューターで直接的に処理される際に必要な情報がさまざま含まれています。

一例ですが、どの命令セットを利用するか?エンディアンは何を使用するか?などが含まれており、これらが異なるプログラム同士は正しく動きません。そのため、ABI によって互換性を定義しておき、互換性がない場合はエラーとなるようになっています。

結果から言うと今回は irb と arrow で利用している ruby 同士で互換性がありませんでした。

互換性の確認には otool コマンドを利用することができます。

otool コマンドはオブジェクトファイルの中身を分析して結果を表示するというコマンドです。オブジェクトファイルとはソースコードをコンパイルした結果のバイナリコードを含む中間的なデータ表現のことで、ここで得られる結果にはバイナリレベルの互換性がどうなっているかを含んでいます。

# irb で利用している ruby の互換性を確認
❯ otool -L $(rbenv which ruby)
/Users/teradamasaru/.rbenv/versions/3.0.3/bin/ruby:
  /Users/teradamasaru/.rbenv/versions/3.0.3/lib/libruby.3.0.dylib (compatibility version 3.0.0, current version 3.0.3)

# arrow で利用している ruby の互換性を確認
❯ otool -L ext/arrow/arrow.bundle
  ext/arrow/arrow.bundle:
    /Users/teradamasaru/.rbenv/versions/3.2.0/lib/libruby.3.2.dylib (compatibility version 3.2.0, current version 3.2.0)

libruby.<version>.dylib が ruby のバイナリを指していて、irb で利用している ruby は互換性のあるバージョンが 3.0.0 に対して、arrow で利用している ruby は互換性のあるバージョンが 3.2.0 になっています。

今回の場合は irb で利用する ruby を arrow に合わせる形で対応しました。私の環境では rbenv を利用しているため、具体的には以下のコマンドを実行しています。

❯ rbenv global 3.2.0

エラー②: 'require': cannot load such file -- arrow.so (LoadError) の解消

こちらも同様に irb 内で arrow を require した際に発生したエラーです。

エラー内容自体は単純で、arrow.so というファイルが見つかりませんよ。ということです。ただ、ファイル自体は確実にローカルに存在しているのですが、irb 内ではそれを見つけることができないようです。

ここで .so ファイルとは共有ライブラリを指すのですが、Mac OS の場合は .bundle という拡張子で用意されている場合もあります。

今回私の環境は Mac で構築していますので、ここで読み込みたいファイルは arrow.bundle になります。こちらのファイルは ext/arrow 配下に存在しています。

❯❯ (git:main) ~/dev/apache/arrow/ruby/red-arrow
❯ ls -l ext/arrow | grep arrow.bundle
-rwxr-xr-x  1 teradamasaru  staff  356537  5 29 20:56 arrow.bundle

ファイル自体は存在しているのに、なぜ読み込まれないか?それは irb ではファイルの検索パスに ext/arrow が含まれていないからです。irb にパスを通すには -I <PATH> オプションをつけて実行します。

❯❯ (git:main) ~/dev/apache/arrow/ruby/red-arrow
❯ bundle exec env GI_TYPELIB_PATH=/tmp/local/lib/girepository-1.0 DYLD_LIBRARY_PATH=/tmp/local/lib irb -I ext/arrow

これで無事 arrow を require することができました。ちなみに irb の中で通っているパスの一覧は $LOAD_PATH に格納されています。ここで目的のパスが存在するかを確認することができます。

irb(main):001:0> require 'arrow'
=> true

irb(main):006:0> $LOAD_PATH.grep(/ext\/arrow/)
=> ["/Users/teradamasaru/dev/apache/arrow/ruby/red-arrow/ext/arrow"]

コメント

タイトルとURLをコピーしました