mruby uses Rake to compile and cross-compile all libraries and binaries.
To compile mruby out of the source code you need the following tools: * C
Compiler (e.g. gcc
) * Linker (e.g. gcc
) * Archive
utility (e.g. ar
) * Parser generator (e.g. bison
)
* Ruby 2.0 or later (e.g. ruby
or jruby
)
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)
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 ./minirake
inside of the mruby source
root. To generate and execute the test tools call ./minirake
test
. To clean all build files call ./minirake clean
.
To see full command line on build, call ./minirake -v
.
Inside of the build_config.rb the following options can be configured based on your environment.
The mruby build system already contains a set of toolchain templates which configure the build environment for specific compiler infrastructures.
Toolchain configuration for the GNU C Compiler. ruby toolchain :gcc
Toolchain configuration for the LLVM C Compiler clang. Mainly equal to the
GCC toolchain. ruby toolchain :clang
Toolchain configuration for Visual Studio on Windows. If you use the Visual
Studio Command Prompt, you normally do not have to specify this
manually, since it gets automatically detected by our build process.
ruby toolchain :visualcpp
Toolchain configuration for Android. ruby toolchain :android
Requires the custom standalone Android NDK and the toolchain path in
ANDROID_STANDALONE_TOOLCHAIN
.
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"
Some environments require a different file separator character. It is
possible to set the character via conf.file_separator
.
ruby conf.file_separator = '/'
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
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
Configuration of the Archiver binary and flags. ruby conf.archiver do
|archiver| archiver.command = ... archiver.archive_options = ... end
Configuration of the Parser Generator binary and flags. ruby
conf.yacc do |yacc| yacc.command = ... yacc.compile_options = ... end
Configuration of the GPerf binary and flags. ruby conf.gperf do
|gperf| gperf.command = ... gperf.compile_options = ... end
conf.exts do |exts| exts.object = ... exts.executable = ... exts.library = ... end
Integrate GEMs in the build process. “`ruby
conf.gem 'path/to/gem' do |g| g.cc.flags << … end
conf.gem 'path/to/another/gem' “`
See doc/mrbgems/README.md for more option about mrbgems.
Configuration Mrbtest build process.
If you want mrbtest.a only, You should set
conf.build_mrbtest_lib_only
ruby
conf.build_mrbtest_lib_only
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
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
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.
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.
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
.
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
“`
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| ----- ----- ------ ---- ---- ----- ----- ----
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 | | | ----- ----- ----- ---- ------ ----- | ----------------------------------------------------------------
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.
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).
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.