mruby 初めの一歩
はじめに
以前から触ってみたいと思っていた mruby をようやく触ったのでメモ。
インストール
Github Readmeの通り。rake
でビルドする方法が書いてある。古めの情報だとminirake
でやってるが、3.3.0
だとminirake
の中でrake
を呼んでるだけだった。
rake all test
mruby-3.3.0/bin
にバイナリがいくつかできている(実は mruby-3.3.0/build/host/bin/mruby
へのシンボリックリンク)のでパスを通しておく。
-
mruby
- 本体 -
mirb
- Rubyでいうirb
-
mrbc
- バイトコードをつくるやつ。VM上で動かせる -
mrbtest
- テストフレームワークっぽい -
mrdb
- デバッガっぽい -
mruby-config
- mrubyプロジェクトのビルドやコンパイル設定を管理するためのツール -
mruby-strip
- mrubyバイナリからデバッグシンボルや不要な情報を取り除いて、サイズを削減するためのツール
チュートリアル
チュートリアル的なドキュメントがあまりなさげで見つからない。多分、Executing Ruby code with mruby が良さげなのでやってみる。
fibt.rb
- Rubyで書いたフィボナッチ数列計算
def fibonacci(n)
return n if n <= 1
fibonacci(n - 1) + fibonacci(n - 2)
end
start_time = Time.now
fibonacci(35)
end_time = Time.now
puts "mruby Execution Time: #{end_time - start_time} seconds"
REPL
普通にirbっぽく
❱❱❱ mirb
mirb - Embeddable Interactive Ruby Shell
> def fibonacci(n)
* return n if n <= 1
* fibonacci(n - 1) + fibonacci(n - 2)
* end
=> :fibonacci
>
=> nil
> start_time = Time.now
=> 2024-09-01 10:48:28 +0900
> puts fibonacci(35)
end_time = Time.now
puts "mruby Execution Time: #{end_time - start_time} seconds"
9227465
=> nil
> end_time = Time.now
=> 2024-09-01 10:48:29 +0900
>
=> nil
> puts "mruby Execution Time: #{end_time - start_time} seconds"
mruby Execution Time: 1.261344 seconds
=> nil
ソースコードから実行
普通にrubyっぽく
❱❱❱ mruby fibt.rb
mruby Execution Time: 1.339467 seconds
CのコードにRubyを埋め込む感じで
やや無理やり感あるけど
#include <mruby.h>
#include <mruby/compile.h>
int main(void) {
mrb_state *mrb = mrb_open();
if (!mrb) { /* handle error */ }
const char *ruby_code =
"def fibonacci(n)\n"
" return n if n <= 1\n"
" fibonacci(n - 1) + fibonacci(n - 2)\n"
"end\n\n"
"start_time = Time.now\n"
"fibonacci(35)\n"
"end_time = Time.now\n\n"
"puts \"mruby Execution Time: #{end_time - start_time} seconds\"\n";
mrb_load_string(mrb, ruby_code);
mrb_close(mrb);
return 0;
}
ヘッダの場所と、libmruby.a
を渡してコンパイル
gcc -std=c99 -I ../mruby-3.3.0/include fibt.c -o fibt ../mruby-3.3.0/build/host/lib/libmruby.a -lm
実行
❱❱❱ ./fibt
mruby Execution Time: 1.243873 seconds
バイトコードにして実行
mrbc
を使ってバイトコードにする
❱❱❱ mrbc fibt.rb
みてみる
❱❱❱ hexdump -C fibt.mrb
00000000 52 49 54 45 30 33 30 30 00 00 01 34 4d 41 54 5a |RITE0300...4MATZ|
00000010 30 30 30 30 49 52 45 50 00 00 00 eb 30 33 30 30 |0000IREP....0300|
00000020 00 00 00 96 00 03 00 08 00 01 00 00 00 00 00 3c |...............<|
00000030 63 03 58 04 00 5f 03 00 1d 03 01 2f 03 02 00 01 |c.X.._...../....|
00000040 01 03 03 04 23 2d 03 00 01 1d 03 01 2f 03 02 00 |....#-....../...|
00000050 01 02 03 51 04 00 01 05 02 01 06 01 3e 05 52 04 |...Q........>.R.|
00000060 51 05 01 52 04 2d 03 03 01 38 03 69 00 02 00 00 |Q..R.-...8.i....|
00000070 16 6d 72 75 62 79 20 45 78 65 63 75 74 69 6f 6e |.mruby Execution|
00000080 20 54 69 6d 65 3a 20 00 00 00 08 20 73 65 63 6f | Time: .... seco|
00000090 6e 64 73 00 00 04 00 09 66 69 62 6f 6e 61 63 63 |nds.....fibonacc|
000000a0 69 00 00 04 54 69 6d 65 00 00 03 6e 6f 77 00 00 |i...Time...now..|
000000b0 04 70 75 74 73 00 00 00 00 49 00 03 00 08 00 00 |.puts....I......|
000000c0 00 00 00 00 00 29 34 04 00 00 01 03 01 07 04 44 |.....)4........D|
000000d0 03 27 03 00 02 38 01 01 04 01 3f 04 01 2d 03 00 |.'...8....?..-..|
000000e0 01 01 05 01 3f 05 02 2d 04 00 01 3c 03 38 03 00 |....?..-...<.8..|
000000f0 00 00 01 00 09 66 69 62 6f 6e 61 63 63 69 00 4c |.....fibonacci.L|
00000100 56 41 52 00 00 00 2d 00 00 00 03 00 0a 73 74 61 |VAR...-......sta|
00000110 72 74 5f 74 69 6d 65 00 08 65 6e 64 5f 74 69 6d |rt_time..end_tim|
00000120 65 00 01 6e 00 00 00 01 00 02 ff ff 45 4e 44 00 |e..n........END.|
00000130 00 00 00 08 |....|
00000134
実行
❱❱❱ mruby -b fibt.mrb
mruby Execution Time: 1.337975 seconds
-b
がバイトコードだよと教えているはずだが、なくても動いた(自動判定?)
Cのコードにしてしまう
❱❱❱ mrbc -B fibt_symbol fibt.rb
これで、fibt.c
ができて、その中のfibt_symbol
にバイトコードがはいっている。
#include <stdint.h>
#ifdef __cplusplus
extern
#endif
const uint8_t fibt_symbol[] = {
0x52,0x49,0x54,0x45,0x30,0x33,0x30,0x30,0x00,0x00,0x01,0x34,0x4d,0x41,0x54,0x5a,
0x30,0x30,0x30,0x30,0x49,0x52,0x45,0x50,0x00,0x00,0x00,0xeb,0x30,0x33,0x30,0x30,
0x00,0x00,0x00,0x96,0x00,0x03,0x00,0x08,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x3c,
0x63,0x03,0x58,0x04,0x00,0x5f,0x03,0x00,0x1d,0x03,0x01,0x2f,0x03,0x02,0x00,0x01,
0x01,0x03,0x03,0x04,0x23,0x2d,0x03,0x00,0x01,0x1d,0x03,0x01,0x2f,0x03,0x02,0x00,
0x01,0x02,0x03,0x51,0x04,0x00,0x01,0x05,0x02,0x01,0x06,0x01,0x3e,0x05,0x52,0x04,
0x51,0x05,0x01,0x52,0x04,0x2d,0x03,0x03,0x01,0x38,0x03,0x69,0x00,0x02,0x00,0x00,
0x16,0x6d,0x72,0x75,0x62,0x79,0x20,0x45,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,
0x20,0x54,0x69,0x6d,0x65,0x3a,0x20,0x00,0x00,0x00,0x08,0x20,0x73,0x65,0x63,0x6f,
0x6e,0x64,0x73,0x00,0x00,0x04,0x00,0x09,0x66,0x69,0x62,0x6f,0x6e,0x61,0x63,0x63,
0x69,0x00,0x00,0x04,0x54,0x69,0x6d,0x65,0x00,0x00,0x03,0x6e,0x6f,0x77,0x00,0x00,
0x04,0x70,0x75,0x74,0x73,0x00,0x00,0x00,0x00,0x49,0x00,0x03,0x00,0x08,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x29,0x34,0x04,0x00,0x00,0x01,0x03,0x01,0x07,0x04,0x44,
0x03,0x27,0x03,0x00,0x02,0x38,0x01,0x01,0x04,0x01,0x3f,0x04,0x01,0x2d,0x03,0x00,
0x01,0x01,0x05,0x01,0x3f,0x05,0x02,0x2d,0x04,0x00,0x01,0x3c,0x03,0x38,0x03,0x00,
0x00,0x00,0x01,0x00,0x09,0x66,0x69,0x62,0x6f,0x6e,0x61,0x63,0x63,0x69,0x00,0x4c,
0x56,0x41,0x52,0x00,0x00,0x00,0x2d,0x00,0x00,0x00,0x03,0x00,0x0a,0x73,0x74,0x61,
0x72,0x74,0x5f,0x74,0x69,0x6d,0x65,0x00,0x08,0x65,0x6e,0x64,0x5f,0x74,0x69,0x6d,
0x65,0x00,0x01,0x6e,0x00,0x00,0x00,0x01,0x00,0x02,0xff,0xff,0x45,0x4e,0x44,0x00,
0x00,0x00,0x00,0x08,
};
これを呼び出すコード fibt_main.c
を以下のように書く
#include <mruby.h>
#include <mruby/irep.h>
#include "fibt.c"
int
main(void)
{
mrb_state *mrb = mrb_open();
if (!mrb) { /* handle error */ }
mrb_load_irep(mrb, fibt_symbol);
mrb_close(mrb);
return 0;
}
コンパイル
gcc -std=c99 -I ../mruby-3.3.0/include fibt_main.c -o fibt ../mruby-3.3.0/build/host/lib/libmruby.a -lm
実行
❱❱❱ ./fibt
mruby Execution Time: 1.270651 seconds
使い分け
Executing Ruby code with mruby から引用
REPL(mirb)は、主に初期開発段階で使用されます。mrubyの現在最も一般的な使用法は、ソースコード(.rb)であり、これはRubyをスクリプト言語として強調し、機械上でソースコードを変更することで簡単に修正できるという特徴があります。ソースコード(.c)は、自分のアプリケーションにmrubyを組み込む最も簡単な方法です。バイトコード(.mrb)は、Javaアプリケーションのような感覚を提供し、ファイルベースでインストールできますが、ソースコードへのアクセスは提供されません。バイトコード(.c)は、多くの人にとってmrubyを使用する最も複雑な方法かもしれませんが、同時にプログラム内でmrubyコードを最も効率的に実行する方法でもあります。
なるほど、スクリプトとして開発しつつ、リリースの時はCでコンパイルすればいいんですね。
mgem
mgem自体はRubyのgemみたい
❱❱❱ sudo gem install mgem
Password:
Fetching mgem-0.3.0.gem
Successfully installed mgem-0.3.0
Parsing documentation for mgem-0.3.0
Installing ri documentation for mgem-0.3.0
Done installing documentation for mgem after 0 seconds
1 gem installed
mgem list
300+ の mgem がある。
gem install mgem
mgem search <search-pattern>
参考
動かす系
仕組み系
Discussion