# 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 `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.