| load "#{MRUBY_ROOT}/tasks/mruby_build_gem.rake" |
| load "#{MRUBY_ROOT}/tasks/mruby_build_commands.rake" |
| |
| module MRuby |
| class << self |
| def targets |
| @targets ||= {} |
| end |
| |
| def each_target(&block) |
| return to_enum(:each_target) if block.nil? |
| @targets.each do |key, target| |
| target.instance_eval(&block) |
| end |
| end |
| end |
| |
| class Toolchain |
| class << self |
| attr_accessor :toolchains |
| end |
| |
| def initialize(name, &block) |
| @name, @initializer = name.to_s, block |
| MRuby::Toolchain.toolchains ||= {} |
| MRuby::Toolchain.toolchains[@name] = self |
| end |
| |
| def setup(conf,params={}) |
| conf.instance_exec(conf, params, &@initializer) |
| end |
| |
| def self.load |
| Dir.glob("#{MRUBY_ROOT}/tasks/toolchains/*.rake").each do |file| |
| Kernel.load file |
| end |
| end |
| end |
| Toolchain.load |
| |
| class Build |
| class << self |
| attr_accessor :current |
| end |
| include Rake::DSL |
| include LoadGems |
| attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir |
| attr_reader :libmruby, :gems, :toolchains |
| attr_writer :enable_bintest, :enable_test |
| |
| COMPILERS = %w(cc cxx objc asm) |
| COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc) |
| attr_block MRuby::Build::COMMANDS |
| |
| Exts = Struct.new(:object, :executable, :library) |
| |
| def initialize(name='host', build_dir=nil, &block) |
| @name = name.to_s |
| |
| unless MRuby.targets[@name] |
| if ENV['OS'] == 'Windows_NT' |
| @exts = Exts.new('.o', '.exe', '.a') |
| else |
| @exts = Exts.new('.o', '', '.a') |
| end |
| |
| build_dir = build_dir || ENV['MRUBY_BUILD_DIR'] || "#{MRUBY_ROOT}/build" |
| |
| @file_separator = '/' |
| @build_dir = "#{build_dir}/#{@name}" |
| @gem_clone_dir = "#{build_dir}/mrbgems" |
| @cc = Command::Compiler.new(self, %w(.c)) |
| @cxx = Command::Compiler.new(self, %w(.cc .cxx .cpp)) |
| @objc = Command::Compiler.new(self, %w(.m)) |
| @asm = Command::Compiler.new(self, %w(.S .asm)) |
| @linker = Command::Linker.new(self) |
| @archiver = Command::Archiver.new(self) |
| @yacc = Command::Yacc.new(self) |
| @gperf = Command::Gperf.new(self) |
| @git = Command::Git.new(self) |
| @mrbc = Command::Mrbc.new(self) |
| |
| @bins = [] |
| @gems, @libmruby = MRuby::Gem::List.new, [] |
| @build_mrbtest_lib_only = false |
| @cxx_exception_enabled = false |
| @cxx_exception_disabled = false |
| @cxx_abi_enabled = false |
| @enable_bintest = false |
| @enable_test = false |
| @toolchains = [] |
| |
| MRuby.targets[@name] = self |
| end |
| |
| MRuby::Build.current = MRuby.targets[@name] |
| MRuby.targets[@name].instance_eval(&block) |
| |
| build_mrbc_exec if name == 'host' |
| build_mrbtest if test_enabled? |
| end |
| |
| def enable_debug |
| compilers.each do |c| |
| c.defines += %w(MRB_DEBUG) |
| if toolchains.any? { |toolchain| toolchain == "gcc" } |
| c.flags += %w(-g3 -O0) |
| end |
| end |
| @mrbc.compile_options += ' -g' |
| end |
| |
| def disable_cxx_exception |
| if @cxx_exception_enabled or @cxx_abi_enabled |
| raise "cxx_exception already enabled" |
| end |
| @cxx_exception_disabled = true |
| end |
| |
| def enable_cxx_exception |
| return if @cxx_exception_enabled |
| return if @cxx_abi_enabled |
| if @cxx_exception_disabled |
| raise "cxx_exception disabled" |
| end |
| @cxx_exception_enabled = true |
| compilers.each { |c| |
| c.defines += %w(MRB_ENABLE_CXX_EXCEPTION) |
| c.flags << c.cxx_exception_flag |
| } |
| linker.command = cxx.command if toolchains.find { |v| v == 'gcc' } |
| end |
| |
| def cxx_exception_enabled? |
| @cxx_exception_enabled |
| end |
| |
| def cxx_abi_enabled? |
| @cxx_abi_enabled |
| end |
| |
| def enable_cxx_abi |
| return if @cxx_abi_enabled |
| if @cxx_exception_enabled |
| raise "cxx_exception already enabled" |
| end |
| compilers.each { |c| |
| c.defines += %w(MRB_ENABLE_CXX_EXCEPTION MRB_ENABLE_CXX_ABI) |
| c.flags << c.cxx_compile_flag |
| } |
| compilers.each { |c| c.flags << c.cxx_compile_flag } |
| linker.command = cxx.command if toolchains.find { |v| v == 'gcc' } |
| @cxx_abi_enabled = true |
| end |
| |
| def compile_as_cxx src, cxx_src, obj = nil, includes = [] |
| src = File.absolute_path src |
| cxx_src = File.absolute_path cxx_src |
| obj = objfile(cxx_src) if obj.nil? |
| |
| file cxx_src => [src, __FILE__] do |t| |
| FileUtils.mkdir_p File.dirname t.name |
| IO.write t.name, <<EOS |
| #define __STDC_CONSTANT_MACROS |
| #define __STDC_LIMIT_MACROS |
| |
| #ifndef MRB_ENABLE_CXX_ABI |
| extern "C" { |
| #endif |
| #include "#{src}" |
| #ifndef MRB_ENABLE_CXX_ABI |
| } |
| #endif |
| EOS |
| end |
| |
| file obj => cxx_src do |t| |
| cxx.run t.name, t.prerequisites.first, [], ["#{MRUBY_ROOT}/src"] + includes |
| end |
| |
| obj |
| end |
| |
| def enable_bintest |
| @enable_bintest = true |
| end |
| |
| def bintest_enabled? |
| @enable_bintest |
| end |
| |
| def toolchain(name, params={}) |
| tc = Toolchain.toolchains[name.to_s] |
| fail "Unknown #{name} toolchain" unless tc |
| tc.setup(self, params) |
| @toolchains.unshift name.to_s |
| end |
| |
| def primary_toolchain |
| @toolchains.first |
| end |
| |
| def root |
| MRUBY_ROOT |
| end |
| |
| def enable_test |
| @enable_test = true |
| end |
| |
| def test_enabled? |
| @enable_test |
| end |
| |
| def build_mrbtest |
| gem :core => 'mruby-test' |
| end |
| |
| def build_mrbc_exec |
| gem :core => 'mruby-bin-mrbc' |
| end |
| |
| def mrbcfile |
| return @mrbcfile if @mrbcfile |
| |
| mrbc_build = MRuby.targets['host'] |
| gems.each { |v| mrbc_build = self if v.name == 'mruby-bin-mrbc' } |
| @mrbcfile = mrbc_build.exefile("#{mrbc_build.build_dir}/bin/mrbc") |
| end |
| |
| def compilers |
| COMPILERS.map do |c| |
| instance_variable_get("@#{c}") |
| end |
| end |
| |
| def define_rules |
| compilers.each do |compiler| |
| if respond_to?(:enable_gems?) && enable_gems? |
| compiler.defines -= %w(DISABLE_GEMS) |
| else |
| compiler.defines += %w(DISABLE_GEMS) |
| end |
| compiler.define_rules build_dir, File.expand_path(File.join(File.dirname(__FILE__), '..')) |
| end |
| end |
| |
| def filename(name) |
| if name.is_a?(Array) |
| name.flatten.map { |n| filename(n) } |
| else |
| '"%s"' % name.gsub('/', file_separator) |
| end |
| end |
| |
| def cygwin_filename(name) |
| if name.is_a?(Array) |
| name.flatten.map { |n| cygwin_filename(n) } |
| else |
| '"%s"' % `cygpath -w "#{filename(name)}"`.strip |
| end |
| end |
| |
| def exefile(name) |
| if name.is_a?(Array) |
| name.flatten.map { |n| exefile(n) } |
| else |
| "#{name}#{exts.executable}" |
| end |
| end |
| |
| def objfile(name) |
| if name.is_a?(Array) |
| name.flatten.map { |n| objfile(n) } |
| else |
| "#{name}#{exts.object}" |
| end |
| end |
| |
| def libfile(name) |
| if name.is_a?(Array) |
| name.flatten.map { |n| libfile(n) } |
| else |
| "#{name}#{exts.library}" |
| end |
| end |
| |
| def build_mrbtest_lib_only |
| @build_mrbtest_lib_only = true |
| end |
| |
| def build_mrbtest_lib_only? |
| @build_mrbtest_lib_only |
| end |
| |
| def run_test |
| puts ">>> Test #{name} <<<" |
| mrbtest = exefile("#{build_dir}/bin/mrbtest") |
| sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}" |
| puts |
| run_bintest if bintest_enabled? |
| end |
| |
| def run_bintest |
| targets = @gems.select { |v| File.directory? "#{v.dir}/bintest" }.map { |v| filename v.dir } |
| targets << filename(".") if File.directory? "./bintest" |
| sh "ruby test/bintest.rb #{targets.join ' '}" |
| end |
| |
| def print_build_summary |
| puts "================================================" |
| puts " Config Name: #{@name}" |
| puts " Output Directory: #{self.build_dir.relative_path}" |
| puts " Binaries: #{@bins.join(', ')}" unless @bins.empty? |
| unless @gems.empty? |
| puts " Included Gems:" |
| @gems.map do |gem| |
| gem_version = " - #{gem.version}" if gem.version != '0.0.0' |
| gem_summary = " - #{gem.summary}" if gem.summary |
| puts " #{gem.name}#{gem_version}#{gem_summary}" |
| puts " - Binaries: #{gem.bins.join(', ')}" unless gem.bins.empty? |
| end |
| end |
| puts "================================================" |
| puts |
| end |
| end # Build |
| |
| class CrossBuild < Build |
| attr_block %w(test_runner) |
| # cross compiling targets for building native extensions. |
| # host - arch of where the built binary will run |
| # build - arch of the machine building the binary |
| attr_accessor :host_target, :build_target |
| |
| def initialize(name, build_dir=nil, &block) |
| @test_runner = Command::CrossTestRunner.new(self) |
| super |
| end |
| |
| def mrbcfile |
| MRuby.targets['host'].exefile("#{MRuby.targets['host'].build_dir}/bin/mrbc") |
| end |
| |
| def run_test |
| mrbtest = exefile("#{build_dir}/bin/mrbtest") |
| if (@test_runner.command == nil) |
| puts "You should run #{mrbtest} on target device." |
| puts |
| else |
| @test_runner.run(mrbtest) |
| end |
| end |
| end # CrossBuild |
| end # MRuby |