sci

最果て風呂

mruby に関するメモ書き

mruby-cf2bd34 (2012.10.09)

8 月にもビルドしていたのだけど、実に 2 ヶ月ぶりのビルドをしてみた。特に大きな変更があるわけでもないので、Makefile に自分用のパッチをあててから make をした。make test は 480 個になっていた。スクリプトを動かす等は次回に試してみる。

mruby-25aea66 (2012.07.13)

ついでに iBook で出ているもうひとつ(下記)の warning について調べてみた。

khash.h:27: warning: `__m' defined but not used

その当該する部分は下記になるのだけど、解決するための意見は複数あるみたい。

static const uint8_t __m[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
  1. static を取れ 実際に static を削除して make をすると warning が出ずにコンパイルが進むものの、リンクの時点で error になってしまう。この方法はペケ。

  2. const を取れ いつもと変化なしで warning も表示される。

  3. -std=c99 付けろ 変化なし。

  4. ifdef とか使え khash.h を読みこんでいるものの、そのファイル内では使ってないからエラーになるという話。codegen.c, error.c, gc.c, numeric.c, proc.c, range.c, string.c, struct.c, vim.c, y.tab.c, mrbc.c, mrblib.c, mruby.c, mirb.c が該当する。かなりの量なんだけど、調べるのがめんどい。

ちなみに khash.h をインクルードしているヘッダは proc.h と variable.h となり、C ソースは gc.c, hash.c, symbol.c, variable.c になる。

gc.c が被っているので見てみる。#include "mruby/khash.h" をコメントアウトしてもコンパイルはできた。warning は出てくるが、これは proc.h と variable.h もインクルードしているからだ。ただ、これらをコメントアウトしてしまうと proc.h や variable.h で定義されているものを使うのでエラーとなる。

次は proc.h から mruby/hkash.h を除いてみよう。KHASH_DECLARE を定義するためにインクルードしている。で、KHASH_DECLARE を使っているソースは、hash.c と symbol.c になる。他に KHASH_DEFINE というのもあるので、こちらも調べてみると classs.c, hash.c, symbol.c で使っている。これの定義は khash.h の中だ。ぬぬっ、KHASH_DECLARE は variable.h の中でも定義されている。

proc.h
KHASH_DECLARE(mt, mrb_sym, struct RProc*, 1);

variable.h
KHASH_DECLARE(iv, mrb_sym, mrb_value, 1)

ちょっと訳わからなくなってきた。同じヘッダファイルをインクルードしていると、それらのソース同士は関数や変数が見えるとかそんな話。あったなぁ。もう一度読み直してみよう。

「warning: enumeration value hoge not handled in switch」の件。実はこれ、表示させた方が良いという話。-Wswitch-enum というオプションがあって、これを有効にしていると、列挙型の項目すべてが指定されていない場合に警告を出すというもの。

例えば、enum hoge {1, 2, 3}; としておいて、switch 文で case 1:... case 3:... とやって case 2:... を書いていない場合に警告を出してくれるというもの。ここで default: を使ってしまうと、(書くのを忘れてしまった) case 2: の場合が当てはまってしまうので、警告は出されず、用途によっては意図したものにならない。

mruby-25aea66 (2012.07.12)

range.c で warning が出るようになってしまった。バイナリは作成されて make test も通るんだけど。どうやら 2012.07.07 にあった変更が原因みたい。ちなみに MinGW では warning は出ていない。コンパイラのバージョンによって違う?

range.c: In function `range_check':
range.c:36: warning: enumeration value `MRB_TT_FALSE' not handled in switch
...
range.c: In function `mrb_range_new':
range.c:36: warning: enumeration value `MRB_TT_FALSE' not handled in switch
...
range.c: In function `range_init':
range.c:36: warning: enumeration value `MRB_TT_FALSE' not handled in switch
...
range.c: At top level:

調べてみると、switch 文に default: break; を付けると warning は出てこなくなるらしい。switch 文が登場するのは 0d99856b57 なので良く見てみる。うお〜、switch 文がネストされてる。どこに default を入れれば良いのか?

とりあえず動いたのでパッチにして次回から使おう。Makefile へのパッチとは別にしておいた。

mruby-15ac09f (2012.07.08)

当初は月間だったのにいつのまにか週間になっている定点ビルド。MinGW 上でだけど下記の警告が出た。note なんて初めて見た。

load.c:140 note: '*((void *)&hex8+6)' was declared here
load.c:573 warnig: '*((void *)&hex8+6)' may be used uninitialized in this function

gcc 3.3 の iBook では出ていないので、4 系になってチェックが厳しくなったのかな。そういえば、逆に下記の警告は iBook で出ているのに MinGW では出ていないな。

../include/mruby/khash.h:27: warning: `__m' defined but not used

mruby-660f64b (2012.07.01)

月一での定点ビルド 3 回目。今回は 660f64b 。Makefile へのパッチをあててから make。make test は 459 あった。先月が 377 だったので約 80 増えたことになる。何をチェックしてるのかわからないけど。

configure スクリプトMakefile を作成する予定はないようなので、このまま Makefile ひとつで行くのかな?Lua とかは Makefile の中でターゲットを指定するようになってるけど、どうなるのだろう?

日付計算のスクリプトは問題なく動作した。これ、ruby で動かすよりも速い。きっと初期動作(フットプリント)が軽いんだろうね。出納帳スクリプトも試してみたけど、こちらは正規表現の部分でエラーになってしまう。組み込み向けだと File IO とかは実装されないのだろうか?

MinGW をインストールし直したので、試しに mruby をビルドしてみた。こちらは make-3.82 なので Makefile に手を加えなくてもビルドが完了した。COMPILE_MODE=homu とわざとタイプミスして make をしてみると、やはり最適化オプションは空になっていた。まぁ、普通は何も指定せずに make のみなんだろうけど。

mirb を起動してみると履歴が使えた。readline はリンクしてないよね?iBook の方がおかしいのか?Windows だけ特別?良くわからん。

Makefile の ifeq eles endif について mruby-21095556(2012.06.21)

そのまま make を実行すると下記のようなエラーが出てしまった。

Makefile:17: Extraneous text after `else' directive
Makefile:19: Extraneous text after `else' directive
Makefile:19: *** only one `else' per conditional.  Stop.

自分の make コマンドが古いのかな?3.79 なのだが。commit 履歴を見ると、2日前に変更が加わったみたい。

else ifeq... の部分に改行と endif を入れたら進んだ。make は if 文に else をひとつしか入れることが出来ないのかしら?修正するにしても Makefile は 7 つもあるんですけど...。

字下げをして書くと下記のようになる。elif とか elsif が無いなんて...。最後に endif が続くのはなんだか ruby っぽい。

ifeq ($(COMPILE_MODE),debug)
  CFLAGS = -g -O3
else
  ifeq ($(COMPILE_MODE),release)
    CFLAGS = -O3
  else
    ifeq ($(COMPILE_MODE),small)
      CFLAGS = -Os
    endif
  endif
endif

とりあえずビルドは完了して make test も 442 個すべて OK だった。前回は 377 個だったからずいぶんと増えたんだな。

ところで、コンパイルモードを判定するブロックであることを(文章の見た目で)意識しないのであれば、下記のように else を使う必要がないんじゃないかな?

ifeq ($(COMPILE_MODE),debug)
  CFLAGS = -g -O3
endif
ifeq ($(COMPILE_MODE),release)
  CFLAGS = -O3
endif
ifeq ($(COMPILE_MODE),small)
  CFLAGS = -Os
endif

直近で環境変数が空の場合は COMPILE_MODE = debug と設定しているのだから、単純に make をするだけなら「CFLAGS = -g O3」がセットされるわけだしね。

ぐぬぬ、「export COMPILE_MODE = homura」なんてやってから make をすると CFLAGS が空っぽになってしまう。私は良くオプションを打ち間違えるのだ。やっぱり ifeq else endif を使わないとダメなのか。

デフォルトで debug にしているのだから、最後にどれでもなかった場合の else 部分も書いて「CFLAGS = -g -O3」となるようにした方が良さそう。

ifeq ($(COMPILE_MODE),debug)
  CFLAGS = -g -O3
else
  ifeq ($(COMPILE_MODE),release)
    CFLAGS = -O3
  else
    ifeq ($(COMPILE_MODE),small)
      CFLAGS = -Os
    else
      CFLAGS = -g -O3
    endif
  endif
endif

これって、debug を設定してる意味ないな。release と small だけ判定して、それ以外は「CFLAGS = -g O3」に設定するのと同じ意味なんだもん。「puts "COMPLIE_MODE がおかしいねん"」とか表示させた方がいいのかな。

Makefile の RANLIB について(mruby-27c2416) (2012.06.19)

mruby をビルドするには ranlib を手動で実行しなければならない。Lua や他のものは特に何も言われずに実行されるので、どうなっているのか調べてみた。Makefile の最初の方を見てみると、

lua RANLIB = ranlib AR = ar rcu
perl ranlib = /usr/bin/ar s AR = /usr/bin/ar
python RANLIB = ranlib AR = ar
ruby RANLIB = ranlib AR = ar
mruby export AR = ar

のようになっていて、mruby は ranlib を使うことを想定していないようだった。なお、ranlib や ar がどのような仕事をするのかを私は知らない。

mruby のディレクトリ内をうろうろしてみたのだが、mrblib/Makefile をいじれば良さそうな気配がするメポ。ビルド時に手動で打ち込むコマンドは

ranlib lib/libmruby_core.a
ranlib lib/libmruby.a

なので、LIBR0 と LIBR をいじっている行を探せば良さそう。

# update libmruby.a
$(LIBR) : $(MLIB) $(LIBR0)
        $(CP) $(LIBR0) $(LIBR)
        $(AR) r $(LIBR) $(MLIB)

とあるので、この処理の最後に ranlib $(LIBR0) を追加しておけば自動的にやってもらえそう。Makefile は TAB 文字を使わなければいけないんだって。

どうやらダメだったみたい。src/Makefile にも libmruby_core.a があるので、こちらをいじる必要があるのかも。こちらでは TARGET になってる。

# executable constructed using linker from object files
$(TARGET) : $(OBJS) $(OBJY)
        $(AR) r $@ $(OBJS) $(OBJY)

単純に ranlib $(TARGET) なんてやっても良いのだろうか?make をしてみると、今まで表示されていた

ld: archive: ../../lib/libmruby_core.a has no table of contents, add one with ranlib(1) (can't load from it)

が無くなって

ld: Undefined symbols: _mrb_init_mrblib

だけになった。これは進歩したんじゃない?

再び mrblib/Makefile に戻って、今度は LIBR について記述する。先程は $(LIBR0) と書いていたけれど、それはすでに ranlib 済みのはずなので、ここでは $(LIBR) としてしまう。

できたできた! make だけで mruby のバイナリが完成した。まとめると下記の通り。

src/Makefile
# executable constructed using linker from object files
$(TARGET) : $(OBJS) $(OBJY)
        $(AR) r $@ $(OBJS) $(OBJY)
        ranlib $(TARGET) <- これ追記

mrblib/Makefile
# update libmruby.a
$(LIBR) : $(MLIB) $(LIBR0)
        $(CP) $(LIBR0) $(LIBR)
        $(AR) r $(LIBR) $(MLIB)
        ranlib $(LIBR) <- これ追記

だけどこれって面倒。Makefile を書き換えるよりも ranlib を直接実行しちゃった方が早いし楽だわ。Makefile の仕組みについてちょっとだけ勉強になった。

追記。$(LIBR0) や $(LIBR) は $@ で良いらしい。どちらの Makefile

RANLIB = ranlib
...
        $(RANLIB) $@

と同じように記述できる。

mruby-27c2416 (2012.06.03)

ひと月ぶりにビルドをする。前回と違って libmruby_core というのが増えた?あと make test が含まれるようになった。そしてバージョン情報が新しくなった。

> make
> ranlib lib/libmruby_core.a
> make
> ranlib lib/libmruby.a
> make
> make test
Total: 377
   OK: 377
   KO: 0
Crash: 0

> bin/mruby --version
mruby - Embeddable Ruby  Copyright (c) 2010-2012 mruby developers

こいつら...どんどん変わっていきやがる。

さらに bin/ 以下に mirb が追加されている。GPL 回避のためなのか、readline ライブラリをインクルードしないみたい。いや、オプションがあるのかな?gosh-rl のようなものがあればいいのにね。

mirb > puts "hello, world"
hello, world
 => false

irb > puts "hello, world"
hello, world
 => nil

素人なので false と nil がどう違うのかわからないけど、なにかが違うんだ。うんうん。

mirb > Time.now
 => Sun Jun 03 18:32:50 2012
mirb > Time.now - Time.local(2012, 4, 1)
 => Wed Oct 29 14:26:48 1969
mirb > (Time.now - Time.local(2012, 4, 1)).to_i
 => -5510013
mirb > (Time.now - Time.local(2012, 4, 1)).to_i / (24 * 60 * 60)
 => -63.77375

irb と違って、明示的に型変換をしないと「/ ってなんやねん」と怒られる。しかし何故にマイナスなん?

mruby-91a9054 (2012.05.05)

この頃流行りらしいので github から zip でもらってビルドしてみる。warning がたくさん出力されて、最後に

gcc -o ../../bin/mrbc ../../src/../tools/mrbc/mrbc.o ../../lib/libmruby.a -lm
ld: archive: ../../lib/libmruby.a has no table of contents, add one with ranlib(1) (can't load from it)

でビルド失敗。このエラーって以前にも似たようなのがあったような...。

> ranlib lib/libmruby.a
> make

で行けるかと思ったらまたしてもエラー。

gcc -o ../../bin/mruby -g -O3 ../../src/../tools/mruby/mruby.o ../../lib/libmruby.a  -lm
ld: table of contents for archive: ../../lib/libmruby.a is out of date; rerun ranlib(1) (can't load from it)

懲りもせず同じことを繰り返す。

> ranlib lib/libmruby.a
> make

でバイナリの完成。早速起動してみると、

> bin/mruby --version
ruby 1.8.7 (2010-08-16 patchlevel 302) [i386-mingw32]
Usage: ./mruby [switches] programfile
  switches:
  -b           load and execute RiteBinary (mrb) file
  -c           check syntax only
  -e 'command' one line of script
  -v           print version number, then run in verbose mode
  --verbose    run in verbose mode
  --version    print the version
  --copyright  print the copyright

あの〜、iBookMac ちゃんなんですけど...。Windows で落したからかな?version.h がアレなのか。最後の

#define RUBY_ENGINE "ruby"

って何だろう?処理を既存の Ruby に渡してるってこと?

> bin/mruby -e 'puts "hello"'
hello

よし、これでアーリーアダプターだ〜。