1 require "mruby-core-ext"
2 require "mruby/build/load_gems"
3 require "mruby/build/command"
6 autoload :Gem, "mruby/gem"
7 autoload :Lockfile, "mruby/lockfile"
14 def each_target(&block)
15 return to_enum(:each_target) if block.nil?
16 @targets.each do |key, target|
17 target.instance_eval(&block)
24 attr_accessor :toolchains
27 def initialize(name, &block)
28 @name, @initializer = name.to_s, block
29 MRuby::Toolchain.toolchains[@name] = self
32 def setup(conf,params={})
33 conf.instance_exec(conf, params, &@initializer)
41 attr_accessor :current
45 attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir
46 attr_reader :libmruby_objs, :gems, :toolchains, :gem_dir_to_repo_url
47 attr_writer :enable_bintest, :enable_test
49 alias libmruby libmruby_objs
51 COMPILERS = %w(cc cxx objc asm)
52 COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc)
53 attr_block MRuby::Build::COMMANDS
55 Exts = Struct.new(:object, :executable, :library)
57 def initialize(name='host', build_dir=nil, &block)
60 unless MRuby.targets[@name]
61 if ENV['OS'] == 'Windows_NT'
62 @exts = Exts.new('.o', '.exe', '.a')
64 @exts = Exts.new('.o', '', '.a')
67 build_dir = build_dir || ENV['MRUBY_BUILD_DIR'] || "#{MRUBY_ROOT}/build"
70 @build_dir = "#{build_dir}/#{@name}"
71 @gem_clone_dir = "#{build_dir}/repos/#{@name}"
72 @cc = Command::Compiler.new(self, %w(.c))
73 @cxx = Command::Compiler.new(self, %w(.cc .cxx .cpp))
74 @objc = Command::Compiler.new(self, %w(.m))
75 @asm = Command::Compiler.new(self, %w(.S .asm))
76 @linker = Command::Linker.new(self)
77 @archiver = Command::Archiver.new(self)
78 @yacc = Command::Yacc.new(self)
79 @gperf = Command::Gperf.new(self)
80 @git = Command::Git.new(self)
81 @mrbc = Command::Mrbc.new(self)
84 @gems, @libmruby_objs = MRuby::Gem::List.new, []
85 @build_mrbtest_lib_only = false
86 @cxx_exception_enabled = false
87 @cxx_exception_disabled = false
88 @cxx_abi_enabled = false
89 @enable_bintest = false
93 @gem_dir_to_repo_url = {}
95 MRuby.targets[@name] = self
98 MRuby::Build.current = MRuby.targets[@name]
99 MRuby.targets[@name].instance_eval(&block)
101 build_mrbc_exec if name == 'host'
102 build_mrbtest if test_enabled?
110 compilers.each do |c|
111 c.defines += %w(MRB_DEBUG)
112 if toolchains.any? { |toolchain| toolchain == "gcc" }
113 c.flags += %w(-g3 -O0)
116 @mrbc.compile_options += ' -g'
126 Lockfile.enabled? && @enable_lock
129 def disable_cxx_exception
130 if @cxx_exception_enabled or @cxx_abi_enabled
131 raise "cxx_exception already enabled"
133 @cxx_exception_disabled = true
136 def enable_cxx_exception
137 return if @cxx_exception_enabled
138 return if @cxx_abi_enabled
139 if @cxx_exception_disabled
140 raise "cxx_exception disabled"
142 @cxx_exception_enabled = true
144 c.defines += %w(MRB_ENABLE_CXX_EXCEPTION)
145 c.flags << c.cxx_exception_flag
147 linker.command = cxx.command if toolchains.find { |v| v == 'gcc' }
150 def cxx_exception_enabled?
151 @cxx_exception_enabled
159 return if @cxx_abi_enabled
160 if @cxx_exception_enabled
161 raise "cxx_exception already enabled"
164 c.defines += %w(MRB_ENABLE_CXX_EXCEPTION MRB_ENABLE_CXX_ABI)
165 c.flags << c.cxx_compile_flag
166 c.flags = c.flags.flatten - c.cxx_invalid_flags.flatten
168 linker.command = cxx.command if toolchains.find { |v| v == 'gcc' }
169 @cxx_abi_enabled = true
172 def compile_as_cxx src, cxx_src, obj = nil, includes = []
173 obj = objfile(cxx_src) if obj.nil?
175 file cxx_src => [src, __FILE__] do |t|
176 mkdir_p File.dirname t.name
177 IO.write t.name, <<EOS
178 #define __STDC_CONSTANT_MACROS
179 #define __STDC_LIMIT_MACROS
181 #ifndef MRB_ENABLE_CXX_ABI
184 #include "#{File.absolute_path src}"
185 #ifndef MRB_ENABLE_CXX_ABI
191 file obj => cxx_src do |t|
192 cxx.run t.name, t.prerequisites.first, [], ["#{MRUBY_ROOT}/src"] + includes
199 @enable_bintest = true
206 def toolchain(name, params={})
208 tc = Toolchain.toolchains[name] || begin
209 path = "#{MRUBY_ROOT}/tasks/toolchains/#{name}.rake"
210 fail "Unknown #{name} toolchain" unless File.exist?(path)
212 Toolchain.toolchains[name]
214 tc.setup(self, params)
215 @toolchains.unshift name
218 def primary_toolchain
235 gem :core => 'mruby-test'
239 gem :core => 'mruby-bin-mrbc'
243 Lockfile.build(@name)
247 return @mrbcfile if @mrbcfile
249 mrbc_build = MRuby.targets['host']
250 gems.each { |v| mrbc_build = self if v.name == 'mruby-bin-mrbc' }
251 @mrbcfile = mrbc_build.exefile("#{mrbc_build.build_dir}/bin/mrbc")
256 instance_variable_get("@#{c}")
261 compilers.each do |compiler|
262 if respond_to?(:enable_gems?) && enable_gems?
263 compiler.defines -= %w(DISABLE_GEMS)
265 compiler.defines += %w(DISABLE_GEMS)
267 compiler.define_rules build_dir, File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
273 name.flatten.map { |n| filename(n) }
275 name.gsub('/', file_separator)
281 name.flatten.map { |n| exefile(n) }
282 elsif File.extname(name).empty?
283 "#{name}#{exts.executable}"
285 # `name` sometimes have (non-standard) extension (e.g. `.bat`).
292 name.flatten.map { |n| objfile(n) }
294 "#{name}#{exts.object}"
300 name.flatten.map { |n| libfile(n) }
302 "#{name}#{exts.library}"
306 def build_mrbtest_lib_only
307 @build_mrbtest_lib_only = true
310 def build_mrbtest_lib_only?
311 @build_mrbtest_lib_only
315 Rake.verbose ? ' -v' : ''
319 puts ">>> Test #{name} <<<"
320 mrbtest = exefile("#{build_dir}/bin/mrbtest")
321 sh "#{filename mrbtest.relative_path}#{verbose_flag}"
326 puts ">>> Bintest #{name} <<<"
327 targets = @gems.select { |v| File.directory? "#{v.dir}/bintest" }.map { |v| filename v.dir }
328 targets << filename(".") if File.directory? "./bintest"
329 sh "ruby test/bintest.rb#{verbose_flag} #{targets.join ' '}"
332 def print_build_summary
333 puts "================================================"
334 puts " Config Name: #{@name}"
335 puts " Output Directory: #{self.build_dir.relative_path}"
336 puts " Binaries: #{@bins.join(', ')}" unless @bins.empty?
338 puts " Included Gems:"
339 gems = @gems.sort_by { |gem| gem.name }
341 gem_version = " - #{gem.version}" if gem.version != '0.0.0'
342 gem_summary = " - #{gem.summary}" if gem.summary
343 puts " #{gem.name}#{gem_version}#{gem_summary}"
344 puts " - Binaries: #{gem.bins.join(', ')}" unless gem.bins.empty?
347 puts "================================================"
352 libfile("#{build_dir}/lib/libmruby")
355 def libmruby_core_static
356 libfile("#{build_dir}/lib/libmruby_core")
364 class CrossBuild < Build
365 attr_block %w(test_runner)
366 # cross compiling targets for building native extensions.
367 # host - arch of where the built binary will run
368 # build - arch of the machine building the binary
369 attr_accessor :host_target, :build_target
371 def initialize(name, build_dir=nil, &block)
373 @test_runner = Command::CrossTestRunner.new(self)
378 MRuby.targets['host'].exefile("#{MRuby.targets['host'].build_dir}/bin/mrbc")
382 @test_runner.runner_options << verbose_flag
383 mrbtest = exefile("#{build_dir}/bin/mrbtest")
384 if (@test_runner.command == nil)
385 puts "You should run #{mrbtest} on target device."
388 @test_runner.run(mrbtest)