history

青木日記 RSS

<前の日 | この月 | 次の日>

2006-05-18

ruby-dev summary

あっ! やっべ、ruby-dev summary 忘れてた。 隔週になっていらい、さらに忘れやすくなったな。

(05:26)

Ruby スクリプトを実行ファイル化する on Linux (1)

Linux で、Ruby スクリプトを単一実行ファイル化したい。 それもできるだけ汎用的な方法がいい。

[方針]

  • libc その他はすべてスタティックリンクする。
  • 拡張ライブラリもスタティックリンクする。
  • Ruby スクリプトは全部 objcopy でオブジェクトファイルにしてバイナリにリンクする。
  • require を Ruby レベルで差し替えてそっちを読ませる。

Ruby スクリプトを実行ファイル化する on Linux (2) ダイナミックロードの問題

ruby をスタティックリンクで作ると、 PAM でダイナミックロードされてるライブラリが使えない。ううーん。

……ん? 実は WEBrick では etc.so はほとんど使ってないのか。 UserDir オプションさえ使わなければ、 WEBrick に関してはとりあえず問題なさそうだな。 問題棚上げ。

他にダイナミックロードが必要と言えばネームサービスか。 サーバ側なら IP アドレスだけ使ってれば getaddrinfo は動かない……かな? なんかいけそうな気がしてきた。 これも問題棚上げ。

Ruby スクリプトを実行ファイル化する on Linux (3) どうやってプログラムを実行させるか

Ruby スクリプトは予定通り objcopy でオブジェクトファイルにして、 これを ruby とリンクさせる……まではよいのだが、 ruby にどうやってこのプログラムを実行させるかが問題だ。

ruby の main.c を差し替えてリコンパイルする方法だと、 ruby の objdir をずっと残しておかないといけない。 できれば ruby とか libruby-static.a だけを使ってどうにかしたい。

普通に ruby 組み込みインターフェイスを使ってしまうと、 拡張ライブラリがリンクされない (libruby-static.a しかリンクされないから)。 拡張ライブラリをスタティックリンクした libruby があるといいんだけどな。

libruby-static.a と拡張ライブラリの *.a を 全部まとめた、専用の libruby.a を自分で作ることにした。 これと独自の main.o をリンクしてバイナリを作る。 独自の main.c は ruby の main.c を基本とするが、 argv をすりかえてメインプログラムを -e でつっこむことにする。 なんかイマイチな方法だけど、まあとりあえず動きゃいい。

Ruby スクリプトを実行ファイル化する on Linux (4) require のすりかえ

さらに、main.c で次のように require をすりかえる。

extern struct script_source rb2exe_file_list[];
 
static VALUE
lookup_script(VALUE name)
{
    struct script_source *ent;
 
    for (ent = rb2exe_file_list; ent->name; ent++) {
        return rb_str_new(ent->start, ent->size);
    }
    return Qnil;
}
 
static void
replace_require(void)
{
    rb_define_global_function("_rb2exe_lookup_script", lookup_script, 1);
    rb_eval_string("\
        module Kernel                             \n\
          alias _rb2exe_original_require require  \n\
          remove_method :require                  \n\
          def require(feat)                       \n\
            rb = feat.sub(/\\.rb\\z/, '') + '.rb' \n\
            if src = _rb2exe_lookup_script(rb)    \n\
              eval src, ::TOPLEVEL_BINDING, rb    \n\
              $\".push rb                         \n\
              return true                         \n\
            end                                   \n\
            _rb2exe_original_require feat         \n\
          end                                     \n\
        end                                       \n\
    ");
}

rb2exe_file_list はリンク時にソースコードを自動生成してコンパイルする。

Ruby スクリプトを実行ファイル化する on Linux (5) 必要な *.rb の検出

残るは、require される *.rb を検出することだ。

……ちょっと考えたんだけど、必要なファイルだけじゃなくて、 ロードパスに入ってる *.rb は全部入れちゃうというのも一案かもしれない。 当然ながらバイナリはでかくなるけど、どーせオンデマンドロードなんだし、 いまどきバイナリが 10MB デカくなったところでたいした問題ではないのではなかろうか。

まあ、いちおう無駄を最小にする方向で考えてみよう。

exerb だと、実際に実行してみて require されるファイルを検出したりする。 しかし、これはいろいろな理由からできれば避けたい感じだ。 あと、レシピファイルを作るのはなんか面倒なので、 少なくともデフォルトにはしたくない。

なお、俺が前に作った簡単スクリプトでは、 単純にソースコードを require で grep して適当に検出していた。 動的な require さえなければこれでも結構うまくいく。

今回は、適当に grep する方針をデフォルトにしつつ、 残りの方法はオプションで選べるようにしようと思う。 つまり以下の四つを用意する。

  • ソースコードを再帰 grep して検出 (デフォルト)
  • 実際に実行して検出
  • 必要なファイルを明示的にリストする
  • ロードパスにある *.rb を全部つっこむ

(06:16)

ruby-dev summary (2)

ruby-dev summary を書くとき、具体的に何をやっているのか、 この日記に書き出してみようと思う。

まず、要約する範囲を決める。現在は隔週でやってるので、 前回の人が担当した部分のあとから二週間分くらいが目安となる。 前回は立石さんの [ruby-talk:190859] ruby-dev summary 28495-28605 なので、[ruby-dev:28606] から二週間くらい。 スレッドの切れめを考えると、[ruby-dev:28636] あたりまでかなあ。 ……って、30 通しかないのかよ。普通はもうちょっとあるんだけど。

対象範囲が決まったら、 新しいメールを作って Subject に範囲を書いてしまう。

次に、メールを眺めつつ、要約する必要のあるスレッドを抽出する。 「要約する必要のあるスレッド」とは、

  • Ruby の仕様や実装に関係する
  • 単に「バグ報告 → 修正」ではない
  • 議論がされている

という感じのスレッドを指す。今回の範囲ならば、次のようなあたり。 リストアップすると同時に、日本語の Subject はてきとうに英訳してしまう。

ちょっと減らしすぎた? というか、元となるメールが少なすぎるんだよ今回は。

ここまで来たら、あとは地道に一個ずつ要約して訳していく。

(次回に続く)

(07:57)

Mac Book 見てきた

店員が Mac Book を示してゐる。

大層大事さうに陳列棚に載せてゐる。
眠い目を擦り、いつたい何が入つてゐるのか見極めようとするが、如何にも眠かった。
Xeon か Opteron でも入つてゐるのか。
何とも手頃な善い匣である。
店員は時折笑つたりもする。

「ぽん」
匣の中から聲がした。
鈴でも轉がすようなシンセサイザーの聲だった。

……

……えー、まあ、京極ネタは置いといて。 実物見ると意外にのっぺりしてるのな。

(22:15)

もうだめ

ぎがねむす。今日はもう寝よう。

ああ、しかし、日記に適当なネタだけ書いて寝たりしてると、 ようやく本調子に戻ってきたかなと実感するね、印象があるね、そんな情勢だね (三段活用)。

(22:24)

本日のツッコミ(全4件) [ツッコミを入れる]
なかだ (2006-05-18 12:27)

const char *ptr = StringValuePtr(name);
    long len = RSTRING(name)->len;
    if (strlen(ent->name) == len && strncmp(ptr, ent->name, len) == 0)

あたりが抜けてると予想。

MoonWolf (2006-05-18 16:37)

RubyScript2Exeとかはどうでしょうか?
Windows,Linux,MacOSXに対応しているようです。
http://www.erikveen.dds.nl/rubyscript2exe/index.html

青木 (2006-05-18 22:22)

やっぱり眠いときにコードを書いちゃいけませんねえ。

青木 (2006-05-18 22:24)

あ、何かあったなーと思ってたけど、RubyScript2Exe でしたか。
rb2exe はぐぐったんだけどなー。*.so までまとめてくれるんだなあ。
libc までは、なんとなく入れてくれないっぽい?
まあ、PAM とネームサービスの問題は解決方法が思いつかないしなあ。

名前
メールアドレス

<前の日 | この月 | 次の日>
2002|04|05|06|07|08|09|10|11|12|
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|04|05|06|09|10|
2009|07|
2010|09|

Copyright (c) 2002-2007 青木峰郎 / Minero Aoki. All rights reserved. LIRS