history

青木日記 RSS

<前月 | 最新 | 次月>

2005-02-01

Ripper @ ruby-core

うう、こまったな、無性に Ruby のコードが書きたくなってきた。 こんなことをやっている余裕はまだないのだが……

[ruby-core:04345] [BUG?] Ripper

もちろん、バグではない。

しかしこれは、どう答えたものかなあ。 この人が求めているものを簡単に実現する方法はまだ存在しないのだが。 いや、tstring_content だけを取り出せばいいのなら簡単だけど、 それだと他の (ヒアドキュメントじゃない) 文字列も拾ってしまう。

まず前提として、トークンはこうなっている。

~ % ruby -rpp -rripper -e 'pp Ripper.scan(%(<<HERE\nstring\nHERE))'
[[[1, 0], :on_heredoc_beg, "<<HERE"],
 [[1, 6], :on_nl, "\n"],
 [[2, 0], :on_tstring_content, "string\n"],
 [[3, 0], :on_heredoc_end, "HERE"]]

heredoc_beg と heredoc_end の間にある tstring_content だけを取りたいというのが求める解だろう。 正規表現マッチみたいなことができればいいわけだよな。

pattern = 'heredoc nl $(tstring_content*) heredoc_end'

と、いう感じにパターンを記述し、

Ripper.slice("<<HERE\nstring\nHERE", pattern, 1)

てな感じで $(...) にマッチする部分を取れる、というのはどうだろう。 をー、なんかいい感じがしてきたぜ。

実装はどうすっか。自分でエンジンを書くのはだるいな。

よし、考えついたぞ。 パターンは正規表現にコンパイルし、 対象は文字列にコンパイルして、普通に正規表現マッチを行う。 で、インデックスで両者の対応を取ればよい。

あー、実装したくなってきたけど、がまんしよう。

(01:43)

Ripper @ ruby-core (2)

おれは誘惑に弱すぎると思った。

~/c/ruby/ext/ripper % ruby -I./lib -rripper -e '
p Ripper.slice(%Q(<<HERE\nstring\nHERE),
               "heredoc_beg nl $(tstring_content *) heredoc_end", 1)
'
"string\n"

意図していなかったが、こんなこともできるようだ。

~/c/ruby/ext/ripper % ruby -I./lib -rripper -e '
p Ripper.slice(%(<<HERE\nstring\#{nil}\nHERE),
               "heredoc_beg nl $(.*?) heredoc_end", 1)
'
"string\#{nil}\n"

これって、もしかしてすごく便利なのでは……

(02:40)

Ripper @ ruby-core (3)

こみっとしてみた。 ついでに ripper/sexp もこみっとした。

(04:00)


2005-02-02

Ruby で goto (もどき)

なんと pure Ruby でここまで goto らしく! 画面右側は隠して御覧ください。

require 'goto'
                                                            __{
_ :hata1                                                     do
	cls
	goto :hata3                                         end
_ :hata2                                                     do
	mes "はーい、こんにちは"                            end
_ :hata3                                                     do
	mes "旗を立ててみるテストです"
	stop                                                end}

……だめだろーなー……。

ちなみに goto.rb はこんなの。

class GotoEnviron
  def initialize
    @blocks = nil
    @table = {}
  end
 
  def push_block(flag, block)
    b = Block.new(block)
    if @blocks
      @blocks.last.next = b
    else
      @blocks = b
    end
    @table[flag] = b
  end
 
  def exec
    b = @blocks
    while true
      target = catch(:__goto_environ_jump) {
        while b
          b.call
          b = b.next
        end
        return
      }
      break unless target
      raise ArgumentError, "no such flag: #{target}" unless @table[target]
      b = @table[target]
    end
  end
 
  def goto(target)
    throw :__goto_environ_jump, target
  end
 
  class Block
    def initialize(block)
      @block = block
      @next = nil
    end
 
    def call
      @block.call
    end
 
    attr_accessor :next
 
    def last
      b = self
      while b.next
        b = b.next
      end
      b
    end
  end
end
 
def __
  @env = GotoEnviron.new
  yield
  @env.exec
end
 
def _(flag, &block)
  @env.push_block flag, block
end
 
def goto(target)
  @env.goto target
end

(21:36)


2005-02-04

『プログラマの数学』

http://www.hyuki.com/math/

結城さんの新作は『プログラマの数学』らしい。

やばい、すげえ面白そうだ。 秘かに数学コンプレックスを持つ文系プログラマとしてはこれは買うしかない。

もしかして Haskell をさわってたのもこの関連なのかなあ。

(17:24)

goto

http://dgames.jp/dan/?date=20050203#p01

> goto が何箇所かで話題になっていたりして
> このサイトにも多少の影響力あり?
> てゆーか自意識過剰?

いえ、dan さんのとこ見て書きました。 書き終わったときにすでに Mozilla のタブを閉じてたから 面倒くさくて URL を張らなかっただけです。

(18:30)

Ruby の <<

http://yowaken.dip.jp/tdiary/20050203.html#p02 より、 なんだけど、最初の派生元は 2ch だろうか。

ぼくも IO#<< は使いません。 ついでに言えば Array#<< も String#<< も使いません。 だって Array だと push なのに String だと concat だから、 つい Array#concat のつもりで << を使ってしまうんです。

(18:56)

not 暇

という感じに日記を書きまくってると いかにも暇そうに見えるのだが、 実はまだテスト期間中であり全然暇ではない。 すべて終わるのは 2/14 の予定。

(19:02)

*.loveruby.net 一時停止のお知らせ

光ファイバー回線導入工事のため、 2 月 15 日 (火) に loveruby.net の全サーバが停止します。 あらかじめ御了承ください。

(19:09)

Solaris 10

クロスプラットフォーム萌えなわたしとしては Solaris 10 超期待ですよ。特に AMD64 対応がいい。 dual Opteron で Solaris 10 入れてメインマシンにしちゃえー という声がどこからか聞こえてくるほどです。 もう皮算用が止まらんね。

(19:46)

Ruby の << (2)

Array#<< も String#<< も使いません。

とは書いたものの、ちょっと grep してみると、 String#<< は意外と使っていた。 それに対し Array#<< は見付からなかった。 やはり Array#push と concat が混乱するのが嫌みたいだな。

(22:21)

Ruby CVS HEAD

srcdir 以外で HEAD をビルドしたら tk で止まった。 報告しようかと思ったが、中田さんのパッチが入れば なおるようなので、それまで待つことにする。

(02:06)

Ripper

ぐぁ、昼のコミットで通るようになっただろーと思ったら、 テストの変更だけコミットしわすれてた……。

コミットしたら Tru64UNIX 5.1B でも 1F になった (iconv に "euc-jp" がないため)。

(02:44)

xsd の 1F

そういえば、ずっと無視してきたんだけど、 これはどうするべきなんだろう。

tunami:~/src/ruby % /usr/local/pkg/ruby-ccc/bin/ruby test/runner.rb test/xsd/test_noencoding.rb
Loaded suite test_noencoding.rb
Started
E
Finished in 0.017578 seconds.
 
  1) Error:
test_wsdl(XSD::TestEmptyCharset):
Iconv::InvalidEncoding: invalid encoding ("euc-jp", "utf-8")
    (eval):6:in `iconv'
    (eval):6:in `encode'
    /usr/local/pkg/ruby-ccc/lib/ruby/1.9/rexml/source.rb:41:in `encoding='
    /usr/local/pkg/ruby-ccc/lib/ruby/1.9/rexml/parsers/baseparser.rb:202:in `pull'
    /usr/local/pkg/ruby-ccc/lib/ruby/1.9/rexml/parsers/streamparser.rb:16:in `parse'
    /usr/local/pkg/ruby-ccc/lib/ruby/1.9/rexml/document.rb:171:in `parse_stream'
    /usr/local/pkg/ruby-ccc/lib/ruby/1.9/xsd/xmlparser/rexmlparser.rb:27:in `do_parse'
    /usr/local/pkg/ruby-ccc/lib/ruby/1.9/wsdl/xmlSchema/parser.rb:60:in `parse'
    ./test/xsd/test_noencoding.rb:15:in `test_wsdl'
 
1 tests, 0 assertions, 0 failures, 1 errors

まず、Tru64UNIX みたいなマイナープラットフォームを サポートする必要があるかという問題がある。 主要プラットフォームでは iconv 自体が "EUC-JP" をサポートしているし、 サポートするプラットフォームは増えていくだろう。 だからこれは無視してもいいという考えもありうる。

第二に、どこで対処すべきかがよくわからない。 iconv か、rexml か、xsd か。 どこで対処するのもそれなりに理がありそうな気がする。

ちなみに EUC-JP のコーデック自体は用意されているのだが、 名前が "eucJP" になっている。 なので、どこで対処するにしても変更自体は簡単なはずである。

(02:51)

本日のツッコミ (全3件) [ツッコミを入れる]

たむら [AMD64萌え〜だよね。JDSはなかなかカコイーし
思った以上にクライアントとして良く出来てると思う。
# ディレクトリ構造に慣れないといかんが]

青木 [萌えですよねー AMD64 + Solaris。
一度は使ってみたい組み合わせです。]

なかだ [config.charsetを$(srcdir)に置いておくとiconv.rbというラッパーを作ります。
http://www.ctan.org/tex-archive/macros/texinfo/texinfo/intl/config.charset

でもTru64UNIXだとCONFIG["target"]は何?]


2005-02-05

自分マイニング

http://nais.to/~yto/clog/2005-01-18-3.html

遅ればせながら俺もやったよ日記マイニング!

~/tmp/tdiary % /usr/pkg/sufary-2.3.8/bin/sang -t 100 -n 10 out
138 ということ
140 とりあえず
110 インストー
107 コンパイル
106 ライブラリ
101 ンストール

とりあえずライブラリのコンパイルとインストールばかりしていたということがわかる。

~/tmp/tdiary % /usr/pkg/sufary-2.3.8/bin/sang -t 50 -n 12 out
58 ――――――
60 うな気がする
53 かもしれない
52 じゃないです
52 たんですが、
53 と思います。
57 ような気がす
101 インストール
66 オブジェクト
85 ソースコード
89 プログラミン
89 ログラミング

インストールばかりしてたような気がするのだけど、 実はソースコードばかり書いていたのかもしれないと思います。 嘘じゃないです。 オブジェクト指向プログラミングキタ――――――!

(02:25)


2005-02-11

生存報告

ようやくテストが大部分終わった。 残りはどーでもいい講義ひとつのみ。 最後のほうは風邪にもやられて酷いめにあった。 今年の風邪は消化器系に来るようだ。

(18:10)

本日のツッコミ (全5件) [ツッコミを入れる]

sugi [refe 0.8.0 でデータを更新しようとしたら、
% mkrefe_rubyrefm man-rd-ja/*.rd
/usr/local/lib/ruby/site_ruby/1.8/refe/rubyrefmparser.rb:180:in `get_method_name': (RuntimeError)
BigDecimal.rd:378: cannot get method name
"--- divmod,quo,modulo,%,remainder\n"
from /usr/local/lib/ruby/site_ruby/1.8/refe/rubyrefmparser.rb:155:in `read_entry'
from /usr/local/lib/ruby/site_ruby/1.8/refe/rubyrefmparser.rb:141:in `register_entry_to'
from /usr/local/lib/ruby/site_ruby/1.8/refe/rubyrefmparser.rb:123:in `parse'
from /usr/local/bin/mkrefe_rubyrefm:60:in `update_database'
from /usr/local/bin/mkrefe_rubyrefm:59:in `open'
from /usr/local/bin/mkrefe_rubyrefm:59:in `update_database'
from /usr/local/bin/mkrefe_rubyrefm:57:in `each'
from /usr/local/bin/mkrefe_rubyrefm:57:in `update_database'
from /usr/local/bin/mkrefe_rubyrefm:49:in `main'
from /usr/local/bin/mkrefe_rubyrefm:122
というエラーになってしまったのですが、これはデータが悪いのでしょうか?]

青木 [それは複数に分けて書いてほしいところですねえ。
こんな感じに、

--- div
--- modulo
--- %

エントリを並べて書いておけば ReFe の表示では
一つにまとまります。]

sugi [ありがとうございます。
ここは分けることで解決したのですが、他にも
--- CGI#[key]
とか
--- EOC # => 0
みたいに書いてあるところがあったりとか、
いろいろ問題がありそうです。

リファレンスマニュアルをどういう表記にすべきかというのが
分からないので、これらの表記を直していいのか不明です。
(MLに投げた方がいいのかなぁ)

お暇なときにでも、一度見てみていただけませんでしょうか。]

sheepman [OpenSSL::ASN1 で --- EOC # => 0 と書いたのは僕です。
--- EOC
0
と書くと定数名と数字との対応が見にくかったので。何か代替案を思い付いたら教えてください。マニュアルの表記法の議論に関しては
http://www.freeml.com/ctrl/html/MLInfoForm/rubyist
だと気兼ねなくできるとおもいます。気が付いた点があったら投稿してください。]

青木 [rubyist ML のほうに書いたのを転載します。

「#=>」はサンプルコード中で値を書くときの表記ですし、評価した
値を暗示するので、メソッドリストで使うべきではないと思います。

また、RDoc だとかわたしの使ってるドキュメントフォーマットだと

--- StringScanner#eos? -> bool

という表記がありますが、これは基本的に返り値の値ではなく型を
示すものと認識しています。

また、ReFe などでエントリだけを単独で読んだ場合には

--- EOC #=> 0

のような表記をされると、はっきり言ってわけがわかりません。ReFe
のような自動処理を行ううえでも、RWiki 上で表現を圧縮するよりも
形式が統一されていることが重要だと思います。

以上の三点から、メソッドリストで「#=>」を使うのには反対です。
ReFe でも当面はサポートしません。]


2005-02-15

回線工事完了

光回線敷設完了。 実効 84Mbps 出てるとかで工事の人もびびってた。

(13:32)

それにしても全然違いがわからない。 ここまで違いがないと悩むぞ。 ルータがボトルネックになってるのかなあ。

いろいろ

ようやく一区切りついたよ……。 そろそろ復活しようかな。

(13:49)

Rubyist Magazine 5 号

http://jp.rubyist.net/magazine/?0005

お、出ましたねー。 今回は自分の原稿とテストで死んでたから何もできなかったな。

今回はインタビューがえらい面白い。 このインタビューはこれまで外れがなくおもしろいけど、今回は特に面白い。

記事の中だと、ゲームがらみってことで RGSS にはかなり興味がある。 ちょっと欲しくなった。しかし最大の問題は、 俺は「Ruby が普通に使える」なんてくらいじゃ全然興味がわかないことだなあ。 Ruby を使うだけだったらコンパイルすればいいじゃん。 したがってこの製品で一番重要なのはライブラリと素材だと思うのだが、 今回の記事はそういう紹介が少ない。 RPG ツクールのサイトでは逆にレベルが低すぎて API がちゃんと載ってないからだめだ。 例えばどんなクラスがあるかって表だけでもあるとよかったと思うんだけどな。

次。CGIKit はちょっと気になっていた。 でも俺は RDB 嫌いなので Tapkit はどうでもいい。さっくり無視。 ……とか適当な読みかたをしたら全然わからんかった。 誰か RDB が必要ないウェブアプリケーションフレームワーク作ってくれよう。 Rails も RDB ありきでセットアップがめんどくせーんだよ!

つーことで lily に興味を持ってみる。 いや、lily はウェブアプリケーションフレームワークじゃないと思うが それは置いといて、そういう文脈で読むことを試みる。

……うーん、だめだ、やっぱ文章読んでるだけじゃわからん。 俺には勘とソースコードだけで動かすほうが向いてる。 (つーことでダウンロード中)

それはそうと俺思うんだけどね、 もっと構造が簡単な個人用 CMS が欲しいんだよ。 ruby があればファイル一個置くだけでいきなり動かせて、 FTP もエディタも使わずにサイト構築できるようなやつ。 んで日記と掲示板と Wiki と絵チャとギャラリーとカウンターが使えて、 できればコンテンツは自動的にバージョン管理システムの管理下に置きたい。 普通のページは HTML だけじゃなくて RD like なシンタックスとか Wiki シンタックスとか使えるといいな。 モノは Ruby でも全部揃ってるはずなので、あとはつなげばよいと思うのだが。

んで、先にるびまの続きを読むと、Win32utils が地味に便利そうね。 クリップボードとか Windows サービスとか。 ファイバまで使ってるのは驚きだ。たぶんうまくいかんだろうけど。

lily

とりあえず、アーカイブを展開したら lily-X.X.X みたいなディレクトリを作ってほしい気がする。 tDiary もバージョンついてないんだっけ? でも、どーせディレクトリを作っちゃったらどういう名前だって変わらなくね?

あーそうか、ファイル一つと言ってもテーマまでまとめるのは難しいなあ。 「アプリケーション部分はファイル一つ」くらいにすべきか。 設定ファイルも一つだけは分離してもよいことにしよう。

chmod 755 する。出ない。 ああそうか FollowSymLinks と AddHandler が足りんかった。追加。 出た。

出たが……。どうやってエントリを追加すればよいのだろう。 えー、手動でファイル追加するのか。めんどくさい。 カテゴリでディレクトリ分けるのもめんどくさいなあ。 俺カテゴリ嫌いだし。

えー、Wiki スタイルにするのにダウンロードしなくちゃいけないのかー。 だるい (やるけど)。 ああ、tDiary の Wiki スタイル由来なのね。 もしかしてライセンスが違うから別々なのか。

カテゴリを使わないで書くとどうなるんだろ。 ああ、これでも出るのか。カテゴリ面倒だから全部これでいいや。

初エントリ書いた。出た。

ふーむ、日付はどこから来てるんだろう。もしかして st_mtime か。 ……touch しても時刻が変わらない。どこに保存してるんだ。 find で発見。log/.entrydate だな。 最初にファイルを表示したときにここに記録されるのか。

コメントを付けようとするとファイルがないと言われた。なぜだ。

うわ、これは mod_rewrite の「ホームディレクトリで使うとはまる罠」っぽい。 やっぱりそうだ。RewriteRule のターゲットを絶対パスにしたら治った。

コメントも動いた。

と、言いますか、コメントで「--------」だけの行を書くと lily を狂わせられるような気がするのはわたしの気のせいか。

確かに動作は変になるが、それほどおもしろい結果にはならなかった。

Firefox で見るときれいだが w3m で見るとヘッダが邪魔だな。

ま、ファーストコンタクトはこんなもんか。

(21:42)

iconv の charset

返事するのをすっかり忘れてました。 ツッコミを再掲すると、

> ■なかだ (2005-02-05 15:23)
>
> config.charsetを$(srcdir)に置いておくとiconv.rbというラッパーを作ります。
> http://www.ctan.org/tex-archive/macros/texinfo/texinfo/intl/config.charset

config.charset のことは知ってますが、 それで個別に解決「すべきなのか」というところを問うてます。 個別に解決するということは、ライブラリなんかを書く人は 結局それがないことを前提に書かざるを得ないでしょう。 そう決めたならそれでいいんですが、 そう決めてないのであれば日本語関連だけでも エイリアスを用意しちゃえばいいのかなーと。 なにもプラットフォームごとに対応表を用意しなくても、 動的にチェックして定義しちゃえばいいんじゃないかと思うんですよ。

例えばわたしの調査によると EUC-JP の変換表が使いたければ "eucJP" という名前を使うのが一番ポータブルなんですが、 この "eucJP" と "EUC-JP" が異なる変換表に 割り当てられている状況はさすがに考えられません。 だから、"EUC-JP" と "eucJP" は全プラットフォームで同じものと考えて エイリアスを (Ruby 側で) 用意しておけばいいのではないかと思うわけです。 そういう感じの定義方法であればプラットフォームごとに 対応する必要はほとんどないはずなので負担は比較的低いでしょう。

> でもTru64UNIXだとCONFIG["target"]は何?

ベンダがちょっと不確実ですが、恐らく "alphaev6-dec-osf5.1" です。 ruby --version だと [alphaev6-osf5.1] なんで。

(21:59)

やる気なし

暇になったとたん何もやる気が起きない。 とりあえず今日はもう寝よう。

それに暇とは言っても本のまえがきとを書くとか 練習問題の答えを書くとかの残務は結構あるんだよなー。 あー……やる気でねえー。

(22:11)

本日のツッコミ (全12件) [ツッコミを入れる]

moriq [RailsはRDBなくても使えますよ。ActionPackのsampleはActiveRecord使ってないし。]

suzuki [CGIKitもRDB必須ではないですよ。両方組み合わせて使えるのを想定してはいますが、基本的にそれぞれ独立してます。]

青木 [すばやい御指摘ありがとうございます。

んー、でも、それは「なくても残りの部分が動く」というだけで、
RDB を捨てちゃったら永続データをカバーするライブラリが存在
しなくなるわけですよね。それだとあまり意味がないと思います。
例えば RDB じゃなくて簡易 OODB が使えるとか、任意のオブジェクト
をファイルシステムに保存するフレームワークが用意されているとか、
何か代替物がないと、単に「モデルをカバーしないフレームワーク」
になってしまいませんか。]

arton [いや、ファイバは盲点だった。ネイティブスレッドと違って問題ないかも知れない。って言うか閑なら試したいな(つまり閑じゃないから試せない)。]

suzuki [CGIKitはWebインターフェースのみをカバーするのが目的で、「DB部分はお好きなライブラリをどうぞ」という指針なので、「モデルをカバーしないフレームワーク」ですね。WebインターフェースとDBモデルの依存度は低い(今のところほぼない)です。]

青木 [む、そういうものですか。Rails はちょっとだけ
試したことがあるんですが CGIKit はソースツリーを
眺めただけなので、今度試してみようと思います。]

青木 [ファイバって「Windowsでのユーザスレッド実装」くらいの
イメージしかなかったんですが、うまくいくんですか。
"Advanced Windows" でも読んで勉強しとこ……。]

arton [今、ちょっと調べたけど僕が大きく勘違いしてるかも知れない。
着眼点が良いなと思ったのは、ファイバそのものは単一のスレッドで動作できるからネイティブスレッドで問題となる異なるスレッドのjumpバッファの戻しが原因の異常状態がなくなるんじゃないかと思ったという点と、GCで問題となるスタックトップの位置の変化が起きないという点の2つなんだけど、最初の点についてはファイバ単位にWindowsも同様な管理をするはずだからやっぱり異常な状態(異なるファイバのスタックの戻し)になってしまうかも(というかrubyのスレッドそのものがファイバなわけだし=余りメリットは無いかも)。]

noritada [あのー……またまたしょうもないツッコミですみませんが、
一応、タイトルが Rubyist Ma*n*agine に (ry]

サイロス誠 [初めまして。
評価ありがとうございます。
今回の記事は、いきなり内部まで突っ込むよりも、とりあず動作を分かり易く紹介して、そののちインタフェースにも手を出そうかというスタンスで考えております。
次回執筆いたしましたら、よろしくお願いします。]

青木 [ううっ、manage → magazine 修正しました。
最近 typo 製造機と化してるなあ。]

青木 [> RGSS
なるほど、続きがすでに構想されているのですね。
楽しみに待ってます。]


2005-02-17

AIX + gcc 3.3.2 + ruby

なぜか AIX で ruby のコンパイルを始めてみた。手強い。

[環境]

  • AIX 5.1L
  • gcc 3.3.2
  • ruby CVS HEAD

[参考資料]

まず何も考えずに configure; make してみると、 miniruby のリンクで止まる。-brtl がよくないらしい。 これはリンカ (/usr/ccs/bin/ld) のオプションなので、 gcc を使う場合は -Wl,-brtl にする必要がある。

それはともあれ、とりあえず先に進めるために -brtl を取ってみると miniruby は作れて動くようになる。

~/obj/ruby $ make miniruby
         gcc main.o libruby-static.a -ldl -lcrypt -lm   -o miniruby -g -O2
~/obj/ruby $ ./miniruby -v -e 'puts "OK"'
ruby 1.9.0 (2005-02-14) [rs6000-aix5.1.0.0]
OK

……が、拡張ライブラリがコンパイルできない。

compiling bigdecimal
        gcc -g -O2  -I. -I../.. -I../../../../src/ruby -I../../../../src/ruby/ext/bigdecimal   -c ../../../../src/ruby/ext/bigdecimal/bigdecimal.c
In file included from ../../../../src/ruby/ruby.h:21,
                 from ../../../../src/ruby/ext/bigdecimal/bigdecimal.c:23:
../../config.h:7:1: warning: "_ALL_SOURCE" redefined
In file included from /opt/freeware/lib/gcc-lib/powerpc-ibm-aix5.1.0.0/3.3.2/include/ctype.h:32,
                 from ../../../../src/ruby/ext/bigdecimal/bigdecimal.c:16:
/usr/include/standards.h:99:1: warning: this is the location of the previous definition
        /usr/ccs/bin/ld -brtl -eInit_bigdecimal -bI:../../ruby.imp -bM:SRE -T512 -H512   -L"../.." -o ../../.ext/rs6000-aix5.1.0.0/bigdecimal.so bigdecimal.o  -ldl -lcrypt -lm   -lc
ld: 0706-003 インポート・ファイルが見つからないか、読み取れません: ../../ruby.imp
        ld:accessx(): このパス名のファイルまたはディレクトリは存在しません。
make: 1254-004 最後のコマンドからのエラー・コードは 255 です。
 
 
停止します。
make: 1254-004 最後のコマンドからのエラー・コードは 1 です。
 
 
停止します。

いろいろ調べた結果、make ruby.imp でエクスポートライブラリを作っておく必要があるとわかった。 めんどくさい。

※ さらに後の調べによって、--enable-shared のときは自動的に作成されることが判明

ruby.imp を作っておくとビルドは問題なく最後まで行くようになったが、 今度は拡張ライブラリがロードできない。

~/obj/ruby $ sudo make install
略
~/obj/ruby $ /usr/local/pkg/ruby/bin/ruby --version
ruby 1.9.0 (2005-02-14) [rs6000-aix5.1.0.0]
~/obj/ruby $ /usr/local/pkg/ruby/bin/ruby -rbigdecimal -e0
./bigdecimal.so: load failed - ./bigdecimal.so (LoadError)

さてどーするかな。

まず、小さいアプリケーションでもって、 dlopen を使ったライブラリルーチンの正しい呼びかたを確認してみる。 構成はできるだけ ruby に似せて次のようにする。

  • main() の定義を持つ main.c。dlopen() で extfunc() を呼ぶ。
  • extfunc() の定義を持つ extlib.so (extlib.c)。rb_int_twice() を呼ぶ。
  • rb_int_twice() の定義を持つ libruby.a (libruby.c)。

このとき次のようにすると動作するライブラリが作れる。

~/c/test/c/shlib $ make
        gcc -c -Wall main.c -o main.o
        gcc -c -Wall libruby.c -o libruby.o
        gcc -shared -Wl,-G libruby.o -o libruby.so
        gcc -c -Wall extlib.c -o extlib.o
        gcc -shared -Wl,-G -Wl,-rtllib extlib.o -L. -lruby -o extlib.so
ld: 0711-224 警告: シンボル ._GLOBAL__DI が重複しています。
ld: 0711-224 警告: シンボル ._GLOBAL__DD が重複しています。
ld: 0711-224 警告: シンボル _GLOBAL__DI が重複しています。
ld: 0711-224 警告: シンボル _GLOBAL__DD が重複しています。
ld: 0711-345 -bloadmap または -bnoquiet オプションを使用して、詳細な情報を得てください。
        gcc main.o -Wl,-brtl -L. -lruby -o ruby
ターゲット "all" は最新のものです。
~/c/test/c/shlib $ ./ruby
result=25

_GLOBAL__DI, _GLOBAL__DD は C++ のコンストラクタとデストラクタらしい。 無視しておこう。

ポイントは 4 点ある。

  • ライブラリを作るときは gcc -shared -Wl,-G
  • 拡張ライブラリを作るときは -Wl,-brtllib も必要
  • 拡張ライブラリには libruby をリンクしておかないといけない。 ひらたく言うと --enable-shared が必要。
  • 実行可能ファイルを作るときには -Wl,-brtl が必要。

拡張ライブラリに libruby をリンクするのは、 rb_xxx_xxxx() をリンクするため。 どうも AIX では単純に dlopen するだけだと 拡張ライブラリ → ruby のシンボル解決ができないっぽい。 だから libruby を独立させて、 コンパイル時にシンボルを解決してしまう必要がある。

また現在の ruby は拡張ライブラリを作るときに ld -eInit_xxxx -bM:SRE -T512 -H512 というフラグを使っているが、 これは必要ないようだ。-G -brtllib だけ付けておけばよい。 man ld には次のようにある。

-G Produces a shared object enabled for use with the run-time linker. The -G
flag is equivalent to specifying the erok, rtl, nortllib, nosymbolic,
noautoexp, and M:SRE options with the -b flag. Subsequent options can
override these options. This flag only applies to AIX 4.2 or later.

共有ライブラリを作るときに必要なのは -bM:SRE オプションなんだが、 これは -G では暗黙のうちに指定される。 また -berok により未定義シンボルが許可されるので、 明示的にシンボルをインポートする必要はない (つまり ruby.imp とかのあたりがすべて必要なくなる)。

念のため他のフラグも見ておく。

-brtl はオブジェクトファイルにライブラリの名前を埋め込むオプションで、 共有ライブラリにリンクするオブジェクトファイルをビルドするときに必要。 また -l オプションのライブラリを探すとき、*.a 以外に *.so も見るようになる。 -G を付けると暗黙のうちに -brtl もセットされる。

ちなみに AIX では共有ライブラリも *.a という名前を持つが、 中身は *.so と一緒 (ECOFF オブジェクトファイル) である。 さらに言えば共有ライブラリはバージョニングされない。 このへんは Tru64UNIX と似ているようだ。

-brtllib は librtl をリンクするフラグで、 dlopen でロードされるライブラリに必要。 -G は暗黙のうちに -bnortllib をセットするので、 -brtllib を明示的に追加する必要がある。

以上の知見をもとに Makefile と config.status を 書き換えまくってみたところ、ビルドまではうまくいった。 しかし拡張ライブラリをロードすると失敗する。

あれ?

あれれ?

……dlopen が使われてないじゃねえかー! これが原因か! dln.c を書き換えて #ifdef AIX を抹殺する。

~/obj/ruby-shared $ ruby -v -rbigdecimal -e 'p $"'
ruby 1.9.0 (2005-02-14) [rs6000-aix5.1.0.0]
["bigdecimal.so"]

勝利!

ん? そういえば rpath を設定してないのになんで実行できるんだろ。 もしかしてカレントディレクトリに libruby.so があるからか。 移動するとどうなる?

~/obj/ruby-shared $ cd
~ $ ruby --version
exec(): 0509-036 以下のエラーのためにプログラム ruby をロードできません:
        0509-150   従属モジュール libruby.so をロードできませんでした。
        0509-022 モジュール libruby.so をロードできません。
        0509-026 システム・エラー: このパス名のファイルまたはディレクトリは存在しません。

だめじゃん……。

どーすればいいんだろう。 ld -blibpath:$prefix/lib:/usr/lib かな?

~/obj/ruby-shared $ gcc -Wl,-brtl -Wl,-blibpath:/usr/local/pkg/ruby/lib:/usr/lib main.o -L. -lruby -ldl -lcrypt -lm -lc -o ruby
~/obj/ruby-shared $ sudo cp ruby /usr/local/pkg/ruby/bin/
~/obj/ruby-shared $ cd
~ $ ruby --version
ruby 1.9.0 (2005-02-14) [rs6000-aix5.1.0.0]

うまくいったもよう。確認。

~ $ dump -H /usr/local/pkg/ruby/bin/ruby
 
/usr/local/pkg/ruby/bin/ruby:
 
                        ***Loader Section***
                      Loader Header Information
VERSION#         #SYMtableENT     #RELOCent        LENidSTR
0x00000001       0x00000015       0x00000071       0x0000004e
 
#IMPfilID        OFFidSTR         LENstrTBL        OFFstrTBL
0x00000004       0x00000764       0x0000005d       0x000007b2
 
 
                        ***Import File Strings***
INDEX  PATH                          BASE                MEMBER
0      /usr/local/pkg/ruby/lib:/usr/lib
1                                    libruby.so
2                                    libc.a              shr.o
3                                    librtl.a            shr.o

ちゃんとセットされているようだ。

さて、パッチをどうするかな。 よーするに、パラメータをこうすりゃいいはずなんだが。

LDSHARED   = gcc -shared
LDFLAGS    = -Wl,-brtl -Wl,-blibpath:$(prefix)/lib:/usr/lib -L. -lruby
DLDFLAGS   = -Wl,-G -Wl,-brtllib $(EXTLDFLAGS)
XLDFLAGS   = $(EXTLDFLAGS)
EXTLDFLAGS =
LIBRUBYARG = -L$(topdir) -lruby

あと dln.c の AIX 独自コードを捨てて dlopen にする。 これで全部通るはずだ。

問題は古いバージョンの AIX だなあ。 man を見ると、4.2 より前とそれ以降でかなり劇的に変わっているようだ。 4.1 以前は無視、てことならば、 上記のように変更してしまえばすべてカタが付く。 無視しないのなら、これまでのパラメータを残しつつ変更する必要がある。

(07:05)

AIX + gcc 3.3.2 + ruby (2)

そーいえば socket がコンパイルされてなかった。 mkmf.log を見る限り、IPv6 がらみの getaddrinfo がだめみたいだ。 てっとりばやく --enable-wide-getaddrinfo で通す。

~/obj/ruby-shared/ext/socket $ ruby ../../../../src/ruby/ext/socket/extconf.rb --enable-wide-getaddrinfo
略
~/obj/ruby-shared/ext/socket $ make
略
~/obj/ruby-shared/ext/socket $ ruby -rsocket -e '
s = TCPSocket.open("harmony", 80)
s.puts "GET / HTTP/1.0"
s.puts
puts s.read
s.close
'
HTTP/1.1 200 OK
Date: Wed, 16 Feb 2005 22:13:40 GMT
Server: Apache/1.3.28 (Unix) mod_fastcgi/2.4.2 mod_ruby/1.0.7 Ruby/1.9.0 mod_ssl/2.8.15 OpenSSL/0.9.7b
Last-Modified: Fri, 05 Mar 2004 15:40:57 GMT
ETag: "22529-ff-40489f89"
Accept-Ranges: bytes
Content-Length: 255
Connection: close
Content-Type: text/html
 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<title>harmony</title>
</head>
<body>
<h1>harmony</h1>
<p>Apache working on harmony</p>
</body>
</html>

解決。

(07:17)

AIX / エクスポートファイル

AIX 用のエクスポートファイルを作る方法。

ruby は nm を使っているが、 dump を使ってもよいらしい。

# mkexp.rb
 
table = {}
`dump -g #{ARGV[0]}`.each do |line|
  next unless /\A\s*\d/ =~ line
  idx, name = line.split
  table[name.sub(/\A\./, '')] = true
end
puts table.keys.sort

(07:22)


2005-02-23

いあいあ

AA が気にいったのでとりあえずくとぅるー喚んでおきますね。

(09:20)

食べものネタ

……米がないわけです。

しかたがないので風邪ひいたときに買いためたおかゆ貯金を崩します。 永谷園のお茶漬のもとを入れるとわりといける。

……あと、大根が腐りました。

(09:48)

AMD64

x86 の 64 ビット拡張で一番嬉しいのって、 実は 64 ビットになったことじゃなくて 汎用レジスタが 16 本になったってことじゃないかと思うんだけど、どうよ。 すでに内部でレジスタリネーミングとかやってるからあんまり影響ないのかな。

(21:27)

RubyConf

今年はようやく RubyConf に行けそうだなあ。

……と言いますか、行けるように金を残しておきます、はい。

(21:45)

日本語プログラミング言語「なでしこ」

http://www.nadesi.com

「なでし・こむ」か。 とりあえず「む」の消費方法を考えるべきだな。

つか

> なでしこ違いで来てしまった人はこちらへ(笑)。

あっちはカタカナでしょ!

(00:04)


2005-02-25

Ruby CVS HEAD / test-all on AIX 5.1L (1)

何するか悩んだらとりあえず make test-all しておくらしい。

drb, rinda, soap4r, webrick が全滅。 エラーを見ると、iconv か getaddrinfo を使うものがすべて失敗していた。 逆に言うとそれ以外はすべて成功しているわけで、 思ったよりちゃんと動くという印象を受けた。 もうちょっと詰めていけば問題なく使えそうだ。

Ruby CVS HEAD / test-all on AIX 5.1L (2) getaddrinfo 問題

とりあえず getaddrinfo のほうを見てみよう。

~/c/bin $ ruby -v getaddrinfo.rb localhost
ruby 1.9.0 (2005-02-14) [rs6000-aix5.1.0.0]
AF_INET 127.0.0.1 0 IP
~/c/bin $ ruby -v getaddrinfo.rb rs7012
ruby 1.9.0 (2005-02-14) [rs6000-aix5.1.0.0]
AF_INET 192.168.1.43 0 IP

ええ? 何これ。 Linux だとこんな感じになるんだけどな。

~/c/bin % ruby -v getaddrinfo.rb localhost
ruby 1.9.0 (2005-02-23) [i686-linux]
AF_INET 127.0.0.1 STREAM TCP
AF_INET 127.0.0.1 DGRAM UDP
AF_INET 127.0.0.1 RAW IP

getnameinfo はさらに酷くて、何も通らない。

~/c/bin $ ruby -v getnameinfo.rb 127.0.0.1
ruby 1.9.0 (2005-02-14) [rs6000-aix5.1.0.0]
./getnameinfo.rb:12:in `getnameinfo': getnameinfo: Host not found (SocketError)
        from ./getnameinfo.rb:12:in `getnameinfo'
        from ./getnameinfo.rb:7:in `main'
        from ./getnameinfo.rb:15
~/c/bin $ ruby -v getnameinfo.rb 192.168.1.43
ruby 1.9.0 (2005-02-14) [rs6000-aix5.1.0.0]
getnameinfo.rb:12:in `getnameinfo': getnameinfo: Host not found (SocketError)
        from getnameinfo.rb:12:in `getnameinfo'
        from getnameinfo.rb:7:in `main'
        from getnameinfo.rb:15

何がどうなってるんだ。

いろいろ試した結果、IPv6 関係がダメダメなことがわかった。 --disable-ipv6 --with-lookup-order-hack=INET でようやく成功。

Ruby CVS HEAD / test-all on AIX 5.1L (3) iconv 問題

~ $ iconv -f us-ascii -t us-ascii
iconv: 0791-004 コンバータがオープンできません
~ $ iconv -f US-ASCII -t US-ASCII
iconv: 0791-004 コンバータがオープンできません
~ $ iconv -f ISO-8859 -t ISO-8859
iconv: 0791-004 コンバータがオープンできません
~ $ iconv -f ISO8859 -t ISO8859
iconv: 0791-004 コンバータがオープンできません
~ $ iconv -f ISO8859-1 -t ISO8859-1
^C
~ $ iconv -f UTF-8 -t UTF-8
^C
~ $ iconv -f eucJP -t eucJP
iconv: 0791-004 コンバータがオープンできません

ついに eucJP もないプラットフォームを見付けてしまったか……。 でも ISO8859-1 とか UTF-8 はあるらしいことがわかる。

一覧が欲しいなあ。コンバータはどこにあるんだろ。 さんざん探した挙句、/usr/lib/nls/loc/iconv で発見した。

$ command ls /usr/lib/nls/loc/iconv | ruby -e 'ARGF.each{|s| puts s.strip.split("_") }' | sort -u
64
ASCII-GR
CNS11643.1986-1
CNS11643.1986-2
Conv
GB18030
GBK
IBM-1027
IBM-1046
IBM-1124
IBM-1129
IBM-1252
IBM-290
IBM-300
IBM-850
IBM-856
IBM-921
IBM-922
IBM-930
IBM-930-DOS
IBM-932
IBM-939
IBM-939-DOS
IBM-943
IBM-eucCN
IBM-eucJP
IBM-eucKR
IBM-eucTW
IBM-sbdTW
IBM-udcJP
IBM-udcJP-GL
IBM-udcJP-GR
IBM-udcTW
ISCII.1991
ISO8859-1
ISO8859-1-GL
ISO8859-1-GR
ISO8859-15
ISO8859-15-GL
ISO8859-15-GR
ISO8859-2
ISO8859-2-GL
ISO8859-2-GR
ISO8859-3
ISO8859-3-GL
ISO8859-3-GR
ISO8859-4
ISO8859-4-GL
ISO8859-4-GR
ISO8859-5
ISO8859-5-GL
ISO8859-5-GR
ISO8859-6
ISO8859-6-GL
ISO8859-6-GR
ISO8859-7
ISO8859-7-GL
ISO8859-7-GR
ISO8859-8
ISO8859-8-GL
ISO8859-8-GR
ISO8859-9
ISO8859-9-GL
ISO8859-9-GR
JISX0201.1976-0
JISX0201.1976-GL
JISX0201.1976-GR
JISX0208.1978-GL
JISX0208.1978-GR
JISX0208.1983-0
JISX0208.1983-GL
JISX0208.1983-GR
KSC5601.1987-0
TIS-620
UCS
UCS-2
UTF-8
Universal
big5
ct
fold7
fold8
uucode

EUC-JP は IBM-eucJP らしい。こんなの予想できるかっ。 で IBM-932 が shift_jis (というか CP932) のようだ。 とりあえず、エンコーディング名の差を吸収するラッパーをインストールしておく。

Ruby CVS HEAD / test-all on AIX 5.1L (4) 残る問題

これでかなり通るようになったけど、 まだいくつか失敗する。まず drb で一つ。

~/src/ruby $ ruby test/runner.rb test/drb
Loaded suite drb
Started
...............................E...................................................
Finished in 32.556596 seconds.
 
  1) Error:
test_10_yield_undumped(TestDRbCore):
NoMethodError: undefined method `unpack' for -279519369:Fixnum
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:569:in `load'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:602:in `recv_request'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:899:in `recv_request'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:1495:in `init_with_client'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:1507:in `setup_message'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:1459:in `perform'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:1554:in `main_loop'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:1550:in `loop'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:1550:in `main_loop'
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:1546
    (druby://rs7012:32900) /usr/local/pkg/ruby/lib/ruby/1.9/drb/drb.rb:1546
    (druby://localhost:32973) /usr/local/pkg/ruby/lib/ruby/1.9/drb/invokemethod.rb:10:in `block_yield'
    (druby://localhost:32973) /usr/local/pkg/ruby/lib/ruby/1.9/drb/invokemethod.rb:17:in `perform_with_block'
    (druby://localhost:32973) /usr/local/pkg/ruby/lib/ruby/1.9/drb/invokemethod.rb:14:in `each'
    /home/aamine/src/ruby/test/drb/drbtest.rb:234:in `test_10_yield_undumped'
 
83 tests, 401 assertions, 0 failures, 1 errors

soap でも一つ。

~/src/ruby $ ruby test/runner.rb test/soap
Loaded suite soap
Started
......................................................E..................................................................
Finished in 83.757822 seconds.
 
  1) Error:
test_success_mu(SOAP::Header::TestAuthHeader):
XSD::NS::FormatError: Unknown namespace qualifier: env
    /usr/local/pkg/ruby/lib/ruby/1.9/xsd/ns.rb:115:in `parse_local'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/encodingstyle/soapHandler.rb:543:in `decode_attrs'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/encodingstyle/soapHandler.rb:505:in `each'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/encodingstyle/soapHandler.rb:505:in `decode_attrs'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/encodingstyle/soapHandler.rb:162:in `decode_tag'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/parser.rb:180:in `decode_tag'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/parser.rb:128:in `start_element'
    /usr/local/pkg/ruby/lib/ruby/1.9/xsd/xmlparser/parser.rb:67:in `start_element'
    /usr/local/pkg/ruby/lib/ruby/1.9/xsd/xmlparser/rexmlparser.rb:34:in `tag_start'
    /usr/local/pkg/ruby/lib/ruby/1.9/rexml/parsers/streamparser.rb:24:in `parse'
    /usr/local/pkg/ruby/lib/ruby/1.9/rexml/document.rb:171:in `parse_stream'
    /usr/local/pkg/ruby/lib/ruby/1.9/xsd/xmlparser/rexmlparser.rb:27:in `do_parse'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/parser.rb:90:in `parse'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/processor.rb:39:in `unmarshal'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/rpc/router.rb:156:in `unmarshal'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/rpc/router.rb:76:in `route'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/rpc/soaplet.rb:108:in `do_POST'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/rpc/soaplet.rb:103:in `with_headerhandler'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/rpc/soaplet.rb:103:in `do_POST'
    /usr/local/pkg/ruby/lib/ruby/1.9/webrick/httpservlet/abstract.rb:35:in `__send__'
    /usr/local/pkg/ruby/lib/ruby/1.9/webrick/httpservlet/abstract.rb:35:in `service'
    /usr/local/pkg/ruby/lib/ruby/1.9/webrick/httpserver.rb:108:in `service'
    /usr/local/pkg/ruby/lib/ruby/1.9/webrick/httpserver.rb:69:in `run'
    /usr/local/pkg/ruby/lib/ruby/1.9/webrick/server.rb:158:in `start_thread'
    /usr/local/pkg/ruby/lib/ruby/1.9/webrick/server.rb:147
    /usr/local/pkg/ruby/lib/ruby/1.9/webrick/server.rb:147
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/rpc/proxy.rb:137:in `call'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/rpc/driver.rb:275:in `call'
    /usr/local/pkg/ruby/lib/ruby/1.9/soap/rp