Last Modified
2019-10-01 18:00:21 -0500
Requires

Description

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) * 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)

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 ./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.

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, 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 # Searchesiconv.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 # Searchesiconv.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

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.

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.