Ruby 1.9.1〜を構成する三つのバージョン

Ruby 1.9.1RC1の標準的な$LOAD_PATHは以下のようになる。

/usr/local/lib/ruby/site_ruby/1.9.1
/usr/local/lib/ruby/site_ruby/1.9.1/i686-linux
/usr/local/lib/ruby/site_ruby
/usr/local/lib/ruby/vendor_ruby/1.9.1
/usr/local/lib/ruby/vendor_ruby/1.9.1/i686-linux
/usr/local/lib/ruby/vendor_ruby
/usr/local/lib/ruby/1.9.1
/usr/local/lib/ruby/1.9.1/i686-linux

ここで気になるのは末尾付近の1.9.1である。

Ruby 1.8シリーズまではこの部分に入るのは1.8のようにマイナーバージョン(X.Y.ZのY)までであった。これはマイナーバージョンレベルでの互換性が保たれる――か、少なくともそのようにする意志があると考えられる。ところが今回のリリースされた実装ではこの部分にフルバージョン(X.Y.Zのすべて)が埋め込まれている。となると1.9.1以降ではそのレベルで、つまりマイナーバージョンアップされるごとにすべての互換性が失われるのだろうか。

もしそうであるならばとても困ったことになる。というのは、将来リリースされるRuby 1.9.2にはバグ修正やことによってはセキュリティ修正が含まれているはずであり、通常はできるだけ早くバージョンアップすべきものとなる。ところが、前述のような事情においては互換性の点からRuby本体以外とは別にインストールしたすべてのコード(Rubyで書かれたコードとC言語などで書かれた拡張ライブラリの両方)が利用できなくなる心配があり、マイナーバージョンアップであってもおいそれとは実施できない。ついでに言えばすべてのコードが$LOAD_PATHから外れてしまうことにもなる。

そのような危惧をもって質問したのが[ruby-dev:37748]である。

実はこのメールを送る前にIRCで意図を尋ねていたのであって、質問というよりも確認を目的とするものとなってしまっているのだが、ともあれ結論としてはそのような心配はない。

現在の実装では$LOADPATHにRuby本体のフルバージョンが埋め込まれているのであが、それは単にコード側が間に合っていないことによるそうだ。本来の意図に従うと$LOADPATHに含まれているのはRuby言語レベルでの互換性を表す文字列である。Ruby言語レベルでのAPIバージョンとも言える。これはRuby本体のバージョンとは別のもので、Ruby言語レベルで互換性がなくなったときに上がることが予定されている。したがって、Ruby 1.9.2がリリースされた際、互換性が保たれていれば$LOAD_PATHには1.9.1が含まれることになる(保たれなければ1.9.1以外の何かになる)。

このRuby言語のAPIバージョンは、バイナリ互換性を表すものではないが、$LOAD_PATHの中の拡張ライブラリ用のパスに対しても同様に埋め込まれている。これはRubyで書かれたライブラリから拡張ライブラリをrequireしているものがあるためで、相互に関係し合うことを考えて一方の互換性がなくなったときには他方でも互性換がなくなったものとみなす。

バイナリ互換性についてはlibruby.soのsonameなどによって運用されることになる。現在の実装ではマイナーバージョンまでを含んだlibruby.so.1.9などが設定されるようになっている(コンパイラに-Wl,-soname,lib$(RUBYSONAME).so.$(MAJOR).$(MINOR)が与えられている)が、これはおそらくRuby 1.9.1リリース時には変更されるものと予想される。

まとめるとRuby 1.9.1以降では、Ruby本体のバージョン、Ruby言語レベルでの互換性を示すバージョン、Rubyインタプリタのバイナリ互換性を示すバージョンという三つのバージョンが運用されることになる。後二者に変化があればRuby体本のバージョンは上がるが、Ruby本体のバージョンが上がっても後二者が変わらないことはありうる。なお、バイナリ互換性については1.9シリーズの中のどこかで失われる可能性があるそうだ。

ところで$LOADPATHの中の/usr/localの部分はconfigure--prefixで指定したパスであり、/usr/local/libに続くrubyの部分は同じく--program-prefix--program-suffixでの指定を加えたRubyインタプリタ名である。たとえば--prefix=/opt --program-suffix=1.9.1rc1としたならば、$LOADPATHの最初のエントリは/opt/lib/ruby1.9.1rc1/site_ruby/1.9.1となる。

このように$LOADPATHにRubyインタプリタの名前が入ることで何か困るということは、それを知って運用している分にはあまりないと言えるかもしれない。だが、これまでたとえばRubyコマンドにバージョンを付ける形でインストールしていたというような環境では、上述の三つのバージョンの問題とは別に、マイナーバージョンアップごとに$LOADPATHの内容が変わってしまう問題が生じることになる。しかもこの部分の文字列を指定する方法は提供されておらず、これを回避するにはソースコードに手を加えるしかない。

それではいくらか不便であるためconfigureで指定できるようにしてはどうかと提供してみたのが[ruby-dev:37749]である。実際にはRubyライブラリと拡張ライブラリのそれぞれの場所を個別に指定できるようにしているつもりで、/usr/share/usr/libの使いわけを意識したものでもある。とはいうものの、アーキテクチャ依存のRubyコードを、アーキテクチャ用のパス(/usr/local/lib/ruby/i686-linuxなど)に配置するといった認識が一般にあるとは思えないので(mkmf.rbにも対応はないと思う)、その入口くらいにしかならないかもしれない。