原作者 Daniel Bovensiepen 译者 Lanza Schneider
通常,我们使用Ruby程序的方式都是直接将源代码分发,并且安装一个有着众多文件的Ruby解释器以执行那些Ruby源代码。因此,如果您有使用其它Ruby实现的经验,那么您可能会对下面列出的一些例子感到熟悉。但mruby不仅能以这种方式运行,还可以构建出独立的程序,甚至可以把Ruby源代码编译成字节码来储存,并在合适的时机加载执行。
我们假设现在有一个Ruby源代码文件 test_program.rb
它的内容是:
puts 'hello world'
它并不直接加载源代码文件来执行Ruby程序,不过你可以在mirb
程序内直接输入Ruby代码来执行:
$ mruby/bin/mirb
mirb - Embeddable Interactive Ruby Shell
> puts 'hello world'
hello world
=> nil
✔ 直接输入源代码执行并即时获取反馈,无需任何间接文件
✘ 不适用于生产场合
✘ 输入的Ruby代码将要解析2次:首先mirb
检查代码的完整性,然后mirb
把代码编译为字节码并执行它。
运行Ruby代码最常见的方式就是把源代码文件名作为参数传递给解释器,在mruby中,这个解释器就叫 mruby
:
$ mruby/bin/mruby test_program.rb
hello world
✔ 非常简单的开发周期:编程 → 测试 → 编程
✘ Ruby源代码会直接向用户暴露
✘ 需要mruby
解释器程序,而且需要文件系统的支持(译者注:譬如在某些单片机上就没有支持文件的环境了)
✘ Ruby源代码仍需解析后编译成字节码才能去运行
你可以把Ruby源代码写成一个C字符串。这就好像使用mruby
解释器程序时,使用了-e
参数一样。
#include <mruby.h>
#include <mruby/compile.h>
int
main(void)
{
mrb_state *mrb = mrb_open();
if (!mrb) { /* handle error */ }
// mrb_load_string(mrb, str) to load from NULL terminated strings
// mrb_load_nstring(mrb, str, len) for strings without null terminator or with known length
mrb_load_string(mrb, "puts 'hello world'");
mrb_close(mrb);
return 0;
}
编译链接:
$ gcc -std=c99 -Imruby/include test_program.c -o test_program mruby/build/host/lib/libmruby.a -lm
执行:
$ ./test_program
hello world
✔ 简单的开发周期 编程 → 编译 (用譬如gcc
的C语言编译器) → 测试 → 编程
✔ 产出的程序将完全是独立的
✘ 需要照抄上面的样板才能去编程和执行(译者注:这里可能指的是需要写很多和业务逻辑关系不大,用于控制mruby的C代码)
✘ Ruby源代码仍需解析后编译成字节码才能去运行
✘ 如果要更新Ruby代码需要重新编译,或者是其它的更新机制
mruby提供了字节码机制。Ruby代码可以通过预编译的方式产出中间代码(字节码),随后再加载执行,就像Java那样。
首先我们要通过mrbc
程序来把Ruby源代码编译成mruby字节码:
$ mruby/bin/mrbc test_program.rb
这样就可以得到一个叫test_program.mrb
的文件,其中包含了我们所给Ruby源代码编译后的mruby字节码内容:
$ hexdump -C test_program.mrb
00000000 52 49 54 45 30 30 30 33 e1 c0 00 00 00 65 4d 41 |RITE0003.....eMA|
00000010 54 5a 30 30 30 30 49 52 45 50 00 00 00 47 30 30 |TZ0000IREP...G00|
00000020 30 30 00 00 00 3f 00 01 00 04 00 00 00 00 00 04 |00...?..........|
00000030 00 80 00 06 01 00 00 3d 00 80 00 a0 00 00 00 4a |.......=.......J|
00000040 00 00 00 01 00 00 0b 68 65 6c 6c 6f 20 77 6f 72 |.......hello wor|
00000050 6c 64 00 00 00 01 00 04 70 75 74 73 00 45 4e 44 |ld......puts.END|
00000060 00 00 00 00 08 |.....|
00000065
这个文件可以由mruby
解释器程序或者mrb_load_irep_file()
函数来执行。使用mruby
解释器程序运行字节码时,需要用-b
参数告诉它这是一个字节码文件而不是普通的Ruby源代码:
$ mruby/bin/mruby -b test_program.mrb
hello world
✔ 不必给用户分发Ruby源代码
✔ 无需解析Ruby源代码
✔ 可以通过替换.mrb文件的方式轻松更新字节码
✘ 复杂的开发周期: 编程 → 编译 (mrbc
) → 测试 (mruby
) → 编程
✘ 需要mruby
解释器程序,而且需要文件系统的支持
如果你想把Ruby代码直接集成在C程序中,这种方式就很适合了。它将会创建一个包含mruby字节码的C数组,然后您就可以在C程序中执行该字节码。
首先用mrbc
编译程序,提供-B
参数并紧跟一个C标识符即可:
$ mruby/bin/mrbc -Btest_symbol test_program.rb
我们就可以得到一个test_program.c
文件,它包含名为test_symbol
的C数组
/* dumped in little endian order.
use `mrbc -E` option for big endian CPU. */
#include <stdint.h>
const uint8_t
#if defined __GNUC__
__attribute__((aligned(4)))
#elif defined _MSC_VER
__declspec(align(4))
#endif
test_symbol[] = {
0x45,0x54,0x49,0x52,0x30,0x30,0x30,0x33,0x73,0x0d,0x00,0x00,0x00,0x65,0x4d,0x41,
0x54,0x5a,0x30,0x30,0x30,0x30,0x49,0x52,0x45,0x50,0x00,0x00,0x00,0x47,0x30,0x30,
0x30,0x30,0x00,0x00,0x00,0x3f,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x04,
0x06,0x00,0x80,0x00,0x3d,0x00,0x00,0x01,0xa0,0x00,0x80,0x00,0x4a,0x00,0x00,0x00,
0x00,0x00,0x00,0x01,0x00,0x00,0x0b,0x68,0x65,0x6c,0x6c,0x6f,0x20,0x77,0x6f,0x72,
0x6c,0x64,0x00,0x00,0x00,0x01,0x00,0x04,0x70,0x75,0x74,0x73,0x00,0x45,0x4e,0x44,
0x00,0x00,0x00,0x00,0x08,
};
然后你可以用下面的模板示例来执行该字节码(我们将此C程序命名为test_stub.c
):
#include <mruby.h>
#include <mruby/irep.h>
#include <test_program.c>
int
main(void)
{
mrb_state *mrb = mrb_open();
if (!mrb) { /* handle error */ }
mrb_load_irep(mrb, test_symbol);
mrb_close(mrb);
return 0;
}
这样就可以执行C数组中的字节码了
编译链接:
$ gcc -std=c99 -Imruby/include test_stub.c -o test_program mruby/build/host/lib/libmruby.a -lm
执行:
$ ./test_program
hello world
✔ 不必给用户分发Ruby源代码
✔ 无需解析Ruby源代码
✔ 产出的程序将完全是独立的
✘ 更复杂的开发周期:编程 → 编译 (mrbc
) → 集成C代码 → 编译 (gcc
等C语言编译器) → 测试 → 编程
✘ 需要照抄上面的样板才能去编程和执行
✘ 如果要更新mruby字节码需要重新编译,或者是其它的更新机制
REPL(交互式解释器) (mirb) 的方式主要用于早期开发过程。 Ruby 源代码 (.rb) 是 mruby 的最常用用法,它将 Ruby 作为一种脚本来使用,可以轻松地修改程序内容。 而 C 源代码 (.c) 是将 mruby 嵌入到您自己应用程序中最简单的做法。 字节码 (.mrb) 用法则类似 Java 程序,可以基于文件来安装程序,但是不分发源代码。 字节码 (C 语言方式) (.c) 对很多人来说可能是最复杂的一种使用 mruby 的方式,但是它也提供了在程序内嵌入 mruby 最有效的办法。(译者注:mruby 自带的 mrbgems 机制就是使用该方式嵌入 Ruby 代码的)