first commit
CI / Build (clang, clang++, ubuntu-22.04, linux, 3.10, master, x86,x86_64) (push) Canceled after 0s
CI / Build (clang, clang++, windows-2022, windows, 3.10, master, x86,x86_64) (push) Canceled after 0s
CI / Release (push) Canceled after 0s

This commit is contained in:
2026-09-13 22:18:11 +01:00
commit 08c03ac533
6701 changed files with 1577314 additions and 0 deletions
+492
View File
@@ -0,0 +1,492 @@
# Compile
mruby uses Rake to compile and cross-compile all libraries and
binaries.
## Prerequisites
To compile mruby out of the source code you need the following tools:
* C Compiler (e.g. `gcc` or `clang`)
* Linker (e.g. `gcc` or `clang`)
* Archive utility (e.g. `ar`)
* Parser generator (e.g. `bison`)
* Ruby 2.0 or later (e.g. `ruby` or `jruby`)
Note that `bison` bundled with MacOS is too old to compile `mruby`.
Try `brew install bison` and follow the instuction shown to update
the `$PATH` to compile `mruby`.
Optional:
* GIT (to update mruby source and integrate mrbgems easier)
* C++ compiler (to use GEMs which include \*.cpp, \*.cxx, \*.cc)
* Assembler (to use GEMs which include \*.asm)
## Usage
Inside of the root directory of the mruby source a file exists
called *build_config.rb*. This file contains the build configuration
of mruby and looks like this for example:
```ruby
MRuby::Build.new do |conf|
toolchain :gcc
end
```
All tools necessary to compile mruby can be set or modified here. In case
you want to maintain an additional *build_config.rb* you can define a
customized path using the *$MRUBY_CONFIG* environment variable.
To compile just call `rake` inside of the mruby source root. To
generate and execute the test tools call `rake test`. To clean
all build files call `rake clean`. To see full command line on
build, call `rake -v`.
## Build Configuration
Inside of the *build_config.rb* the following options can be configured
based on your environment.
### Toolchains
The mruby build system already contains a set of toolchain templates which
configure the build environment for specific compiler infrastructures.
#### GCC
Toolchain configuration for the GNU C Compiler.
```ruby
toolchain :gcc
```
#### clang
Toolchain configuration for the LLVM C Compiler clang. Mainly equal to the
GCC toolchain.
```ruby
toolchain :clang
```
#### Visual Studio 2010, 2012 and 2013
Toolchain configuration for Visual Studio on Windows. If you use the
[Visual Studio Command Prompt](http://msdn.microsoft.com/en-us/library/ms229859\(v=vs.110\).aspx),
you normally do not have to specify this manually, since it gets automatically detected by our build process.
```ruby
toolchain :visualcpp
```
#### Android
Toolchain configuration for Android.
```ruby
toolchain :android
```
Requires the custom standalone Android NDK and the toolchain path
in `ANDROID_STANDALONE_TOOLCHAIN`.
### Binaries
It is possible to select which tools should be compiled during the compilation
process. The following tools can be selected:
* mruby (mruby interpreter)
* mirb (mruby interactive shell)
To select them declare conf.gem as follows:
```ruby
conf.gem "#{root}/mrbgems/mruby-bin-mruby"
conf.gem "#{root}/mrbgems/mruby-bin-mirb"
```
### File Separator
Some environments require a different file separator character. It is possible to
set the character via `conf.file_separator`.
```ruby
conf.file_separator = '/'
```
### C Compiler
Configuration of the C compiler binary, flags and include paths.
```ruby
conf.cc do |cc|
cc.command = ...
cc.flags = ...
cc.include_paths = ...
cc.defines = ...
cc.option_include_path = ...
cc.option_define = ...
cc.compile_options = ...
end
```
C Compiler has header searcher to detect installed library.
If you need a include path of header file use `search_header_path`:
```ruby
# Searches ```iconv.h```.
# If found it will return include path of the header file.
# Otherwise it will return nil .
fail 'iconv.h not found' unless conf.cc.search_header_path 'iconv.h'
```
If you need a full file name of header file use `search_header`:
```ruby
# Searches ```iconv.h```.
# If found it will return full path of the header file.
# Otherwise it will return nil .
iconv_h = conf.cc.search_header 'iconv.h'
print "iconv.h found: #{iconv_h}\n"
```
Header searcher uses compiler's `include_paths` by default.
When you are using GCC toolchain (including clang toolchain since its base is gcc toolchain)
it will use compiler specific include paths too. (For example `/usr/local/include`, `/usr/include`)
If you need a special header search paths define a singleton method `header_search_paths` to C compiler:
```ruby
def conf.cc.header_search_paths
['/opt/local/include'] + include_paths
end
```
### Linker
Configuration of the Linker binary, flags and library paths.
```ruby
conf.linker do |linker|
linker.command = ...
linker.flags = ...
linker.flags_before_libraries = ...
linker.libraries = ...
linker.flags_after_libraries = ...
linker.library_paths = ....
linker.option_library = ...
linker.option_library_path = ...
linker.link_options = ...
end
```
### Archiver
Configuration of the Archiver binary and flags.
```ruby
conf.archiver do |archiver|
archiver.command = ...
archiver.archive_options = ...
end
```
### Parser Generator
Configuration of the Parser Generator binary and flags.
```ruby
conf.yacc do |yacc|
yacc.command = ...
yacc.compile_options = ...
end
```
### GPerf
Configuration of the GPerf binary and flags.
```ruby
conf.gperf do |gperf|
gperf.command = ...
gperf.compile_options = ...
end
```
### File Extensions
```ruby
conf.exts do |exts|
exts.object = ...
exts.executable = ...
exts.library = ...
end
```
### Mrbgems
Integrate GEMs in the build process.
```ruby
# Integrate GEM with additional configuration
conf.gem 'path/to/gem' do |g|
g.cc.flags << ...
end
# Integrate GEM without additional configuration
conf.gem 'path/to/another/gem'
```
See doc/mrbgems/README.md for more option about mrbgems.
### Mrbtest
Configuration Mrbtest build process.
If you want mrbtest.a only, You should set `conf.build_mrbtest_lib_only`
```ruby
conf.build_mrbtest_lib_only
```
### Bintest
Tests for mrbgem tools using CRuby.
To have bintests place \*.rb scripts to `bintest/` directory of mrbgems.
See `mruby-bin-*/bintest/*.rb` if you need examples.
If you want a temporary files use `tempfile` module of CRuby instead of `/tmp/`.
You can enable it with following:
```ruby
conf.enable_bintest
```
### C++ ABI
By default, mruby uses setjmp/longjmp to implement its
exceptions. But it doesn't release C++ stack object
correctly. To support mrbgems written in C++, mruby can be
configured to use C++ exception.
There are two levels of C++ exception handling. The one is
`enable_cxx_exception` that enables C++ exception, but
uses C ABI. The other is `enable_cxx_abi` where all
files are compiled by C++ compiler.
When you mix C++ code, C++ exception would be enabled automatically.
If you need to enable C++ exception explicitly add the following:
```ruby
conf.enable_cxx_exception
```
#### C++ exception disabling.
If your compiler does not support C++ and you want to ensure
you don't use mrbgem written in C++, you can explicitly disable
C++ exception, add following:
```ruby
conf.disable_cxx_exception
```
and you will get an error when you try to use C++ gem.
Note that it must be called before `enable_cxx_exception` or `gem` method.
### Debugging mode
To enable debugging mode add the following:
```ruby
conf.enable_debug
```
When debugging mode is enabled
* Macro `MRB_DEBUG` would be defined.
* Which means `mrb_assert()` macro is enabled.
* Debug information of irep would be generated by `mrbc`.
* Because `-g` flag would be added to `mrbc` runner.
* You can have better backtrace of mruby scripts with this.
## Cross-Compilation
mruby can also be cross-compiled from one platform to another. To
achieve this the *build_config.rb* needs to contain an instance of
`MRuby::CrossBuild`. This instance defines the compilation
tools and flags for the target platform. An example could look
like this:
```ruby
MRuby::CrossBuild.new('32bit') do |conf|
toolchain :gcc
conf.cc.flags << "-m32"
conf.linker.flags << "-m32"
end
```
All configuration options of `MRuby::Build` can also be used
in `MRuby::CrossBuild`.
### Mrbtest in Cross-Compilation
In cross compilation, you can run `mrbtest` on emulator if
you have it by changing configuration of test runner.
```ruby
conf.test_runner do |t|
t.command = ... # set emulator. this value must be non nil or false
t.flags = ... # set flags of emulator
def t.run(bin) # override `run` if you need to change the behavior of it
... # `bin` is the full path of mrbtest
end
end
```
## Build process
During the build process the directory *build* will be created in the
root directory. The structure of this directory will look like this:
+- build
|
+- host
|
+- bin <- Binaries (mirb, mrbc and mruby)
|
+- lib <- Libraries (libmruby.a and libmruby_core.a)
|
+- mrblib
|
+- src
|
+- test <- mrbtest tool
|
+- tools
|
+- mirb
|
+- mrbc
|
+- mruby
The compilation workflow will look like this:
* compile all files under *src* (object files will be stored
in *build/host/src*)
* generate parser grammar out of *src/parse.y* (generated
result will be stored in *build/host/src/y.tab.c*)
* compile *build/host/src/y.tab.c* to *build/host/src/y.tab.o*
* create *build/host/lib/libmruby_core.a* out of all object files (C only)
* create `build/host/bin/mrbc` by compiling *tools/mrbc/mrbc.c* and
linking with *build/host/lib/libmruby_core.a*
* create *build/host/mrblib/mrblib.c* by compiling all \*.rb files
under *mrblib* with `build/host/bin/mrbc`
* compile *build/host/mrblib/mrblib.c* to *build/host/mrblib/mrblib.o*
* create *build/host/lib/libmruby.a* out of all object files (C and Ruby)
* create `build/host/bin/mruby` by compiling *mrbgems/mruby-bin-mruby/tools/mruby/mruby.c* and
linking with *build/host/lib/libmruby.a*
* create `build/host/bin/mirb` by compiling *mrbgems/mruby-bin-mirb/tools/mirb/mirb.c* and
linking with *build/host/lib/libmruby.a*
```
_____ _____ ______ ____ ____ _____ _____ ____
| CC |->|GEN |->|AR |->|CC |->|CC |->|AR |->|CC |->|CC |
| *.c | |y.tab| |core.a| |mrbc| |*.rb| |lib.a| |mruby| |mirb|
----- ----- ------ ---- ---- ----- ----- ----
```
### Cross-Compilation
In case of a cross-compilation to *i386* the *build* directory structure looks
like this:
+- build
|
+- host
| |
| +- bin <- Native Binaries
| |
| +- lib <- Native Libraries
| |
| +- mrblib
| |
| +- src
| |
| +- test <- Native mrbtest tool
| |
| +- tools
| |
| +- mirb
| |
| +- mrbc
| |
| +- mruby
+- i386
|
+- bin <- Cross-compiled Binaries
|
+- lib <- Cross-compiled Libraries
|
+- mrblib
|
+- src
|
+- test <- Cross-compiled mrbtest tool
|
+- tools
|
+- mirb
|
+- mrbc
|
+- mruby
An extra directory is created for the target platform. In case you
compile for *i386* a directory called *i386* is created under the
build directory.
The cross compilation workflow starts in the same way as the normal
compilation by compiling all *native* libraries and binaries.
Afterwards the cross compilation process proceeds like this:
* cross-compile all files under *src* (object files will be stored
in *build/i386/src*)
* generate parser grammar out of *src/parse.y* (generated
result will be stored in *build/i386/src/y.tab.c*)
* cross-compile *build/i386/src/y.tab.c* to *build/i386/src/y.tab.o*
* create *build/i386/mrblib/mrblib.c* by compiling all \*.rb files
under *mrblib* with the native `build/host/bin/mrbc`
* cross-compile *build/host/mrblib/mrblib.c* to *build/host/mrblib/mrblib.o*
* create *build/i386/lib/libmruby.a* out of all object files (C and Ruby)
* create `build/i386/bin/mruby` by cross-compiling *mrbgems/mruby-bin-mruby/tools/mruby/mruby.c* and
linking with *build/i386/lib/libmruby.a*
* create `build/i386/bin/mirb` by cross-compiling *mrbgems/mruby-bin-mirb/tools/mirb/mirb.c* and
linking with *build/i386/lib/libmruby.a*
* create *build/i386/lib/libmruby_core.a* out of all object files (C only)
* create `build/i386/bin/mrbc` by cross-compiling *tools/mrbc/mrbc.c* and
linking with *build/i386/lib/libmruby_core.a*
```
_______________________________________________________________
| Native Compilation for Host System |
| _____ ______ _____ ____ ____ _____ |
| | CC | -> |AR | -> |GEN | -> |CC | -> |CC | -> |AR | |
| | *.c | |core.a| |y.tab| |mrbc| |*.rb| |lib.a| |
| ----- ------ ----- ---- ---- ----- |
---------------------------------------------------------------
||
\||/
\/
________________________________________________________________
| Cross Compilation for Target System |
| _____ _____ _____ ____ ______ _____ |
| | CC | -> |AR | -> |CC | -> |CC | -> |AR | -> |CC | |
| | *.c | |lib.a| |mruby| |mirb| |core.a| |mrbc | |
| ----- ----- ----- ---- ------ ----- |
----------------------------------------------------------------
```
## Build Configuration Examples
### Minimal Library
To build a minimal mruby library you need to use the Cross Compiling
feature due to the reason that there are functions (e.g. stdio) which
can't be disabled for the main build.
```ruby
MRuby::CrossBuild.new('Minimal') do |conf|
toolchain :gcc
conf.cc.defines = %w(MRB_DISABLE_STDIO)
conf.bins = []
end
```
This configuration defines a cross compile build called 'Minimal' which
is using the GCC and compiles for the host machine. It also disables
all usages of stdio and doesn't compile any binaries (e.g. mrbc).
## Test Environment
mruby's build process includes a test environment. In case you start the testing
of mruby, a native binary called `mrbtest` will be generated and executed.
This binary contains all test cases which are defined under *test/t*. In case
of a cross-compilation an additional cross-compiled *mrbtest* binary is
generated. You can copy this binary and run on your target system.
+370
View File
@@ -0,0 +1,370 @@
# How to Use the mruby Debugger
copyright (c) 2014 Specified Non-Profit Corporation mruby Forum
## 1. Summary
This file documents the mruby debugger ('mrdb') methods.
## 2 Debugging with mrdb
## 2.1 Building mrdb
The trunk of the mruby source tree, with the most recent mrdb, can be checked out with the following command:
```bash
$ git clone https://github.com/mruby/mruby.git
```
To run the `make` command:
```bash
$ cd mruby
$ make
```
By default, the `make` command will install the debugger files into mruby/bin.
You can add the path for mrdb on your host environment with the following command:
```bash
$ echo "export PATH=\$PATH:MRUBY_ROOT/bin" >> ~/.bashrc
$ source ~/.bashrc
```
`*MRUBY_ROOT` is the directory in which mruby source code will be installed.
To confirm mrdb was installed properly, run mrdb with the `--version` option:
```bash
$ mrdb --version
mruby 2.1.2 (2020-08-06)
```
## 2.2 Basic Operation
### 2.2.1 Debugging mruby Script Files (rb file) with mrdb
To invoke the mruby debugger, just type `mrdb`.
To specify the script file:
```bash
$ mrdb [option] file name
```
For example: Debugging sample.rb
```bash
$ mrdb sample.rb
```
You can execute the shell commands listed below:
|command|description|
|:-:|:--|
|run|execute programs|
|step|execute stepping|
|continue|execute continuing program|
|break|configure the breaking point|
|delete|deleting the breaking points|
|disable|disabling the breaking points|
|enable|enabling the breaking points|
|info breakpoints|showing list of the breaking points|
|print|evaluating and printing the values of the mruby expressions in the script|
|list|displaying the source cords|
|help|showing help|
|quit|terminating the mruby debugger|
### 2.2.2 Debugging mruby Binary Files (mrb file) with mrdb
You can debug the mruby binary files.
#### 2.2.2.1 Debugging the binary files
* notice
To debug mruby binary files, you need to compile mruby files with option `-g`.
```bash
$ mrbc -g sample.rb
```
You can debug the mruby binary files with following command and the option `-b`.
```bash
$ mrdb -b sample.mrb
```
Then you can execute all debugger shell commands.
#### Break Command
You can use any breakpoint to stop the program by specifying the line number and method name.
The breakpoint list will be displayed after you have set the breakpoint successfully.
Usage:
```
break [file:]linenum
b [file:]linenum
break [class:]method
b [class:]method
```
The breakpoint will be ordered in serial from 1.
The number, which was given to the deleted breakpoint, will never be given to another breakpoint again.
You can give multiple breakpoints to specified the line number and method.
Be ware that breakpoint command will not check the validity of the class name and method name.
You can get the current breakpoint information by the following options.
breakpoint breakpoint number : file name. line number
breakpoint breakpoint number : [class name,] method name
#### Continue Command
Usage:
```
continue [N]
c [N]
```
N: the next breakpoint number
When resuming the program, it will stop at breakpoint N (N-1 breakpoint will be ignored).
When you run the `continue` command without specifying N, the program will be stopped at the next breakpoint.
Example:
```
(foo.rb:1) continue 3
```
This will resume the program and stop it at the third breakpoint.
#### Delete Command
This will delete the specified breakpoint.
Usage:
```
delete [breakpoint-no]
d [breakpoint-no]
```
breakpoint-no: breakpoint number
Example:
```
(foo.rb:1) delete
```
This will delete all of the breakpoints.
```
(foo.rb:1) delete 1 3
```
This will delete the breakpoint at 1 and 3.
#### Disable Command
This will disable the specified breakpoint.
Usage:
```
disable [breakpoint-no]
dis [breakpoint-no]
```
reappointing: breakpoint number
Example:
```
(foo.rb:1) disable
```
Use `disable` if you would like to disable all of the breakpoints.
```
(foo.rb:1) disable 1 3
```
This will disable the breakpoints at 1 and 3.
#### Enable Command
This will enable the specified breakpoints.
Usage:
```
enable [breakpoint-no]
e [breakpoint-no]
```
breakpoint-no: breakpoint number
Example:
```
(foo.rb:1) enable
```
Enabling all breakpoints
```
(foo.rb:1) enable 1 3
```
Enabling the breakpoint 1 and 3
#### eval command
Evaluating the string as source code and printing the value.
Same as print command, please see print command.
#### help command
Displaying the help message.
Usage:
```
help [command]
h [command]
```
Typing `help` without any options will display the command list.
#### Info Breakpoints Command
Displaying the specified breakpoint information.
Usage:
```
info breakpoints [breakpoint-no]
i b [breakpoint-no]
```
breakpoint-no: breakpoint number
Typing "info breakpoints" without ant option will display all breakpoint information.
Example:
```
(sample.rb:1) info breakpoints
Num Type Enb What
1 breakpoint y at sample.rb:3 -> file name,line number
2 breakpoint n in Sample_class:sample_class_method -> [class:]method name
3 breakpoint y in sample_global_method
```
Displaying the specified breakpoint number:
```
(foo.rb:1) info breakpoints 1 3
Num Type Enb What
1 breakpoint y at sample.rb:3
3 breakpoint y in sample_global_method
```
#### List Command
To display the code of the source file.
Usage:
```
list [filename:]first[,last]
l [filename]:first[,last]
```
first: the opening row number
last : the closing row number
When you specify the `first`, but not the `last` option, you will receive 10 rows.
When you do not specify both the `first` and `last` options, you will receive the next 10 rows.
Example:
```
Specifying file name and first row number
sample.rb:1) list sample2.rb:5
```
Specifying the file name and the first and last row number:
```
(sample.rb:1) list sample2.rb:6,7
```
#### Print Command
Evaluating the string as source code and printing the value.
Usage:
```
print [expr]
p [expr]
```
expr: expression
The expression is mandatory.
The displayed expressions will be serially ordered from 1.
If an exception occurs, the exception information will be displayed and the debugging will be continued.
Example:
```
(sample.rb:1) print 1+2
$1 = 3
(sample.rb:1) print self
$2 = main
```
Below is the case of the exception:
```
(sample.rb:1) print (1+2
$1 = SyntaxError: line 1: syntax error, unexpected $end, expecting ')'
```
#### Quit Command
Quitting the debugger.
Usage:
```
quit
q
```
#### Run Command
Running the program and stopping at the first breakpoint.
Usage:
```
run
r
```
#### Step Command
This will run the program step by step.
When the method and the block are invoked, the program will be stop at the first row.
The program, which is developed in C, will be ignored.
+177
View File
@@ -0,0 +1,177 @@
# How to use `mrb_gc_arena_save()`/`mrb_gc_arena_restore()`/`mrb_gc_protect()`
_This is an English translation of [Matz's blog post][matz blog post]
written in Japanese._
_Some parts are updated to reflect recent changes._
[matz blog post]: http://www.rubyist.net/~matz/20130731.html
When you are extending mruby using C language, you may encounter
mysterious "arena overflow error" or memory leak or very slow
execution speed. This is an error indicating overflow of "GC arena"
implementing "conservative GC".
GC (garbage collector) must ensure that object is "alive", in other
words, that it is referenced by somewhere from program. This can be
determined by checking if the object can be directly or indirectly
referenced by root. The local variables, global variables and
constants etc are root.
If program execution is performed inside mruby VM, there is nothing to
worry about because GC can access all roots owned by VM.
The problem arises when executing C functions. The object referenced
by C variable is also "alive", but mruby GC cannot aware of this, so
it might mistakenly recognize the objects referenced by only C
variables as dead.
This can be a fatal bug if the GC tries to collect a live object.
In CRuby, we scan C stack area, and use C variable as root to check
whether object is alive or not. Of course, because we are accessing C
stack just as memory region, we never know it is an integer or a
pointer. We workaround this by assuming that if it looks like a
pointer, then assume it as a pointer. We call it "conservative".
By the way, CRuby's "conservative GC" has some problems.
The biggest problem is we have no way to access to the stack area in
portable way. Therefore, we cannot use this method if we'd like to
implement highly portable runtime, like mruby.
So we came up with an another plan to implement "conservative GC" in mruby.
Again, the problem is when an object which was created in C function, becomes
no longer referenced in the Ruby world, and cannot be treated as garbage.
In mruby, we recognize all objects created in C function are alive.
Then we have no problem such as confusing a live object as dead.
This means that because we cannot collect truly dead object, we may
lose efficiency, but as a trade-off the GC itself is highly portable.
We can say goodbye to the problem that GC deletes live objects due to
optimization which sometimes occurs in CRuby.
According to this idea, we have a table, called "GC arena", which
remembers objects created in C function.
The arena is stack structure, when C function execution is returned to mruby
VM, all objects registered in the arena are popped.
This works very well, but can cause another problem: "arena overflow error" or
memory leak.
As of this writing, mruby automatically extend arena to remember
objects (See `MRB_GC_FIXED_ARENA` and `MRB_GC_ARENA_SIZE` in
doc/guides/mrbconf.md).
If you create many objects in C functions, memory usage will increase, since
GC never kick in. This memory usage may look like memory leak, but will also
make execution slower as more memory will need to be allocated.
With the build time configuration, you can limit the maximum size of
arena (e.g., 100). Then if you create many objects, arena overflows,
thus you will get an "arena overflow error".
To workaround these problems, we have `mrb_gc_arena_save()` and
`mrb_gc_arena_restore()` functions.
`int mrb_gc_arena_save(mrb)` returns the current position of the stack
top of GC arena, and `void mrb_gc_arena_restore(mrb, idx)` sets the
stack top position to back to given `idx`.
We can use them like this:
```c
int arena_idx = mrb_gc_arena_save(mrb);
// ...create objects...
mrb_gc_arena_restore(mrb, arena_idx);
```
In mruby, C function calls are surrounded by this save/restore, but we
can further optimize memory usage by surrounding save/restore, and can
avoid creating arena overflow bugs.
Let's take a real example. Here is the source code of `Array#inspect`:
```c
static mrb_value
inspect_ary(mrb_state *mrb, mrb_value ary, mrb_value list)
{
mrb_int i;
mrb_value s, arystr;
char head[] = { '[' };
char sep[] = { ',', ' ' };
char tail[] = { ']' };
/* check recursive */
for(i=0; i<RARRAY_LEN(list); i++) {
if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) {
return mrb_str_new(mrb, "[...]", 5);
}
}
mrb_ary_push(mrb, list, ary);
arystr = mrb_str_new_capa(mrb, 64);
mrb_str_cat(mrb, arystr, head, sizeof(head));
for(i=0; i<RARRAY_LEN(ary); i++) {
int ai = mrb_gc_arena_save(mrb);
if (i > 0) {
mrb_str_cat(mrb, arystr, sep, sizeof(sep));
}
if (mrb_array_p(RARRAY_PTR(ary)[i])) {
s = inspect_ary(mrb, RARRAY_PTR(ary)[i], list);
}
else {
s = mrb_inspect(mrb, RARRAY_PTR(ary)[i]);
}
mrb_str_cat(mrb, arystr, RSTRING_PTR(s), RSTRING_LEN(s));
mrb_gc_arena_restore(mrb, ai);
}
mrb_str_cat(mrb, arystr, tail, sizeof(tail));
mrb_ary_pop(mrb, list);
return arystr;
}
```
This is a real example, so a little bit complicated, but bear with me.
The essence of `Array#inspect` is that after stringifying each element
of array using `inspect` method, we join them together so that we can
get `inspect` representation of the entire array.
After the `inspect` representation is created, we no longer require the
individual string representation. This means that we don't have to register
these temporal objects into GC arena.
Therefore, in order to keep the arena size small; the `ary_inspect()` function
will do the following:
* save the position of the stack top using `mrb_gc_arena_save()`.
* get `inspect` representation of each element.
* append it to the constructing entire `inspect` representation of array.
* restore stack top position using `mrb_gc_arena_restore()`.
Please note that the final `inspect` representation of entire array
was created before the call of `mrb_gc_arena_restore()`. Otherwise,
required temporal object may be deleted by GC.
We may have a usecase where after creating many temporal objects, we'd
like to keep some of them. In this case, we cannot use the same idea
in `ary_inspect()` like appending objects to existing one.
Instead, after `mrb_gc_arena_restore()`, we must re-register the objects we
want to keep in the arena using `mrb_gc_protect(mrb, obj)`.
Use `mrb_gc_protect()` with caution because it could also lead to an "arena
overflow error".
We must also mention that when `mrb_funcall` is called in top level, the return
value is also registered to GC arena, so repeated use of `mrb_funcall` may
eventually lead to an "arena overflow error".
Use `mrb_gc_arena_save()` and `mrb_gc_arena_restore()` or possible use of
`mrb_gc_protect()` to workaround this.
+181
View File
@@ -0,0 +1,181 @@
# mruby configuration macros.
## How to use these macros.
You can use mrbconfs with following ways:
* Write them in `mrbconf.h`.
* Using compiler flags is preferred when building a cross binaries or multiple mruby binaries
since it's easier to use different mrbconf per each `MRuby::Build`.
* Most flags can be enabled by just commenting in.
* Pass them as compiler flags.
* Make sure you pass the same flags to all compilers since some mrbconf(e.g., `MRB_GC_FIXED_ARENA`)
changes `struct` layout and cause memory access error when C and other language(e.g., C++) is mixed.
## stdio setting.
`MRB_DISABLE_STDIO`
* When defined `<stdio.h>` functions won't be used.
* Some features will be disabled when this is enabled:
* `mrb_irep` load/dump from/to file.
* Compiling mruby script from file.
* Printing features in **src/print.c**.
## Debug macros.
`MRB_ENABLE_DEBUG_HOOK`
* When defined code fetch hook and debug OP hook will be enabled.
* When using any of the hook set function pointer `code_fetch_hook` and/or `debug_op_hook` of `mrb_state`.
* Fetch hook will be called before any OP.
* Debug OP hook will be called when dispatching `OP_DEBUG`.
`MRB_DEBUG`
* When defined `mrb_assert*` macro will be defined with macros from `<assert.h>`.
* Could be enabled via `enable_debug` method of `MRuby::Build`.
## Stack configuration
`MRB_STACK_EXTEND_DOUBLING`
* If defined doubles the stack size when extending it.
* Else extends stack with `MRB_STACK_GROWTH`.
`MRB_STACK_GROWTH`
* Default value is `128`.
* Used in stack extending.
* Ignored when `MRB_STACK_EXTEND_DOUBLING` is defined.
`MRB_STACK_MAX`
* Default value is `0x40000 - MRB_STACK_GROWTH`.
* Raises `RuntimeError` when stack size exceeds this value.
## Primitive type configuration.
`MRB_USE_FLOAT`
* When defined single precision floating point type(C type `float`) is used as `mrb_float`.
* Else double precision floating point type(C type `double`) is used as `mrb_float`.
`MRB_WITHOUT_FLOAT`
* When defined removes floating point numbers from mruby.
* It makes mruby easier to handle in "Microcontroller without FPU" and "Kernel Space".
`MRB_INT32`
* When defined, or `MRB_INT64` are not defined on 32-bit CPU mode, `mrb_int` will be defined as `int32_t`.
* Conflicts with `MRB_INT64`.
`MRB_INT64`
* When defined, or `MRB_INT32` are not defined on 64-bit CPU mode, `mrb_int` will be defined as `int64_t`.
* Conflicts with `MRB_INT32`.
## Garbage collector configuration.
`MRB_GC_STRESS`
* When defined full GC is emitted per each `RBasic` allocation.
* Mainly used in memory manager debugging.
`MRB_GC_TURN_OFF_GENERATIONAL`
* When defined turns generational GC by default.
`MRB_GC_FIXED_ARENA`
* When defined used fixed size GC arena.
* Raises `RuntimeError` when this is defined and GC arena size exceeds `MRB_GC_ARENA_SIZE`.
* Useful tracking unnecessary mruby object allocation.
`MRB_GC_ARENA_SIZE`
* Default value is `100`.
* Ignored when `MRB_GC_FIXED_ARENA` isn't defined.
* Defines fixed GC arena size.
`MRB_HEAP_PAGE_SIZE`
* Defines value is `1024`.
* Specifies number of `RBasic` per each heap page.
## Memory pool configuration.
`POOL_ALIGNMENT`
* Default value is `4`.
* If you're allocating data types that requires alignment more than default value define the
largest value of required alignment.
`POOL_PAGE_SIZE`
* Default value is `16000`.
* Specifies page size of pool page.
* Smaller the value is increases memory overhead.
## State atexit configuration.
`MRB_FIXED_STATE_ATEXIT_STACK`
* If defined enables fixed size `mrb_state` atexit stack.
* Raises `RuntimeError` when `mrb_state_atexit` call count to same `mrb_state` exceeds
`MRB_FIXED_STATE_ATEXIT_STACK_SIZE`'s value.
`MRB_FIXED_STATE_ATEXIT_STACK_SIZE`
* Default value is `5`.
* If `MRB_FIXED_STATE_ATEXIT_STACK` isn't defined this macro is ignored.
## `mrb_value` configuration.
`MRB_ENDIAN_BIG`
* If defined compiles mruby for big endian machines.
* Used in `MRB_NAN_BOXING`.
* Some mrbgem use this mrbconf.
`MRB_NAN_BOXING`
* If defined represent `mrb_value` in boxed `double`.
* Conflicts with `MRB_USE_FLOAT` and `MRB_WITHOUT_FLOAT`.
`MRB_WORD_BOXING`
* If defined represent `mrb_value` as a word.
* If defined `Float` will be a mruby object with `RBasic`.
## Instance variable configuration.
`MRB_IV_SEGMENT_SIZE`
* Default value is `4`.
* Specifies size of each segment in segment list.
## Reduce heap memory configuration.
`MRB_USE_LINK_TIME_RO_DATA_P`
* Only available on ELF platforms.
* If you specify the address of a read-only section when creating a symbol or string, that string will be used as it is.
* Heap memory can be saved.
* Uses `__ehdr_start` and `__init_array_start`.
* It must be `__ehdr_start < data_addr < __init_array_start`.
`MRB_USE_CUSTOM_RO_DATA_P`
* Takes precedence over `MRB_USE_LINK_TIME_RO_DATA_P`.
* Please try if `MRB_USE_LINK_TIME_RO_DATA_P` is not available.
* The `mrb_ro_data_p()` function is implemented by the user in an arbitrary file.
* The prototype declaration is `mrb_bool mrb_ro_data_p(const char *ptr)`.
* Return `TRUE` if `ptr` is in read-only section, otherwise return `FALSE`.
## Other configuration.
`MRB_UTF8_STRING`
* Adds UTF-8 encoding support to character-oriented String instance methods.
* If it isn't defined, they only support the US-ASCII encoding.
`MRB_FUNCALL_ARGC_MAX`
* Default value is `16`.
* Specifies 4th argument(`argc`) max value of `mrb_funcall`.
* Raises `ArgumentError` when the `argc` argument is bigger then this value `mrb_funcall`.
`KHASH_DEFAULT_SIZE`
* Default value is `32`.
* Specifies default size of khash table bucket.
* Used in `kh_init_ ## name` function.
`MRB_STR_BUF_MIN_SIZE`
* Default value is `128`.
* Specifies initial capacity of `RString` created by `mrb_str_buf_new` function..
`MRB_METHOD_CACHE`
* Improve performance for method dispatch.
`MRB_METHOD_CACHE_SIZE`
* Default value is `128`.
* Ignored if `MRB_METHOD_CACHE` is not defined.
* Need to be the power of 2.
`MRB_METHOD_T_STRUCT`
* Use C struct to represent `mrb_method_t`
* No `MRB_METHOD_T_STRUCT` requires highest 2 bits of function pointers to be zero
* Define this macro on machines that use higher bits of pointers
`MRB_ENABLE_ALL_SYMBOLS`
* Make it available `Symbols.all_symbols` in `mrbgems/mruby-symbol-ext`
* Increase heap memory usage.
+350
View File
@@ -0,0 +1,350 @@
# mrbgems
mrbgems is a library manager to integrate C and Ruby extension in an easy and
standardised way into mruby.
## Usage
By default mrbgems is currently deactivated. As soon as you add a GEM to your
build configuration (i.e. *build_config.rb*), mrbgems will be activated and the
extension integrated.
To add a GEM into the *build_config.rb* add the following line for example:
```ruby
conf.gem '/path/to/your/gem/dir'
```
You can also use a relative path which would be relative from the mruby root:
```ruby
conf.gem 'examples/mrbgems/ruby_extension_example'
```
A remote GIT repository location for a GEM is also supported:
```ruby
conf.gem :git => 'https://github.com/masuidrive/mrbgems-example.git', :branch => 'master'
conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master'
conf.gem :bitbucket => 'mruby/mrbgems-example', :branch => 'master'
```
You can specify the sub directory of the repository with `:path` option:
```ruby
conf.gem github: 'mruby/mruby', path: 'mrbgems/mruby-socket'
```
To use mrbgem from [mgem-list](https://github.com/mruby/mgem-list) use `:mgem` option:
```ruby
conf.gem :mgem => 'mruby-yaml'
conf.gem :mgem => 'yaml' # 'mruby-' prefix could be omitted
```
For specifying commit hash to checkout use `:checksum_hash` option:
```ruby
conf.gem mgem: 'mruby-redis', checksum_hash: '3446d19fc4a3f9697b5ddbf2a904f301c42f2f4e'
```
If there is missing dependencies, mrbgem dependencies solver will reference
mrbgem from core or mgem-list.
To pull all gems from remote GIT repository on build, call ```rake -p```,
or ```rake --pull-gems```.
NOTE: `:bitbucket` option supports only git. Hg is unsupported in this version.
## GemBox
There are instances when you wish to add a collection of mrbgems into mruby at
once, or be able to substitute mrbgems based on configuration, without having to
add each gem to the *build_config.rb* file. A packaged collection of mrbgems
is called a GemBox. A GemBox is a file that contains a list of mrbgems to load
into mruby, in the same format as if you were adding them to *build_config.rb*
via `config.gem`, but wrapped in an `MRuby::GemBox` object. GemBoxes are
loaded into mruby via `config.gembox 'boxname'`.
Below we have created a GemBox containing *mruby-time* and *mrbgems-example*:
```ruby
MRuby::GemBox.new do |conf|
conf.gem "#{root}/mrbgems/mruby-time"
conf.gem :github => 'masuidrive/mrbgems-example'
end
```
As mentioned, the GemBox uses the same conventions as `MRuby::Build`. The GemBox
must be saved with a *.gembox* extension inside the *mrbgems* directory to to be
picked up by mruby.
To use this example GemBox, we save it as `custom.gembox` inside the *mrbgems*
directory in mruby, and add the following to our *build_config.rb* file inside
the build block:
```ruby
conf.gembox 'custom'
```
This will cause the *custom* GemBox to be read in during the build process,
adding *mruby-time* and *mrbgems-example* to the build.
If you want, you can put GemBox outside of mruby directory. In that case you must
specify an absolute path like below.
```ruby
conf.gembox "#{ENV["HOME"]}/mygemboxes/custom"
```
There are two GemBoxes that ship with mruby: [default](../../mrbgems/default.gembox)
and [full-core](../../mrbgems/full-core.gembox). The [default](../../mrbgems/default.gembox) GemBox
contains several core components of mruby, and [full-core](../../mrbgems/full-core.gembox)
contains every gem found in the *mrbgems* directory.
## GEM Structure
The maximal GEM structure looks like this:
+- GEM_NAME <- Name of GEM
|
+- include/ <- Header for Ruby extension (will exported)
|
+- mrblib/ <- Source for Ruby extension
|
+- src/ <- Source for C extension
|
+- test/ <- Test code (Ruby)
|
+- mrbgem.rake <- GEM Specification
|
+- README.md <- Readme for GEM
The folder *mrblib* contains pure Ruby files to extend mruby. The folder *src*
contains C/C++ files to extend mruby. The folder *include* contains C/C++ header
files. The folder *test* contains C/C++ and pure Ruby files for testing purposes
which will be used by `mrbtest`. *mrbgem.rake* contains the specification
to compile C and Ruby files. *README.md* is a short description of your GEM.
## Build process
mrbgems expects a specification file called *mrbgem.rake* inside of your
GEM directory. A typical GEM specification could look like this for example:
```ruby
MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Example mrbgem using C and ruby'
end
```
The mrbgems build process will use this specification to compile Object and Ruby
files. The compilation results will be added to *lib/libmruby.a*. This file exposes
the GEM functionality to tools like `mruby` and `mirb`.
The following properties can be set inside of your `MRuby::Gem::Specification` for
information purpose:
* `spec.license` or `spec.licenses` (A single license or a list of them under which this GEM is licensed)
* `spec.author` or `spec.authors` (Developer name or a list of them)
* `spec.version` (Current version)
* `spec.description` (Detailed description)
* `spec.summary`
* One line short description of mrbgem.
* Printed in build summary of rake when set.
* `spec.homepage` (Homepage)
* `spec.requirements` (External requirements as information for user)
The `license` and `author` properties are required in every GEM!
In case your GEM is depending on other GEMs please use
`spec.add_dependency(gem, *requirements[, default_get_info])` like:
```ruby
MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
# Add GEM dependency mruby-parser.
# The version must be between 1.0.0 and 1.5.2 .
spec.add_dependency('mruby-parser', '>= 1.0.0', '<= 1.5.2')
# Use any version of mruby-uv from github.
spec.add_dependency('mruby-uv', '>= 0.0.0', :github => 'mattn/mruby-uv')
# Use latest mruby-onig-regexp from github. (version requirements can be omitted)
spec.add_dependency('mruby-onig-regexp', :github => 'mattn/mruby-onig-regexp')
# You can add extra mgems active only on test
spec.add_test_dependency('mruby-process', :github => 'iij/mruby-process')
end
```
The version requirements and default gem information are optional.
Version requirement supports following operators:
* '=': is equal
* '!=': is not equal
* '>': is greater
* '<': is lesser
* '>=': is equal or greater
* '<=': is equal or lesser
* '~>': is equal or greater and is lesser than the next major version
* example 1: '~> 2.2.2' means '>= 2.2.2' and '< 2.3.0'
* example 2: '~> 2.2' means '>= 2.2.0' and '< 3.0.0'
When more than one version requirements is passed, the dependency must satisfy all of it.
You can have default gem to use as dependency when it's not defined in *build_config.rb*.
When the last argument of `add_dependency` call is `Hash`, it will be treated as default gem information.
Its format is same as argument of method `MRuby::Build#gem`, expect that it can't be treated as path gem location.
When a special version of dependency is required,
use `MRuby::Build#gem` in *build_config.rb* to override default gem.
If you have conflicting GEMs use the following method:
* `spec.add_conflict(gem, *requirements)`
* The `requirements` argument is same as in `add_dependency` method.
like following code:
```ruby
MRuby::Gem::Specification.new 'some-regexp-binding' do |spec|
spec.license = 'BSD'
spec.author = 'John Doe'
spec.add_conflict 'mruby-onig-regexp', '> 0.0.0'
spec.add_conflict 'mruby-hs-regexp'
spec.add_conflict 'mruby-pcre-regexp'
spec.add_conflict 'mruby-regexp-pcre'
end
```
In case your GEM has more complex build requirements you can use
the following options additionally inside of your GEM specification:
* `spec.cc.flags` (C compiler flags)
* `spec.cc.defines` (C compiler defines)
* `spec.cc.include_paths` (C compiler include paths)
* `spec.linker.flags` (Linker flags)
* `spec.linker.libraries` (Linker libraries)
* `spec.linker.library_paths` (Linker additional library path)
* `spec.bins` (Generate binary file)
* `spec.rbfiles` (Ruby files to compile)
* `spec.objs` (Object files to compile)
* `spec.test_rbfiles` (Ruby test files for integration into mrbtest)
* `spec.test_objs` (Object test files for integration into mrbtest)
* `spec.test_preload` (Initialization files for mrbtest)
You also can use `spec.mruby.cc` and `spec.mruby.linker` to add extra global parameters for compiler and linker.
### include_paths and dependency
Your GEM can export include paths to another GEMs that depends on your GEM.
By default, `/...absolute path.../{GEM_NAME}/include` will be exported.
So it is recommended not to put GEM's local header files on include/.
These exports are retroactive.
For example: when B depends to C and A depends to B, A will get include paths exported by C.
Exported include_paths are automatically appended to GEM local include_paths by rake.
You can use `spec.export_include_paths` accessor if you want more complex build.
## C Extension
mruby can be extended with C. This is possible by using the C API to
integrate C libraries into mruby.
### Preconditions
mrbgems expects that you have implemented a C method called
`mrb_YOURGEMNAME_gem_init(mrb_state)`. `YOURGEMNAME` will be replaced
by the name of your GEM. If you call your GEM *c_extension_example*, your
initialisation method could look like this:
```C
void
mrb_c_extension_example_gem_init(mrb_state* mrb) {
struct RClass *class_cextension = mrb_define_module(mrb, "CExtension");
mrb_define_class_method(mrb, class_cextension, "c_method", mrb_c_method, MRB_ARGS_NONE());
}
```
### Finalize
mrbgems expects that you have implemented a C method called
`mrb_YOURGEMNAME_gem_final(mrb_state)`. `YOURGEMNAME` will be replaced
by the name of your GEM. If you call your GEM *c_extension_example*, your
finalizer method could look like this:
```C
void
mrb_c_extension_example_gem_final(mrb_state* mrb) {
free(someone);
}
```
### Example
+- c_extension_example/
|
+- src/
| |
| +- example.c <- C extension source
|
+- test/
| |
| +- example.rb <- Test code for C extension
|
+- mrbgem.rake <- GEM specification
|
+- README.md
## Ruby Extension
mruby can be extended with pure Ruby. It is possible to override existing
classes or add new ones in this way. Put all Ruby files into the *mrblib*
folder.
### Pre-Conditions
none
### Example
+- ruby_extension_example/
|
+- mrblib/
| |
| +- example.rb <- Ruby extension source
|
+- test/
| |
| +- example.rb <- Test code for Ruby extension
|
+- mrbgem.rake <- GEM specification
|
+- README.md
## C and Ruby Extension
mruby can be extended with C and Ruby at the same time. It is possible to
override existing classes or add new ones in this way. Put all Ruby files
into the *mrblib* folder and all C files into the *src* folder.
mruby codes under *mrblib* directory would be executed after gem init C
function is called. Make sure *mruby script* depends on *C code* and
*C code* doesn't depend on *mruby script*.
### Pre-Conditions
See C and Ruby example.
### Example
+- c_and_ruby_extension_example/
|
+- mrblib/
| |
| +- example.rb <- Ruby extension source
|
+- src/
| |
| +- example.c <- C extension source
|
+- test/
| |
| +- example.rb <- Test code for C and Ruby extension
|
+- mrbgem.rake <- GEM specification
|
+- README.md