mruby 使用 Rake 来进行编译。
你需要准备下列工具:
注意,MacOS 自带的 bison 工具对编译 mruby 来说已经太老了,你需要用 brew install bison
并把它添加到 $PATH,当然可以的话,也顺便把 ruby 更新一下吧。
非必须的工具:
如果只是要用默认配置来编译 mruby,那只要在 mruby 源代码目录下使用 rake
命令即可。如果要生成和运行测试工具,请用 rake test
;清除构建文件请用 rake clean
。要看所有的构建选项,请用 rake -v
。
上面说的是默认配置,如果你想用其它的配置文件来构建 mruby,可以用 MRUBY_CONFIG
环境变量来指定一个配置文件 (也可以用 CONFIG
),如果没有找到配置文件,就会转而使用 build_config/${MRUBY_CONFIG}.rb
作为配置文件。顺带一提,默认配置文件是 build_config/default.rb
。
显然配置文件是一个 Ruby 源代码文件。它包含了用于构建 mruby 的配置对象。
要设置编译工具链为GCC,只需在构建中编写 conf.toolchain :gcc
即可
和GCC差不多,写 conf.toolchain :clang
就行
conf.toolchain :visualcpp
conf.toolchain :android
构建 Android 平台的 mruby,你需要 Android NDK,以及 NDK 的 toolchain path 环境变量:ANDROID_STANDALONE_TOOLCHAIN
你可以设置需要构建出的mruby可执行程序,如:
这部分的设置在mrbgems部分就完成了,请参见mrbgems部分。
如果你在什么特殊的平台构建,可以自己指定文件目录分隔符,比如:
conf.file_separator = '/'
conf.cc do |cc|
cc.command = 'gcc' # 编译器命令
cc.flags = ['-D_WIN32'] # 编译器的flags
cc.include_paths = [] # 这里填入编译过程中的文件搜索目录
cc.defines = [] # 这里是预定义
cc.compile_options = [] # 这里是一些编译选项
end
conf.linker do |linker|
linker.command = ... # 链接器命令
linker.flags = ... # 链接器flags
linker.libraries = ... # 附加库名称
linker.library_paths = ... # 附加库搜索目录
linker.link_options = ... # 链接选项
end
conf.archiver do |archiver|
archiver.command = ... # 归档器命令
archiver.archive_options = ... # 归档选项
end
conf.yacc do |yacc|
yacc.command = ... # yacc命令
yacc.compile_options = ... # 编译选项
end
conf.exts do |exts|
exts.object = ... # 目标文件扩展名 (一般是 .o)
exts.executable = ... # 可执行文件扩展名
exts.library = ... # 静态库文件扩展名 (一般是 .a)
end
从 mruby3.0 起,一些 ruby symbol 将会被预先记录成 presym,从而节省运行时的 RAM 开销……当然,如果出于一些原因,你想关闭这个功能的话,可以使用 conf.disable_presym
在构建过程当中,mrbc
工具在交叉编译的环境下都会在该配置下被编译。
mruby 可以通过 mrbgem 的方式进行扩展,要启用一个指定的 gem,你可以使用 conf.gem
启用一个已经集成在源码目录下的gem:
conf.gem :core => 'mruby-something'
启用一个在github上托管的gem:
conf.gem :github => 'someone/mruby-another'
启用一个binary gem(往往会产出一个可执行文件):
conf.gem :core => 'mruby-bin-mruby'
启用一个GemBox(若干Gems组成的集合):
conf.gembox "default"
GemBox就是一组Gems组成的集合配置文件,参见 mrbgems/default.gembox
如果你安装了cruby,你可以安装一个叫做mgem的RubyGem,它可以提供给你一个已经注册过的mrbgems列表。
可以用 conf.build_mrbtest_lib_only
使得构建过程只产出 mrbtest.a
用cruby测试mrbgems所产出的可执行文件
这部分内容可以看看mrbgems目录下的 mruby-bin-*/bintest/*.rb
conf.enable_bintest
一般情况下,mruby 使用 sjlj(setjmp/longjmp) 来实现异常处理。不过在 C++ 环境下,这个做法就没有办法正常地释放栈对象了,为了支持使用 C++ 编写的 mrbgems,mruby 可以使用 C++ 的异常处理来避免这个情况。
关于这方面的配置,有两个等级可以选择。conf.enable_cxx_exception
可以启用 C++ 异常来代替 sjlj,不过仍使用 C ABI。另一个就是 conf.enable_cxx_abi
,如果启用它,那么所有文件都会用C++编译器来进行编译。
如果你的编译器不支持 C++,你也确定不会使用一些由 C++ 编写成的 mrbgems,那就可以禁用 C++ 异常,使用 conf.disable_cxx_exception
就可以了
如果你这么做了,但还是启用了包含 C++ 的 mrbgems,那么就会收到报错
conf.enable_debug
可以打开调试
调试模式开启时:
MRB_DEBUG
会被添加到编译器宏定义,意味着 mrb_assert (...)
也会启用mrbc
生成的代码将会包含调试信息,这样就可以获得更清晰的 backtrace 信息mruby 支持从当前平台交叉编译到另一个平台。要准备交叉编译,你的配置文件中需要有一个交叉编译的配置对象 (MRuby::CrossBuild 的实例),比如:
MRuby::CrossBuild.new ('32bit') do |conf|
conf.toolchain :gcc
conf.cc.flags = ['-m32']
conf.linker.flags = ['-m32']
end
任何用在 MRuby::Build 中的配置选项都可以用于 CrossBuild 当中,参见 build_config 目录来获取示例
构建前,mruby 源码根目录将会创建一个 build 目录,整个构建过程中产生的文件都会位于该目录下。它的结构看起来像这样:
+- build
***|
***+- host
*******|
*******+- bin <- 可执行程序 (mirb mrbc mruby)
*******|
*******+- lib <- 静态库 (libmruby.a libmruby_core.a)
*******|
*******+- mrblib
*******|
*******+- src
*******|
*******+- test <- mrbtest 工具
*******|
*******+- tools
**********|
**********+- mirb
**********|
**********+- mrbc
**********|
**********+- mruby
编译工作流如下:
编译所有 src 目录下的源代码 (编译产物存放在 build/host/src)
生成 parser 语法文件 (生成结果存放在 build/host/src/y.tab.c)
编译上一步的产物 y.tab.c
将这时所有的编译产物归档为 libmruby_core.a,存放在 build/host/lib 下
编译 tools/mrbc/mrbc.c,并和上面的静态库链接成 mrbc 工具存放在 build/host/bin 下
用上一步生成的 mrbc 工具编译 mrblib 下所有的 *.rb 文件,生成为 build/host/mrblib/mrblib.c
编译上一步的产物 mrblib.c
将这时所有的编译产物归档为 libmruby.a,存放在 build/host/lib 下
将 mrbgems/mruby-bin-mruby/tools/mruby/mruby.c 编译,并和上面的静态库链接成 mruby 工具存放在 build/host/bin 下
和上面类似,产出 mirb 程序
假设我们建立了一个叫作 i386
的交叉编译配置,那么 build 目录看起来像这样:
+- build
***|
***+- host
*******|
*******+- bin <- 本地平台的 可执行程序 (mirb mrbc mruby)
*******|
*******+- lib <- 本地平台的 静态库 (libmruby.a libmruby_core.a)
*******|
*******+- mrblib
*******|
*******+- src
*******|
*******+- test <- 本地平台的 mrbtest 工具
*******|
*******+- tools
**********|
**********+- mirb
**********|
**********+- mrbc
**********|
**********+- mruby
***+- i386
*******|
*******+- bin <- i386 平台的 可执行程序 (mirb mrbc mruby)
*******|
*******+- lib <- i386 平台的 静态库 (libmruby.a libmruby_core.a)
*******|
*******+- mrblib
*******|
*******+- src
*******|
*******+- test <- i386 平台的 mrbtest 工具
*******|
*******+- tools
**********|
**********+- mirb
**********|
**********+- mrbc
**********|
**********+- mruby
可以看到,除了 host 外,又多出了为交叉编译而创建的目录。
交叉编译的工作流一开始和普通编译并无不同,在本地平台的构建完成后,交叉编译的流程如下:
交叉编译所有 src 目录下的源代码 (编译产物存放在 build/i386/src)
生成 parser 语法文件 (生成结果存放在 build/i386/src/y.tab.c)
交叉编译上一步的产物 y.tab.c
用 mrbc 工具编译 mrblib 下所有的 *.rb 文件,生成为 build/i386/mrblib/mrblib.c
交叉编译上一步的产物 mrblib.c
将这时所有的编译产物归档为 libmruby.a,存放在 build/i386/lib 下
将 mrbgems/mruby-bin-mruby/tools/mruby/mruby.c 编译,并和上面的静态库链接成 mruby 工具存放在 build/i386/bin 下
和上面类似,产出 mirb 程序
将这时的 C 源码编译产物归档为 libmruby_core.a,存放在 build/i386/lib 下
交叉编译 tools/mrbc/mrbc.c,并和上面的静态库链接成 mrbc 工具存放在 build/i386/bin 下
要构建一个最小配置的 mruby,你可以建立一个 CrossBuild,编写如下:
MRuby::CrossBuild.new ('Minimal') do |conf|
toolchain :gcc
conf.cc.defines = % w (MRB_NO_STDIO)
conf.bins = []
end
这个构建禁用所有 stdio 相关的功能,且不会产出可执行程序
构建过程完成后,你就可以获得一个 libmruby.a
,你可以将它链接到你的应用程序当中。
你可以用 mruby-config 获取链接它所需要的配置清单。