きりかノート 3冊め

おあそびプログラミング

ruby-1.8のportでuniversal対応が簡単にできる機能をgroupに追加

リクエスト受け取ったのは6月だったんだけど、やっと対応した。いやー、遅くなって悪いねっ(棒

もう1.8とかいいじゃん。。2.1のpreviewも出る時代ですよ。

今回の新機能

  • ruby.setup extconf.rb または ruby.setup setup.rb を使っている

ことを前提として、Portfileに

   PortGroup muniversal 1.0

を書くと、自動的に+universalでそれぞれのアーキテクチャでビルドしてそれぞれの.bundleの置き場所に配置してくれる。簡単ですね!

Portfileに手を入れないで対応する方向でいろいろ試したり調べたりしたんだけど、それは無理だった。まあ1行なんで書いてくれ。あとビルド、インストールの確認はportのメンテナ側でお願いね。拡張モジュールは固有の事情が多いので全体としてどうこうじゃない部分が多すぎるのですよ。

extconf.rbのケースの対応

ここからは技術的な解説というか、自分への覚え書き。

extconf.rbなやつはruby-gnome2系の対応したときに手順自体はできあがってたので、それの共通化。対象のアーキテクチャごとにconfigure && makeやるのはmuniversalで準備してくれるので、rubyとしてはextconf.rbをそれぞれのアーキテクチャrubyで実行してやればよい。

universalバイナリのめんどうなとことして、実行ファイルのパスが同じなのでアーキテクチャを指定して実行するには'arch'コマンドを通してやらなくちゃいけない。

こんなふうに。

   % arch -arch i386 /opt/local/bin/ruby1.8 extconf.rb
   % arch -arch x86_64 /opt/local/bin/ruby1.8 extconf.rb

MacPortsでのextconf.rbの実行にあたるのは、configureの段階なのでconfiure.cmdを調整してやればよい。だけど、muniversalから提供されるアーキテクチャごとの設定は、argsやenvが対象でcmdは変更できない。argsでもいいんだけど、archコマンドは環境変数ARCHPREFERENCEを設定することによって-archオプションなしに優先する実行ファイルのアーキテクチャを指定することができる。

つまり、次の2つは同じことになる。

   % arch -arch i386 /opt/local/bin/ruby1.8 extconf.rb
   % ARCHPREFERENCE=i386 arch /opt/local/bin/ruby1.8 extconf.rb

ということで、merger_configure_env(arch)でアーキテクチャを指定し、configure.cmdは"arch ruby extconf.rb"と指定する。

これが必要になる(universalにする)のは、

  • +universalバリアントが指定されている。
  • PortGroup muniversalが対象のPortfile中で記述されている。

とき。前者は[variant_isset universal]で、後者は[info exists universal_archs_supported]で判定している。

これでextconf.rbの対応が完了。

setup.rbのケースの対応

setup.rbも基本的にextconf.rbと同じ。結局、setup.rbからextconf.rb呼んでるわけだからね。ただ、extconf.rbの実行がsetup.rbから別プロセスで実行されるので、そのrubyをarchコマンド経由で呼ぶようにしてやらなくちゃいけない。

多くのsetup.rbは、"---rubyprog"というオプションでextconf.rbを実行するコマンドを指定できるようになっているので、それを使えばよい。ただし、--rubyprogで渡したコマンドは system(rubyprog, *args) のように実行されるので、--rubyprog="/usr/bin/arch /opt/local/bin/ruby1.8"としても、それ全体をひとつのパスとして実行しようとしてしまう。いろいろ悩んだんだけど、結局それを実行するシェルスクリプトを${worksrcpath}に生成してそれを使うようにした。

また、setup.rbに渡すオプション名が"--rubyprog"でなく"--ruby-prog"な場合もある(rb-sqlite3, rb-rrb)ので、それをPortfile中で指定できるようにした。Portfileの変数の評価順の都合で、これはruby.setupより前に書かなければならないことに注意。って新しい1.8用のport書く人がいるとも思わないけれど。

あと全setup.rbなrb-*を調べてるときに、pure rubyにも関わらずsupported_archs noarchしてないportがいくつかあったので直しといた。

他のケースの対応

やらない。無理。