README.md in mruby_tools-0.0.3.1 vs README.md in mruby_tools-0.0.4.1

- old
+ new

@@ -11,10 +11,19 @@ `mrbt` accepts any number of .rb files and "compiles" them into a standalone executable using mruby. The .rb files must be [mruby-compatible](https://github.com/mruby/mruby/blob/master/doc/limitations.md) (roughly equivalent to MRI v1.9). +Two primary modes of operation are supported: + +1. ruby code is injected into a C wrapper which is then compiled. The ruby +code is **interpreted** every time the resulting binary is executed. + +2. ruby code is first interpreted into **bytecode**, and the bytecode +is injected into a C wrapper which is then compiled. This means a faster +runtime as the code interpretation is not performed at runtime. + ## Install ### `git clone` By using `git clone` rather than `gem install`, you can make use of rake @@ -65,20 +74,28 @@ ```shell gem install mruby_tools ``` -Now, `mrbt` may be used. It will need to know where to find the mruby_dir, -so specify it with the `-m` flag or `MRUBY_DIR` environment variable. +Now, `mrbt` may be used. We set the `MRUBY_DIR` environment variable: ```shell -export MRUBY_DIR=~/src/mruby-1.3.0 # or wherever +export MRUBY_DIR=~/src/mruby-1.3.0 # or wherever it lives mrbt file1.rb file2.rb # etc. ``` ## Usage +``` + USAGE: mrbt file1.rb file2.rb ... +OPTIONS: -o outfile (provide a name for the standalone executable) + -c generated.c (leave the specified C file on the filesystem) + -m mruby_dir (provide the dir for mruby src) + -b (pregenerate ruby bytecode for faster execution) + -v (verbose) +``` + With no additional options, `mrbt` will inject the contents of file1.rb and file2.rb into C strings, to be loaded with mrb_load_nstring(), written to a Tempfile. `mrbt` then compiles the generated .c file using GCC and writes a standalone executable (around 1.5 MB for "hello world"). @@ -95,30 +112,17 @@ rake mrbt -- examples/hello_world.rb examples/goodbye_world.rb -o adios ``` Other useful rake tasks: -* hello world - compiles and runs `examples/hello_world.rb` -* timed_simplex - compiles and runs several files that work together +* hello world - compiles and runs `examples/hello_world.rb` +* timed_simplex - compiles and runs several files that work together * raise_exception - compiles and runs `examples/raise.rb` * examples - runs hello_world and timed_simplex -* verbose - add verbose output, e.g. `rake verbose hello_world` +* verbose - add verbose output, e.g. `rake verbose hello_world` +* bytecode - enable bytecode generation at compile time -### With *rubygems* - -```shell -mrbt -h -``` - -``` - USAGE: mrbt file1.rb file2.rb ... -OPTIONS: -o outfile (provide a name for the standalone executable) - -c generated.c (leave the specified C file on the filesystem) - -m mruby_dir (provide the dir for mruby src) - -v (verbose) -``` - ## Examples There are some example .rb files in examples/ that can be used to produce an executable. Use `mrbt` or `rake mrbt` as appropriate: @@ -160,11 +164,11 @@ # or even rake verbose hello_world ``` ``` -/home/vagrant/.rubies/ruby-2.4.0/bin/ruby -Ilib bin/mrbt examples/hello_world.rb -o examples/hello_world -v +/home/vagrant/.rubies/ruby-2.4.0/bin/ruby -Ilib bin/mrbt -v examples/hello_world.rb -o examples/hello_world #include <stdlib.h> #include <mruby.h> #include <mruby/compile.h> #include <mruby/string.h> @@ -196,25 +200,25 @@ mrb_close(mrb); return 0; } -generated /tmp/mrbt-20171117-24568-no7ee3.c +generated /tmp/mrbt-20171122-20650-4pi6tt.c compiling... created binary executable: examples/hello_world file examples/hello_world -examples/hello_world: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=2114ab60983156c92a5a74b88895f9c43a4bb086, not stripped +examples/hello_world: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=e9fb81e70686e761cf49202efc4f3e733d7aab17, not stripped stat examples/hello_world File: ‘examples/hello_world’ - Size: 1559056 Blocks: 3048 IO Block: 4096 regular file -Device: 801h/2049d Inode: 388049 Links: 1 + Size: 1631784 Blocks: 3192 IO Block: 4096 regular file +Device: 801h/2049d Inode: 388542 Links: 1 Access: (0755/-rwxr-xr-x) Uid: ( 1000/ vagrant) Gid: ( 1000/ vagrant) -Access: 2017-11-17 18:48:25.713629203 +0000 -Modify: 2017-11-17 18:48:25.709629203 +0000 -Change: 2017-11-17 18:48:25.709629203 +0000 +Access: 2017-11-22 23:42:12.202875568 +0000 +Modify: 2017-11-22 23:42:12.190881566 +0000 +Change: 2017-11-22 23:42:12.190881566 +0000 Birth: - examples/hello_world hello_world ``` @@ -222,5 +226,84 @@ This proceeds exactly as before but with additional output: * Show the generated C code * Note the temporary file containing the C code * Call `file` and `stat` on the output executable + +### Verbose Bytecode Hello World + +```shell +mrbt -v examples/hello_world.rb -b + +# or +rake mrbt -- -b examples/hello_world.rb -v + +# or even +rake verbose bytecode hello_world +``` + +``` +/home/vagrant/.rubies/ruby-2.4.0/bin/ruby -Ilib bin/mrbt -b -v examples/hello_world.rb -o examples/hello_world +creating bytecode.mrb... +#include <stdlib.h> +#include <stdint.h> +#include <mruby.h> +#include <mruby/string.h> +#include <mruby/irep.h> + +const uint8_t +#if defined __GNUC__ +__attribute__((aligned(4))) +#elif defined _MSC_VER +__declspec(align(4)) +#endif +/* bytecode.mrb */ +test_symbol[] = { +0x52,0x49,0x54,0x45,0x30,0x30,0x30,0x34,0x22,0x80,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,0x00,0x80,0x00,0x06,0x01,0x00,0x00,0x84,0x00,0x80,0x00,0xa0,0x00,0x00,0x00,0x4a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x04,0x70,0x75,0x74,0x73,0x00,0x00,0x0b,0x68,0x65,0x6c,0x6c,0x6f,0x5f,0x77,0x6f,0x72,0x6c,0x64,0x00,0x45,0x4e,0x44,0x00,0x00,0x00,0x00,0x08, +}; + +void check_exc(mrb_state *mrb) { + if (mrb->exc) { + mrb_value exc = mrb_obj_value(mrb->exc); + mrb_value exc_msg = mrb_funcall(mrb, exc, "to_s", 0); + fprintf(stderr, "ERROR %s: %s\n", + mrb_obj_classname(mrb, exc), + mrb_str_to_cstr(mrb, exc_msg)); + /* mrb_print_backtrace(mrb); # empty */ + exit(1); + } +} + +int +main(void) +{ + mrb_state *mrb = mrb_open(); + if (!mrb) { + printf("mrb problem"); + exit(1); + } + mrb_load_irep(mrb, test_symbol); + check_exc(mrb); + mrb_close(mrb); + return 0; +} + +generated /tmp/mrbt-20171122-25456-azsw3n.c +compiling... +created binary executable: examples/hello_world + +file examples/hello_world +examples/hello_world: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=61e903e56a9e5d1159cb5a5ea4a669b05b493f44, not stripped + +stat examples/hello_world + File: ‘examples/hello_world’ + Size: 1324616 Blocks: 2592 IO Block: 4096 regular file +Device: 801h/2049d Inode: 388542 Links: 1 +Access: (0755/-rwxr-xr-x) Uid: ( 1000/ vagrant) Gid: ( 1000/ vagrant) +Access: 2017-11-22 23:46:09.540147567 +0000 +Modify: 2017-11-22 23:46:09.536149567 +0000 +Change: 2017-11-22 23:46:09.536149567 +0000 + Birth: - + +examples/hello_world +hello_world +```