diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2013-01-20 14:41:50 -0800 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2013-01-20 14:41:50 -0800 |
| commit | 8e86ff2283d427b5cb2a02607e1aab998cb5090c (patch) | |
| tree | bd40d166673b2290053f1742660d573d5586a974 | |
| parent | cc16bd7c0d70b326ddcf8de8a511116dae9fc30d (diff) | |
| parent | ced80d2b4b1ed4ef0752a8bbaf0dbfe7aa6c6a95 (diff) | |
| download | mruby-8e86ff2283d427b5cb2a02607e1aab998cb5090c.tar.gz mruby-8e86ff2283d427b5cb2a02607e1aab998cb5090c.zip | |
Merge pull request #755 from masuidrive/imprive_build_scripts
Improved build scripts and config files
| -rw-r--r-- | Rakefile | 19 | ||||
| -rw-r--r-- | build_config.rb | 113 | ||||
| -rw-r--r-- | doc/mrbgems/c_and_ruby_extension_example/mrbgem.rake | 21 | ||||
| -rw-r--r-- | doc/mrbgems/c_extension_example/mrbgem.rake | 19 | ||||
| -rw-r--r-- | doc/mrbgems/ruby_extension_example/mrbgem.rake | 21 | ||||
| -rw-r--r-- | include/mrbconf.h | 1 | ||||
| -rw-r--r-- | mrblib/mrblib.rake | 11 | ||||
| -rw-r--r-- | src/mruby_core.rake | 18 | ||||
| -rw-r--r-- | tasks/libmruby.rake | 4 | ||||
| -rw-r--r-- | tasks/mrbgem_spec.rake | 139 | ||||
| -rw-r--r-- | tasks/mrbgems.rake | 53 | ||||
| -rw-r--r-- | tasks/mrbgems_test.rake | 20 | ||||
| -rw-r--r-- | tasks/mruby_build.rake | 239 | ||||
| -rw-r--r-- | tasks/mruby_build_commands.rake | 198 | ||||
| -rw-r--r-- | tasks/mruby_build_gem.rake | 39 | ||||
| -rw-r--r-- | tasks/mruby_gem_spec.rake | 160 | ||||
| -rw-r--r-- | tasks/ruby_ext.rake | 43 | ||||
| -rw-r--r-- | tasks/rules.rake | 43 | ||||
| -rw-r--r-- | tasks/toolchains/clang.rake | 6 | ||||
| -rw-r--r-- | tasks/toolchains/gcc.rake | 21 | ||||
| -rw-r--r-- | tasks/toolchains/vs2012.rake | 44 | ||||
| -rw-r--r-- | test/mrbtest.rake | 27 | ||||
| -rw-r--r-- | tools/mirb/mirb.rake | 15 | ||||
| -rw-r--r-- | tools/mrbc/mrbc.rake | 12 | ||||
| -rw-r--r-- | tools/mruby/mruby.rake | 15 |
25 files changed, 786 insertions, 515 deletions
@@ -4,14 +4,13 @@ load 'tasks/ruby_ext.rake' load 'tasks/mruby_build.rake' -load 'tasks/mruby_gem_spec.rake' +load 'tasks/mrbgem_spec.rake' ############################## # compile flags MRUBY_CONFIG = File.expand_path(ENV['MRUBY_CONFIG'] || './build_config.rb') load MRUBY_CONFIG -load 'tasks/rules.rake' load 'src/mruby_core.rake' load 'mrblib/mrblib.rake' load 'tools/mrbc/mrbc.rake' @@ -29,27 +28,26 @@ load 'test/mrbtest.rake' task :default => :all depfiles = MRuby.targets['host'].bins.map do |bin| - install_path = exefile("bin/#{bin}") + install_path = MRuby.targets['host'].exefile("bin/#{bin}") - file install_path => exefile("build/host/bin/#{bin}") do |t| + file install_path => MRuby.targets['host'].exefile("build/host/bin/#{bin}") do |t| FileUtils.cp t.prerequisites.first, t.name end install_path end -depfiles += MRuby.targets.reject {|n,t| n == 'host' }.map { |n, t| - ["#{t.build_dir}/lib/libmruby.a"] + t.bins.map { |bin| exefile("#{t.build_dir}/bin/#{bin}") } +depfiles += MRuby.targets.reject { |n, t| n == 'host' }.map { |n, t| + [t.libfile("#{t.build_dir}/lib/libmruby")] + t.bins.map { |bin| t.exefile("#{t.build_dir}/bin/#{bin}") } }.flatten desc "build all targets, install (locally) in-repo" task :all => depfiles desc "run all mruby tests" -task :test => MRuby.targets.values.map { |t| exefile("#{t.build_dir}/test/mrbtest") } do - sh "#{filename exefile('build/host/test/mrbtest')}" - if MRuby.targets.count > 1 - puts "\nYou should run #{MRuby.targets.map{ |t| t.name == 'host' ? nil : "#{t.build_dir}/test/mrbtest" }.compact.join(', ')} on target device." +task :test => MRuby.targets.values.map { |t| t.exefile("#{t.build_dir}/test/mrbtest") } do + MRuby.each_target do + run_test end end @@ -59,4 +57,5 @@ task :clean do FileUtils.rm_rf t.build_dir end FileUtils.rm_f depfiles + puts "Cleaned up build folder" end diff --git a/build_config.rb b/build_config.rb index 4e80a2596..1c177fdac 100644 --- a/build_config.rb +++ b/build_config.rb @@ -1,55 +1,76 @@ MRuby::Build.new do |conf| - conf.cc = ENV['CC'] || 'gcc' - conf.ld = ENV['LD'] || 'gcc' - conf.ar = ENV['AR'] || 'ar' - # conf.bins = %w(mrbc mruby mirb) - # conf.cxx = conf.cc - # conf.objcc = conf.cc - # conf.asm = conf.cc - # conf.yacc = 'bison' - # conf.gperf = 'gperf' - # conf.cat = 'cat' - # conf.git = 'git' - - conf.cflags << (ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration)) - conf.ldflags << (ENV['LDFLAGS'] || %w(-lm)) - # conf.cxxflags = [] - # conf.objccflags = [] - # conf.asmflags = [] + # load specific toolchain settings + toolchain :gcc + # Use mrbgems # conf.gem 'doc/mrbgems/ruby_extension_example' - # conf.gem 'doc/mrbgems/c_extension_example' + # conf.gem 'doc/mrbgems/c_extension_example' do |g| + # g.cc.flags << '-g' # append cflags in this gem + # end # conf.gem 'doc/mrbgems/c_and_ruby_extension_example' - # conf.gem :git => '[email protected]:masuidrive/mrbgems-example.git', :branch => 'master' -end + # conf.gem :github => 'masuidrive/mrbgems-example', :branch => 'master' + # conf.gem :git => '[email protected]:masuidrive/mrbgems-example.git', :branch => 'master', :options => '-v' -=begin -MRuby::CrossBuild.new('i386') do |conf| - conf.cc = ENV['CC'] || 'gcc' - conf.ld = ENV['LD'] || 'gcc' - conf.ar = ENV['AR'] || 'ar' + # Generate binaries # conf.bins = %w(mrbc mruby mirb) - # conf.cxx = 'gcc' - # conf.objcc = 'gcc' - # conf.asm = 'gcc' - # conf.yacc = 'bison' - # conf.gperf = 'gperf' - # conf.cat = 'cat' - # conf.git = 'git' + + # C compiler settings + # conf.cc do |cc| + # cc.command = ENV['CC'] || 'gcc' + # cc.flags = [ENV['CFLAGS'] || %w()] + # cc.include_paths = ["#{root}/include"] + # cc.defines = %w(DISABLE_GEMS) + # cc.option_include_path = '-I%s' + # cc.option_define = '-D%s' + # cc.compile_options = "%{flags} -MMD -o %{outfile} -c %{infile}" + # end - if ENV['OS'] == 'Windows_NT' # MinGW - conf.cflags = %w(-g -O3 -Wall -Werror-implicit-function-declaration -Di386_MARK) - conf.ldflags = %w(-s -static) - else - conf.cflags << %w(-g -O3 -Wall -Werror-implicit-function-declaration -arch i386) - conf.ldflags << %w(-arch i386) - end - # conf.cxxflags << [] - # conf.objccflags << [] - # conf.asmflags << [] + # Linker settings + # conf.linker do |linker| + # linker.command = ENV['LD'] || 'gcc' + # linker.flags = [ENV['LDFLAGS'] || []] + # linker.libraries = %w() + # linker.library_paths = [] + # linker.option_library = '-l%s' + # linker.option_library_path = '-L%s' + # linker.link_options = "%{flags} -o %{outfile} %{objs} %{libs}" + # end + + # Archiver settings + # conf.archiver do |archiver| + # archiver.command = ENV['AR'] || 'ar' + # archiver.archive_options = 'rs %{outfile} %{objs}' + # end + + # Parser generator settings + # conf.yacc do |yacc| + # yacc.command = ENV['YACC'] || 'bison' + # yacc.compile_options = '-o %{outfile} %{infile}' + # end + + # gperf settings + # conf.gperf do |gperf| + # gperf.command = 'gperf' + # gperf.compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}' + # end + + # file extensions + # conf.exts do |exts| + # exts.object = '.o' + # exts.executable = '' # '.exe' if Windows + # exts.library = '.a' + # end - # conf.gem 'doc/mrbgems/ruby_extension_example' - # conf.gem 'doc/mrbgems/c_extension_example' - # conf.gem 'doc/mrbgems/c_and_ruby_extension_example' + # file separetor + # conf.file_separator = '/' end -=end
\ No newline at end of file + +# Define cross build settings +# MRuby::CrossBuild.new('32bit') do |conf| +# toolchain :gcc +# +# conf.cc.flags << "-m32" +# conf.linker.flags << "-m32" +# +# conf.gem 'doc/mrbgems/c_and_ruby_extension_example' +# end diff --git a/doc/mrbgems/c_and_ruby_extension_example/mrbgem.rake b/doc/mrbgems/c_and_ruby_extension_example/mrbgem.rake index 9309436aa..64fa1972f 100644 --- a/doc/mrbgems/c_and_ruby_extension_example/mrbgem.rake +++ b/doc/mrbgems/c_and_ruby_extension_example/mrbgem.rake @@ -2,16 +2,19 @@ MRuby::Gem::Specification.new('c_and_ruby_extension_example') do |spec| spec.license = 'MIT' spec.authors = 'mruby developers' - # spec.cflags = '' - - # spec.mruby_cflags = '' - # spec.mruby_ldflags = '' - # spec.mruby_libs = '' - # spec.mruby_includes = ["#{spec.dir}/include"] - + # Add compile flags + # spec.cc.flags << '' + + # Add cflags to all + # spec.mruby.cc.flags << '-g' + + # Add libraries + # spec.linker.libraries << 'external_lib' + + # Default building fules # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") - # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") - # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } # spec.test_preload = 'test/assert.rb' end diff --git a/doc/mrbgems/c_extension_example/mrbgem.rake b/doc/mrbgems/c_extension_example/mrbgem.rake index 289f87d7f..6bcb6e105 100644 --- a/doc/mrbgems/c_extension_example/mrbgem.rake +++ b/doc/mrbgems/c_extension_example/mrbgem.rake @@ -2,16 +2,19 @@ MRuby::Gem::Specification.new('c_extension_example') do |spec| spec.license = 'MIT' spec.authors = 'mruby developers' - # spec.cflags = '' - - # spec.mruby_cflags = '' - # spec.mruby_ldflags = '' - # spec.mruby_libs = '' - # spec.mruby_includes = ["#{spec.dir}/include"] + # Add compile flags + # spec.cc.flags << '-g' + + # Add cflags to all + # spec.mruby.cc.flags << '-g' + + # Add libraries + # spec.linker.libraries << 'external_lib' + # Default building fules # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") - # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") - # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } # spec.test_preload = 'test/assert.rb' end diff --git a/doc/mrbgems/ruby_extension_example/mrbgem.rake b/doc/mrbgems/ruby_extension_example/mrbgem.rake index 80a299187..0a1e62b1c 100644 --- a/doc/mrbgems/ruby_extension_example/mrbgem.rake +++ b/doc/mrbgems/ruby_extension_example/mrbgem.rake @@ -2,16 +2,19 @@ MRuby::Gem::Specification.new('ruby_extension_example') do |spec| spec.license = 'MIT' spec.authors = 'mruby developers' - # spec.cflags = '' - - # spec.mruby_cflags = '' - # spec.mruby_ldflags = '' - # spec.mruby_libs = '' - # spec.mruby_includes = ["#{spec.dir}/include"] - + # Add compile flags + # spec.cc.flags << '' + + # Add cflags to all + # spec.mruby.cc.flags << '-g' + + # Add libraries + # spec.linker.libraries << 'external_lib' + + # Default building fules # spec.rbfiles = Dir.glob("#{dir}/mrblib/*.rb") - # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } # spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb") - # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") } + # spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).pathmap("#{build_dir}/%X")) } # spec.test_preload = 'test/assert.rb' end diff --git a/include/mrbconf.h b/include/mrbconf.h index 80c8bd6fa..066c040f6 100644 --- a/include/mrbconf.h +++ b/include/mrbconf.h @@ -125,6 +125,7 @@ typedef short mrb_sym; #endif #ifdef _MSC_VER +# include <float.h> # define inline __inline # define snprintf _snprintf # define isnan _isnan diff --git a/mrblib/mrblib.rake b/mrblib/mrblib.rake index 5dab4cee9..493207db4 100644 --- a/mrblib/mrblib.rake +++ b/mrblib/mrblib.rake @@ -1,15 +1,14 @@ -dir = File.dirname(__FILE__).sub(%r|^\./|, '') - MRuby.each_target do - self.libmruby << "#{build_dir}/#{dir}/mrblib.o" + dir = File.dirname(__FILE__).relative_path_from(root) + self.libmruby << objfile("#{build_dir}/#{dir}/mrblib") - file "#{build_dir}/#{dir}/mrblib.o" => "#{build_dir}/#{dir}/mrblib.c" + file objfile("#{build_dir}/#{dir}/mrblib") => "#{build_dir}/#{dir}/mrblib.c" file "#{build_dir}/#{dir}/mrblib.c" => [mrbcfile] + Dir.glob("#{dir}/*.rb") do |t| - mrbc, *rbfiles = t.prerequisites + mrbc_, *rbfiles = t.prerequisites FileUtils.mkdir_p File.dirname(t.name) open(t.name, 'w') do |f| f.puts File.read("#{dir}/init_mrblib.c") - compile_mruby f, rbfiles, 'mrblib_irep' + mrbc.run f, rbfiles, 'mrblib_irep' end end end diff --git a/src/mruby_core.rake b/src/mruby_core.rake index 7db1dbf77..44d62c1e9 100644 --- a/src/mruby_core.rake +++ b/src/mruby_core.rake @@ -1,25 +1,25 @@ -dir = File.dirname(__FILE__).sub(%r|^\./|, '') - MRuby.each_target do + dir = File.dirname(__FILE__).relative_path_from(root) + lex_def = "#{dir}/lex.def" - objs = Dir.glob("src/*.{c}").map { |f| f.pathmap("#{build_dir}/%X.o") } + ["#{build_dir}/#{dir}/y.tab.o"] + objs = Dir.glob("src/*.{c}").map { |f| objfile(f.pathmap("#{build_dir}/%X")) } + [objfile("#{build_dir}/#{dir}/y.tab")] self.libmruby << objs - file "#{build_dir}/lib/libmruby_core.a" => objs do |t| - archive t.name, 'rs', t.prerequisites + file libfile("#{build_dir}/lib/libmruby_core") => objs do |t| + archiver.run t.name, t.prerequisites end # Parser file "#{build_dir}/#{dir}/y.tab.c" => ["#{dir}/parse.y"] do |t| - run_yacc t.name, t.prerequisites.first + yacc.run t.name, t.prerequisites.first end - file "#{build_dir}/#{dir}/y.tab.o" => ["#{build_dir}/#{dir}/y.tab.c", lex_def] do |t| - compile_c t.name, t.prerequisites.first, [], dir + file objfile("#{build_dir}/#{dir}/y.tab") => ["#{build_dir}/#{dir}/y.tab.c", lex_def] do |t| + cc.run t.name, t.prerequisites.first, [], [dir] end # Lexical analyzer file lex_def => "#{dir}/keywords" do |t| - run_gperf t.name, t.prerequisites.first + gperf.run t.name, t.prerequisites.first end end diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake index 9f5cc555a..c3b9d714f 100644 --- a/tasks/libmruby.rake +++ b/tasks/libmruby.rake @@ -1,5 +1,5 @@ MRuby.each_target do - file "#{build_dir}/lib/libmruby.a" => libmruby.flatten do |t| - archive t.name, 'rs', t.prerequisites + file libfile("#{build_dir}/lib/libmruby") => libmruby.flatten do |t| + archiver.run t.name, t.prerequisites end end diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake new file mode 100644 index 000000000..e21e0b670 --- /dev/null +++ b/tasks/mrbgem_spec.rake @@ -0,0 +1,139 @@ +require 'pathname' +require 'forwardable' + +module MRuby + module Gem + class << self + attr_accessor :current + end + LinkerConfig = Struct.new(:libraries, :library_paths, :flags) + + class Specification + include Rake::DSL + extend Forwardable + def_delegators :@build, :filename, :objfile, :libfile, :exefile + + attr_accessor :name, :dir, :build + alias mruby build + attr_accessor :build_config_initializer + + attr_accessor :licenses, :authors + alias :license= :licenses= + alias :author= :authors= + + attr_accessor :rbfiles, :objs + attr_accessor :test_objs, :test_rbfiles + attr_accessor :test_preload + + attr_block MRuby::Build::COMMANDS + + def initialize(name, &block) + @name = name + @initializer = block + MRuby::Gem.current = self + end + + def setup + MRuby::Gem.current = self + MRuby::Build::COMMANDS.each do |command| + instance_variable_set("@#{command}", @build.send(command).clone) + end + @linker = LinkerConfig.new([], [], []) + + compilers.each do |compiler| + compiler.defines -= %w(DISABLE_GEMS) + compiler.include_paths << "#{dir}/include" + end + + @rbfiles = Dir.glob("#{dir}/mrblib/*.rb") + @objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X")) } + @objs << objfile("#{build_dir}/gem_init") + + @test_rbfiles = Dir.glob("#{dir}/test/*.rb") + @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) } + @test_preload = 'test/assert.rb' + + instance_eval(&@initializer) + + if !name || !licenses || !authors + fail "#{name || dir} required to set name, license(s) and author(s)" + end + + build.libmruby << @objs + + instance_eval(&@build_config_initializer) if @build_config_initializer + + compilers.each do |compiler| + compiler.define_rules build_dir, "#{dir}/" + end + + define_gem_init_builder + end + + def build_dir + "#{build.build_dir}/mrbgems/#{name}" + end + + def testlib + libfile("#{build_dir}/libmrb-#{name}-gem-test") + end + + def funcname + @funcname ||= @name.gsub('-', '_') + end + + def compilers + MRuby::Build::COMPILERS.map do |c| + instance_variable_get("@#{c}") + end + end + + def define_gem_init_builder + file objfile("#{build_dir}/gem_init") => "#{build_dir}/gem_init.c" + file "#{build_dir}/gem_init.c" => [build.mrbcfile] + rbfiles do |t| + FileUtils.mkdir_p build_dir + generate_gem_init("#{build_dir}/gem_init.c") + end + end + + def generate_gem_init(fname) + open(fname, 'w') do |f| + print_gem_init_header f + build.mrbc.run f, rbfiles, "gem_mrblib_irep_#{funcname}" unless rbfiles.empty? + f.puts %Q[void mrb_#{funcname}_gem_init(mrb_state *mrb);] + f.puts %Q[void GENERATED_TMP_mrb_#{funcname}_gem_init(mrb_state *mrb) {] + f.puts %Q[ int ai = mrb_gc_arena_save(mrb);] + f.puts %Q[ mrb_#{funcname}_gem_init(mrb);] if objs != [objfile("#{build_dir}/gem_init")] + unless rbfiles.empty? + f.puts %Q[ mrb_load_irep(mrb, gem_mrblib_irep_#{funcname});] + f.puts %Q[ if (mrb->exc) {] + f.puts %Q[ mrb_p(mrb, mrb_obj_value(mrb->exc));] + f.puts %Q[ exit(0);] + f.puts %Q[ }] + end + f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] + f.puts %Q[}] + end + end # generate_gem_init + + def print_gem_init_header(f) + f.puts %Q[/*] + f.puts %Q[ * This file is loading the irep] + f.puts %Q[ * Ruby GEM code.] + f.puts %Q[ *] + f.puts %Q[ * IMPORTANT:] + f.puts %Q[ * This file was generated!] + f.puts %Q[ * All manual changes will get lost.] + f.puts %Q[ */] + f.puts %Q[#include "mruby.h"] + f.puts %Q[#include "mruby/irep.h"] + f.puts %Q[#include "mruby/dump.h"] + f.puts %Q[#include "mruby/string.h"] + f.puts %Q[#include "mruby/proc.h"] + f.puts %Q[#include "mruby/variable.h"] + f.puts %Q[#include "mruby/array.h"] + end + + end # Specification + end # Gem +end # MRuby diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index 07e412b53..dc5e67eef 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -1,35 +1,34 @@ -dir = File.dirname(__FILE__).sub(%r|^\./|, '') - MRuby.each_target do - if enable_gems? - self.libmruby << "#{build_dir}/mrbgems/gem_init.o" + dir = File.dirname(__FILE__).relative_path_from(root) - file "#{build_dir}/mrbgems/gem_init.o" => "#{build_dir}/mrbgems/gem_init.c" - file "#{build_dir}/mrbgems/gem_init.c" do |t| + if enable_gems? + # set up all gems + gems.each(&:setup) + + # loader all gems + self.libmruby << objfile("#{build_dir}/mrbgems/gem_init") + file objfile("#{build_dir}/mrbgems/gem_init") => "#{build_dir}/mrbgems/gem_init.c" + file "#{build_dir}/mrbgems/gem_init.c" => [MRUBY_CONFIG] do |t| FileUtils.mkdir_p "#{build_dir}/mrbgems" open(t.name, 'w') do |f| - f.puts <<__EOF__ -/* - * This file contains a list of all - * initializing methods which are - * necessary to bootstrap all gems. - * - * IMPORTANT: - * This file was generated! - * All manual changes will get lost. - */ - -#include "mruby.h" - -#{gems.map{|gem| "void GENERATED_TMP_mrb_%s_gem_init(mrb_state* mrb);" % [gem.funcname]}.join("\n")} -void -mrb_init_mrbgems(mrb_state *mrb) { -#{gems.map{|gem| "GENERATED_TMP_mrb_%s_gem_init(mrb);" % [gem.funcname]}.join("\n")} -} -__EOF__ + f.puts %Q[/*] + f.puts %Q[ * This file contains a list of all] + f.puts %Q[ * initializing methods which are] + f.puts %Q[ * necessary to bootstrap all gems.] + f.puts %Q[ *] + f.puts %Q[ * IMPORTANT:] + f.puts %Q[ * This file was generated!] + f.puts %Q[ * All manual changes will get lost.] + f.puts %Q[ */] + f.puts %Q[] + f.puts %Q[#include "mruby.h"] + f.puts %Q[] + f.puts %Q[#{gems.map{|g| "void GENERATED_TMP_mrb_%s_gem_init(mrb_state* mrb);" % g.funcname}.join("\n")}] + f.puts %Q[void] + f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {] + f.puts %Q[#{gems.map{|g| "GENERATED_TMP_mrb_%s_gem_init(mrb);" % g.funcname}.join("\n")}] + f.puts %Q[}] end end - - file "#{build_dir}/mrbgems/gem_init.c" => MRUBY_CONFIG end end diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake index bbdc0169f..1c495be5b 100644 --- a/tasks/mrbgems_test.rake +++ b/tasks/mrbgems_test.rake @@ -1,21 +1,21 @@ -dir = File.dirname(__FILE__).sub(%r|^\./|, '') - MRuby.each_target do + dir = File.dirname(__FILE__).relative_path_from(root) + gems.each do |g| test_rbc = "#{g.build_dir}/gem_test.c" - test_rbobj = test_rbc.ext('o') + test_rbobj = test_rbc.ext(exts.object) - Rake::FileTask.define_task g.testlib => g.test_objs + [test_rbobj] do |t| - g.build.archive t.name, 'rs', t.prerequisites + file g.testlib => g.test_objs + [test_rbobj] do |t| + g.build.archiver.run t.name, t.prerequisites end - Rake::FileTask.define_task test_rbobj => test_rbc - Rake::FileTask.define_task test_rbc => g.test_rbfiles + [g.build.mrbcfile, "#{build_dir}/lib/libmruby.a"] do |t| + file test_rbobj => test_rbc + file test_rbc => g.test_rbfiles + [g.build.mrbcfile, libfile("#{build_dir}/lib/libmruby")] do |t| open(t.name, 'w') do |f| - f.puts g.gem_init_header - g.build.compile_mruby f, g.test_preload, "gem_test_irep_#{g.funcname}_preload" + g.print_gem_init_header(f) + g.build.mrbc.run f, g.test_preload, "gem_test_irep_#{g.funcname}_preload" g.test_rbfiles.each_with_index do |rbfile, i| - g.build.compile_mruby f, rbfile, "gem_test_irep_#{g.funcname}_#{i}" + g.build.mrbc.run f, rbfile, "gem_test_irep_#{g.funcname}_#{i}" end f.puts %Q[void mrb_#{g.funcname}_gem_test(mrb_state *mrb);] unless g.test_objs.empty? f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb) {] diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index de9e556b4..bcae9dfd9 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -1,7 +1,8 @@ +load 'tasks/mruby_build_gem.rake' +load 'tasks/mruby_build_commands.rake' + module MRuby class << self - attr_accessor :build - def targets @targets ||= {} end @@ -13,170 +14,148 @@ module MRuby end end - class Build - include Rake::DSL - attr_accessor :name - attr_accessor :cc, :cflags, :includes - attr_accessor :ld, :ldflags, :libs - attr_accessor :ar - attr_writer :cxx, :cxxflags - attr_writer :objcc, :objcflags - attr_writer :asm, :asmflags - attr_accessor :bins - attr_accessor :gperf, :yacc - attr_accessor :cat, :git - attr_reader :root, :gems - attr_reader :libmruby - - def initialize(&block) - @name ||= 'host' - @root = File.expand_path("#{File.dirname(__FILE__)}/..") - @cc, @cflags, @includes = 'gcc', %W(-DDISABLE_GEMS -MMD), %W(#{@root}/include) - @ldflags, @libs = [], %w(-lm) - @ar = 'ar' - @cxxflags, @objccflags, @asmflags = [], [], [] - - @yacc, @gperf = 'bison', 'gperf' - @cat, @git = 'cat', 'git' + class Toolchain + class << self + attr_accessor :toolchains + end - @bins = %w(mruby mrbc mirb) + def initialize(name, &block) + @name, @initializer = name.to_s, block + MRuby::Toolchain.toolchains ||= {} + MRuby::Toolchain.toolchains[@name] = self + end - @gems, @libmruby = [], [] + def setup(conf) + conf.instance_eval(&@initializer) + end - MRuby.targets[name.to_s] = self - MRuby.build = self - instance_eval(&block) + def toolchain(name) + @@toolchains[name.to_s].setup(self) end - def cxx; @cxx || cc; end - def cxxflags; !@cxxflags || @cxxflags.empty? ? cflags : @cxxflags; end + def self.load + Dir.glob("#{File.dirname(__FILE__)}/toolchains/*.rake").each do |file| + Kernel.load file + end + end + end + Toolchain.load - def objcc; @objcc || cc; end - def objcflags; !@objcflags || @objcflags.empty? ? cflags : @objcflags; end + class Build + class << self + attr_accessor :current + end + include Rake::DSL + include LoadGems + attr_accessor :name, :bins, :exts, :file_separator + attr_reader :root, :libmruby, :gems - def asm; @asm || cc; end - def asmflags; !@asmflags || @asmflags.empty? ? cflags : @asmflags; end + COMPILERS = %w(cc cxx objc asm) + COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc) + attr_block MRuby::Build::COMMANDS - def ld; @ld || cc; end + Exts = Struct.new(:object, :executable, :library) - def gem(gemdir) - gemdir = load_external_gem(gemdir) if gemdir.is_a?(Hash) + def initialize(name='host', &block) + MRuby::Build.current = self + @name = name + @root = File.expand_path("#{File.dirname(__FILE__)}/..") - [@cflags, @cxxflags, @objcflags, @asmflags].each do |f| - f.delete '-DDISABLE_GEMS' if f + if ENV['OS'] == 'Windows_NT' + @exts = Exts.new('.o', '.exe', '.a') + @file_separator = '\\' + else + @exts = Exts.new('.o', '', '.a') + @file_separator = '/' end - Gem::processing_path = gemdir - load File.join(gemdir, "mrbgem.rake") - end - def load_external_gem(params) - if params[:github] - params[:git] = "[email protected]:#{params[:github]}.git" - end + @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) - if params[:git] - url = params[:git] - gemdir = "build/mrbgems/#{url.match(/([-_\w]+)(\.[-_\w]+|)$/).to_a[1]}" - return gemdir if File.exists?(gemdir) - options = [] - options << "--branch \"#{params[:branch]}\"" if params[:branch] - run_git_clone gemdir, url, options - gemdir - else - fail "unknown gem option #{params}" - end - end + @bins = %w(mruby mrbc mirb) + @gems, @libmruby = [], [] - def enable_gems? + MRuby.targets[name.to_s] = self + + instance_eval(&block) + + compilers.each do |compiler| + compiler.defines -= %w(DISABLE_GEMS) if respond_to?(:enable_gems?) && enable_gems? + compiler.define_rules build_dir + end end - def gemlibs - enable_gems? ? ["#{build_dir}/mrbgems/gem_init.o"] + @gems.map{ |g| g.lib } : [] + def toolchain(name) + Toolchain.toolchains[name.to_s].setup(self) end def build_dir - #@build_dir ||= "build/#{name}" "build/#{self.name}" end def mrbcfile - @mrbcfile ||= exefile("build/host/bin/mrbc") - end - - def compile_c(outfile, infile, flags=[], includes=[]) - FileUtils.mkdir_p File.dirname(outfile) - flags = [cflags, gems.map { |g| g.mruby_cflags }, flags] - flags << [self.includes, gems.map { |g| g.mruby_includes }, includes].flatten.map { |f| "-I#{filename f}" } - sh "#{filename cc} #{flags.flatten.join(' ')} -o #{filename outfile} -c #{filename infile}" - end - - def compile_cxx(outfile, infile, flags=[], includes=[]) - FileUtils.mkdir_p File.dirname(outfile) - flags = [cxxflags, gems.map { |g| g.mruby_cflags }, flags] - flags << [self.includes, gems.map { |g| g.mruby_includes }, includes].flatten.map { |f| "-I#{filename f}" } - sh "#{filename cxx} #{flags.flatten.join(' ')} -o #{filename outfile} -c #{filename infile}" - end - - def compile_objc(outfile, infile, flags=[], includes=[]) - FileUtils.mkdir_p File.dirname(outfile) - flags = [objcflags, gems.map { |g| g.mruby_cflags }, flags] - flags << [self.includes, gems.map { |g| g.mruby_includes }, includes].flatten.map { |f| "-I#{filename f}" } - sh "#{filename objcc} #{flags.flatten.join(' ')} -o #{filename outfile} -c #{filename infile}" - end - - def compile_asm(outfile, infile, flags=[], includes=[]) - FileUtils.mkdir_p File.dirname(outfile) - flags = [asmflags, gems.map { |g| g.mruby_cflags }, flags] - flags << [self.includes, gems.map { |g| g.mruby_includes }, includes].flatten.map { |f| "-I#{filename f}" } - sh "#{filename asm} #{flags.flatten.join(' ')} -o #{filename outfile} -c #{filename infile}" - end - - def compile_mruby(outfile, infiles, funcname) - cmd = "#{cat} #{filenames [infiles]} | #{filename mrbcfile} -B#{funcname}" - if outfile.is_a?(IO) - IO.popen("#{cmd} -o- -", 'r') do |f| - outfile.puts f.read - end - else - FileUtils.mkdir_p File.dirname(outfile) - sh "#{cmd} -o#{filename outfile} -" - end - end - - def link(outfile, objfiles, flags=[], libs=[]) - FileUtils.mkdir_p File.dirname(outfile) - flags = [ldflags, flags] - libs = [libs, self.libs] - sh "#{filename ld} -o #{filename outfile} #{flags.join(' ')} #{filenames objfiles} #{libs.flatten.join(' ')}" + exefile("build/host/bin/mrbc") end - - def archive(outfile, options, objfiles) - FileUtils.mkdir_p File.dirname(outfile) - sh "#{filename ar} #{options} #{filename outfile} #{filenames objfiles}" + + def compilers + COMPILERS.map do |c| + instance_variable_get("@#{c}") + end end - def run_yacc(outfile, infile) - FileUtils.mkdir_p File.dirname(outfile) - sh "#{filename yacc} -o #{filename outfile} #{filename infile}" + def filename(name) + if name.is_a?(Array) + name.map { |n| filename(n) } + else + '"%s"' % name.gsub('/', file_separator) + end end - def run_gperf(outfile, infile) - FileUtils.mkdir_p File.dirname(outfile) - sh %Q[#{filename gperf} -L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" #{filename infile} > #{filename outfile}] + def exefile(name) + if name.is_a?(Array) + name.map { |n| exefile(n) } + else + "#{name}#{exts.executable}" + end end - def run_git_clone(gemdir, giturl, options=[]) - sh "#{filename git} clone #{options.join(' ')} #{filename giturl} #{filename gemdir}" + def objfile(name) + if name.is_a?(Array) + name.map { |n| objfile(n) } + else + "#{name}#{exts.object}" + end end + def libfile(name) + if name.is_a?(Array) + name.map { |n| libfile(n) } + else + "#{name}#{exts.library}" + end + end + def run_test + puts ">>> Test #{name} <<<" + mrbtest = exefile("#{build_dir}/test/mrbtest") + sh "#{filename mrbtest}" + puts + end end # Build class CrossBuild < Build - def initialize(name, &block) - @name ||= name - super(&block) + def run_test + mrbtest = exefile("#{build_dir}/test/mrbtest") + puts "You should run #{mrbtest} on target device." + puts end end # CrossBuild end # MRuby diff --git a/tasks/mruby_build_commands.rake b/tasks/mruby_build_commands.rake new file mode 100644 index 000000000..023b23763 --- /dev/null +++ b/tasks/mruby_build_commands.rake @@ -0,0 +1,198 @@ +require 'forwardable' + +module MRuby + class Command + include Rake::DSL + extend Forwardable + def_delegators :@build, :filename, :objfile, :libfile, :exefile + attr_accessor :build, :command + + def initialize(build) + @build = build + end + + # clone is deep clone without @build + def clone + target = super + excepts = %w(@build) + instance_variables.each do |attr| + unless excepts.include?(attr.to_s) + val = Marshal::load(Marshal.dump(instance_variable_get(attr))) # deep clone + target.instance_variable_set(attr, val) + end + end + target + end + + private + def _run(options, params={}) + sh build.filename(command) + ' ' + ( options % params ) + end + end + + class Command::Compiler < Command + attr_accessor :flags, :include_paths, :defines, :source_exts + attr_accessor :compile_options, :option_define, :option_include_path, :out_ext + + def initialize(build, source_exts=[]) + super(build) + @command = ENV['CC'] || 'gcc' + @flags = [ENV['CFLAGS'] || []] + @source_exts = source_exts + @include_paths = ["#{build.root}/include"] + @defines = %w(DISABLE_GEMS) + @option_include_path = '-I%s' + @option_define = '-D%s' + @compile_options = "%{flags} -MMD -o %{outfile} -c %{infile}" + end + + def run(outfile, infile, _defineds=[], _include_paths=[], _flags=[]) + FileUtils.mkdir_p File.dirname(outfile) + define_flags = [defines, _defineds].flatten.map{ |d| option_define % d } + include_path_flags = [include_paths, _include_paths, File.dirname(infile)].flatten.map{ |f| option_include_path % filename(f) } + _run compile_options, { :flags => (flags + define_flags + include_path_flags + _flags).join(' '), :infile => filename(infile), :outfile => filename(outfile) } + end + + def define_rules(build_dir, source_dir='') + @out_ext = build.exts.object + + generated_file_matcher = Regexp.new("^#{build_dir}/(.*)#{Regexp.escape out_ext}$") + source_exts.each do |ext, compile| + rule generated_file_matcher => [ + proc { |file| + file.sub(generated_file_matcher, "#{source_dir}\\1#{ext}") + }, + proc { |file| + get_dependencies(file) + } + ] do |t| + run t.name, t.prerequisites.first + end + + rule generated_file_matcher => [ + proc { |file| + file.sub(generated_file_matcher, "#{build_dir}/\\1#{ext}") + }, + proc { |file| + get_dependencies(file) + } + ] do |t| + run t.name, t.prerequisites.first + end + end + end + + private + def get_dependencies(file) + file = file.ext('d') unless File.extname(file) == '.d' + if File.exists?(file) + File.read(file).gsub("\\\n ", "").scan(/^\S+:\s+(.+)$/).flatten.map {|s| s.split(' ') }.flatten + else + [] + end + end + end + + class Command::Linker < Command + attr_accessor :flags, :libraries, :library_paths + attr_accessor :link_options, :option_library, :option_library_path + + def initialize(build) + super + @command = ENV['LD'] || 'gcc' + @flags = (ENV['LDFLAGS'] || []) + @libraries = [] + @library_paths = [] + @option_library = '-l%s' + @option_library_path = '-L%s' + @link_options = "%{flags} -o %{outfile} %{objs} %{libs}" + end + + def run(outfile, objfiles, _libraries=[], _library_paths=[], _flags=[]) + FileUtils.mkdir_p File.dirname(outfile) + library_flags = [libraries, _libraries].flatten.reverse.map{ |d| option_library % d } + library_path_flags = [library_paths, _library_paths].flatten.map{ |f| option_library_path % filename(f) } + _run link_options, { :flags => (flags + library_path_flags + _flags).join(' '), :outfile => filename(outfile) , :objs => filename(objfiles).join(' '), :libs => library_flags.join(' ') } + end + end + + class Command::Archiver < Command + attr_accessor :archive_options + + def initialize(build) + super + @command = ENV['AR'] || 'ar' + @archive_options = 'rs %{outfile} %{objs}' + end + + def run(outfile, objfiles) + FileUtils.mkdir_p File.dirname(outfile) + _run archive_options, { :outfile => filename(outfile), :objs => filename(objfiles).join(' ') } + end + end + + class Command::Yacc < Command + attr_accessor :compile_options + + def initialize(build) + super + @command = 'bison' + @compile_options = '-o %{outfile} %{infile}' + end + + def run(outfile, infile) + FileUtils.mkdir_p File.dirname(outfile) + _run compile_options, { :outfile => filename(outfile) , :infile => filename(infile) } + end + end + + class Command::Gperf < Command + attr_accessor :compile_options + + def initialize(build) + super + @command = 'gperf' + @compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}' + end + + def run(outfile, infile) + FileUtils.mkdir_p File.dirname(outfile) + _run compile_options, { :outfile => filename(outfile) , :infile => filename(infile) } + end + end + + class Command::Git < Command + attr_accessor :flags + attr_accessor :clone_options + + def initialize(build) + super + @command = 'git' + @flags = [] + @clone_options = "clone %{flags} %{url} %{dir}" + end + + def run_clone(dir, url, _flags = []) + _run clone_options, { :flags => [flags, _flags].flatten.join(' '), :url => url, :dir => filename(dir) } + end + end + + class Command::Mrbc < Command + def initialize(build) + super + @command = nil + @compile_options = "-B%{funcname} -o- -" + end + + def run(out, infiles, funcname) + @command ||= @build.mrbcfile + IO.popen("#{filename @command} #{@compile_options % {:funcname => funcname}}", 'r+') do |io| + [infiles].flatten.each do |f| + io.write IO.read(f) + end + io.close_write + out.puts io.read + end + end + end +end
\ No newline at end of file diff --git a/tasks/mruby_build_gem.rake b/tasks/mruby_build_gem.rake new file mode 100644 index 000000000..ae0a79447 --- /dev/null +++ b/tasks/mruby_build_gem.rake @@ -0,0 +1,39 @@ +module MRuby + module LoadGems + def gem(gemdir, &block) + gemdir = load_external_gem(gemdir) if gemdir.is_a?(Hash) + load File.join(gemdir, "mrbgem.rake") + Gem.current.dir = gemdir + Gem.current.build = MRuby::Build.current + Gem.current.build_config_initializer = block + gems << Gem.current + Gem.current + end + + def load_external_gem(params) + if params[:github] + params[:git] = "https://github.com/#{params[:github]}.git" + end + + if params[:git] + url = params[:git] + gemdir = "build/mrbgems/#{url.match(/([-_\w]+)(\.[-_\w]+|)$/).to_a[1]}" + return gemdir if File.exists?(gemdir) + + options = [params[:options]] || [] + options << "--branch \"#{params[:branch]}\"" if params[:tag] + + FileUtils.mkdir_p "build/mrbgems" + git.run_clone gemdir, url, options + + gemdir + else + fail "unknown gem option #{params}" + end + end + + def enable_gems? + end + end # LoadGems +end # MRuby diff --git a/tasks/mruby_gem_spec.rake b/tasks/mruby_gem_spec.rake deleted file mode 100644 index c2479412e..000000000 --- a/tasks/mruby_gem_spec.rake +++ /dev/null @@ -1,160 +0,0 @@ -require 'pathname' - -module MRuby - module Gem - class << self - attr_accessor :processing_path - end - - class Specification - include Rake::DSL - - attr_reader :build - attr_accessor :name, :dir - - def self.attr_array(*vars) - attr_reader *vars - vars.each do |v| - class_eval "def #{v}=(val);@#{v}||=[];@#{v}+=[val].flatten;end" - end - end - - attr_array :licenses, :authors - alias :license= :licenses= - alias :author= :authors= - attr_array :cflags, :cxxflags, :objcflags, :asmflags - attr_array :mruby_cflags, :mruby_includes, :mruby_ldflags, :mruby_libs - - attr_array :rbfiles, :objs - attr_array :test_objs, :test_rbfiles - attr_accessor :test_preload - - def initialize(name, &block) - @name = name - @build = MRuby.build - @dir = Gem.processing_path - @cflags, @cxxflags, @objcflags, @asmflags = [], [], [], [] - @mruby_cflags, @mruby_ldflags, @mruby_libs = [], [], [] - @mruby_includes = ["#{dir}/include"] - @rbfiles = Dir.glob("#{dir}/mrblib/*.rb") - @objs = Dir.glob("#{dir}/src/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X.o") } - @test_rbfiles = Dir.glob("#{dir}/test/*.rb") - @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X.o") } - @test_preload = 'test/assert.rb' - - instance_eval(&block) - - @objs << "#{build_dir}/gem_init.o" - - if !name || !licenses || !authors - fail "#{name || dir} required to set name, license(s) and author(s)" - end - - build.gems << self - build.libmruby << @objs - - define_default_rules - add_tasks - end - - def testlib - "#{build_dir}/libmrb-#{name}-gem-test.a" - end - - def funcname - @funcname ||= @name.gsub('-', '_') - end - - def build_dir - @build_dir ||= "#{build.build_dir}/mrbgems/#{name}" - FileUtils.mkdir_p @build_dir - @build_dir - end - - def add_tasks - Rake::FileTask.define_task "#{build_dir}/gem_init.o" => "#{build_dir}/gem_init.c" - Rake::FileTask.define_task "#{build_dir}/gem_init.c" => [build.mrbcfile] + rbfiles do |t| - generate_gem_init("#{build_dir}/gem_init.c") - end - end - - def define_default_rules - obj_matcher = Regexp.new("^#{build_dir}/(.*)\\.o$") - { - '.c' => proc { |t| build.compile_c t.name, t.prerequisites.first, cflags }, - '.cpp' => proc { |t| build.compile_cxx t.name, t.prerequisites.first, cxxflags }, - '.cxx' => proc { |t| build.compile_cxx t.name, t.prerequisites.first, cxxflags }, - '.cc' => proc { |t| build.compile_cxx t.name, t.prerequisites.first, cxxflags }, - '.m' => proc { |t| build.compile_objc t.name, t.prerequisites.first, objcflags }, - '.S' => proc { |t| build.compile_asm t.name, t.prerequisites.first, asmflags } - }.each do |ext, compile| - rule obj_matcher => [ - proc { |file| - file.sub(obj_matcher, "#{dir}/\\1#{ext}") - }, - proc { |file| - get_dependencies(file) - }] do |t| - FileUtils.mkdir_p File.dirname(t.name) - compile.call t - end - - rule obj_matcher => [ - proc { |file| - file.sub(obj_matcher, "#{build_dir}/\\1#{ext}") - }, - proc { |file| - get_dependencies(file) - }] do |t| - FileUtils.mkdir_p File.dirname(t.name) - compile.call t - end - end - end - - def generate_gem_init(fname) - open(fname, 'w') do |f| - f.puts gem_init_header - build.compile_mruby f, rbfiles, "gem_mrblib_irep_#{funcname}" unless rbfiles.empty? - f.puts "void mrb_#{funcname}_gem_init(mrb_state *mrb);" - f.puts "void GENERATED_TMP_mrb_#{funcname}_gem_init(mrb_state *mrb) {" - f.puts " int ai = mrb_gc_arena_save(mrb);" - f.puts " mrb_#{funcname}_gem_init(mrb);" if objs != ["#{build_dir}/gem_init.o"] - f.puts <<__EOF__ unless rbfiles.empty? - mrb_load_irep(mrb, gem_mrblib_irep_#{funcname}); - if (mrb->exc) { - mrb_p(mrb, mrb_obj_value(mrb->exc)); - exit(0); - } - -__EOF__ - f.puts " mrb_gc_arena_restore(mrb, ai);" - - f.puts "}" - end - end # generate_gem_init - - def gem_init_header - <<__EOF__ -/* - * This file is loading the irep - * Ruby GEM code. - * - * IMPORTANT: - * This file was generated! - * All manual changes will get lost. - */ -#include "mruby.h" -#include "mruby/irep.h" -#include "mruby/dump.h" -#include "mruby/string.h" -#include "mruby/proc.h" -#include "mruby/variable.h" -#include "mruby/array.h" -#include "mruby/string.h" -__EOF__ - end # gem_init_header - - end # Specification - end # Gem -end # MRuby diff --git a/tasks/ruby_ext.rake b/tasks/ruby_ext.rake index 08633b4da..ebd499063 100644 --- a/tasks/ruby_ext.rake +++ b/tasks/ruby_ext.rake @@ -1,24 +1,35 @@ -def exefile(filename) - if ENV['OS'] == 'Windows_NT' - "#{filename}.exe" - else - filename +class Object + class << self + def attr_block(*syms) + syms.flatten.each do |sym| + class_eval "def #{sym}(&block);block.call(@#{sym}) if block_given?;@#{sym};end" + end + end end end -def filename(name) - if ENV['OS'] == 'Windows_NT' - '"'+name.gsub('/', '\\')+'"' +class String + def relative_path_from(dir) + Pathname.new(File.expand_path(self)).relative_path_from(Pathname.new(File.expand_path(dir))).to_s + end + + # Compatible with 1.9 on 1.8 + def %(params) + if params.is_a?(Hash) + str = self.clone + params.each do |k, v| + str.gsub!("%{#{k}}", v) + end + str + else + sprintf(self, params) + end end - '"'+name+'"' -end - -def filenames(names) - [names].flatten.map { |n| filename(n) }.join(' ') end -class String - def relative_path_from(dir) - Pathname.new(self).relative_path_from(Pathname.new(dir)).to_s +class Symbol + # Compatible with 1.9 on 1.8 + def to_proc + proc { |obj, *args| obj.send(self, *args) } end end diff --git a/tasks/rules.rake b/tasks/rules.rake deleted file mode 100644 index beda2a864..000000000 --- a/tasks/rules.rake +++ /dev/null @@ -1,43 +0,0 @@ -def get_dependencies(file) - file = file.ext('d') unless File.extname(file) == '.d' - if File.exists?(file) - File.read(file).gsub("\\\n ", "").scan(/^\S+:\s+(.+)$/).flatten.map {|s| s.split(' ') }.flatten - else - [] - end -end - -MRuby.each_target do |t| - obj_matcher = Regexp.new("^#{build_dir}/(.*)\\.o$") - { - '.c' => proc { |t| compile_c t.name, t.prerequisites.first }, - '.cpp' => proc { |t| compile_cxx t.name, t.prerequisites.first }, - '.cxx' => proc { |t| compile_cxx t.name, t.prerequisites.first }, - '.cc' => proc { |t| compile_cxx t.name, t.prerequisites.first }, - '.m' => proc { |t| compile_objc t.name, t.prerequisites.first }, - '.S' => proc { |t| compile_asm t.name, t.prerequisites.first } - }.each do |ext, compile| - rule obj_matcher => [ - proc { |file| - file.sub(obj_matcher, "\\1#{ext}") - }, - proc { |file| - get_dependencies(file) - }] do |t| - FileUtils.mkdir_p File.dirname(t.name) - compile.call t - end - - rule obj_matcher => [ - proc { |file| - file.sub(obj_matcher, "#{build_dir}/\\1#{ext}") - }, - proc { |file| - get_dependencies(file) - }] do |t| - FileUtils.mkdir_p File.dirname(t.name) - compile.call t - end - end -end - diff --git a/tasks/toolchains/clang.rake b/tasks/toolchains/clang.rake new file mode 100644 index 000000000..01dd5f234 --- /dev/null +++ b/tasks/toolchains/clang.rake @@ -0,0 +1,6 @@ +MRuby::Toolchain.new(:clang) do |conf| + toolchain :gcc + + conf.cc.command = ENV['CC'] || 'clang' + conf.linker.command = ENV['LD'] || 'clang' +end diff --git a/tasks/toolchains/gcc.rake b/tasks/toolchains/gcc.rake new file mode 100644 index 000000000..c624c8fc9 --- /dev/null +++ b/tasks/toolchains/gcc.rake @@ -0,0 +1,21 @@ +MRuby::Toolchain.new(:gcc) do |conf| + conf.cc do |cc| + cc.command = ENV['CC'] || 'gcc' + cc.flags = [ENV['CFLAGS'] || %w(-g -O3 -Wall -Werror-implicit-function-declaration)] + cc.include_paths = ["#{root}/include"] + cc.defines = %w(DISABLE_GEMS) + cc.option_include_path = '-I%s' + cc.option_define = '-D%s' + cc.compile_options = '%{flags} -MMD -o %{outfile} -c %{infile}' + end + + conf.linker do |linker| + linker.command = ENV['LD'] || 'gcc' + linker.flags = [ENV['LDFLAGS'] || %w()] + linker.libraries = %w(m) + linker.library_paths = [] + linker.option_library = '-l%s' + linker.option_library_path = '-L%s' + linker.link_options = '%{flags} -o %{outfile} %{objs} %{libs}' + end +end diff --git a/tasks/toolchains/vs2012.rake b/tasks/toolchains/vs2012.rake new file mode 100644 index 000000000..8b4212468 --- /dev/null +++ b/tasks/toolchains/vs2012.rake @@ -0,0 +1,44 @@ +MRuby::Toolchain.new(:vs2012) do |conf| + conf.cc do |cc| + cc.command = ENV['CC'] || 'cl.exe' + cc.flags = [ENV['CFLAGS'] || %w(/c /nologo /W3 /D_DEBUG /MDd /Zi /Od /RTC1 /DDISABLE_GEMS /DHAVE_STRING_H /DNO_GETTIMEOFDAY /D_CRT_SECURE_NO_WARNINGS)] + cc.include_paths = ["#{root}/include"] + cc.defines = %w(DISABLE_GEMS) + cc.option_include_path = '-I%s' + cc.option_define = '-D%s' + cc.compile_options = "%{flags} /Fo%{outfile} -c %{infile}" + end + + conf.linker do |linker| + linker.command = ENV['LD'] || 'link.exe' + linker.flags = [ENV['LDFLAGS'] || %w(/nologo)] + linkerraries = %w(kernel32 user32 gdi32 winspool comdlg32 advapi32 shell32 ole32 oleaut32 uuid odbc32 odbccp32) + linkerrary_paths = [] + linker.option_library = '-l%s' + linker.option_library_path = '-L%s' + linker.link_options = "%{flags} /OUT:%{outfile} %{objs} %{libs}" + end + + conf.archiver do |archiver| + archiver.command = ENV['AR'] || 'lib.exe' + archiver.archive_options = '/OUT:%{outfile} %{objs}' + end + + conf.yacc do |yacc| + yacc.command = ENV['YACC'] || 'bison.exe' + yacc.compile_options = '-o %{outfile} %{infile}' + end + + conf.gperf do |gperf| + gperf.command = 'gperf.exe' + gperf.compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}' + end + + conf.exts do |exts| + exts.object = '.obj' + exts.executable = '.exe' + exts.library = '.lib' + end + + conf.file_separator = '\\' +end diff --git a/test/mrbtest.rake b/test/mrbtest.rake index 33f283fc9..591b737cd 100644 --- a/test/mrbtest.rake +++ b/test/mrbtest.rake @@ -1,32 +1,35 @@ -dir = File.dirname(__FILE__).sub(%r|^\./|, '') - MRuby.each_target do + dir = File.dirname(__FILE__).relative_path_from(root) + exec = exefile("#{build_dir}/#{dir}/mrbtest") clib = "#{build_dir}/#{dir}/mrbtest.c" - mlib = clib.ext('o') + mlib = clib.ext(exts.object) mrbs = Dir.glob("#{dir}/t/*.rb") init = "#{dir}/init_mrbtest.c" asslib = "#{dir}/assert.rb" - objs = ["#{build_dir}/#{dir}/driver.o", mlib] + objs = [objfile("#{build_dir}/#{dir}/driver"), mlib] - file exec => objs + gems.map{ |g| g.testlib } + ["#{build_dir}/lib/libmruby.a"] do |t| - link t.name, t.prerequisites, gems.map { |g| g.mruby_ldflags }, gems.map { |g| g.mruby_libs } + file exec => objs + gems.map(&:testlib) + [libfile("#{build_dir}/lib/libmruby")] do |t| + gem_flags = gems.map { |g| g.linker.flags } + gem_libraries = gems.map { |g| g.linker.libraries } + gem_library_paths = gems.map { |g| g.linker.library_paths } + linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags end file mlib => [clib] file clib => [mrbcfile, init, asslib] + mrbs do |t| open(clib, 'w') do |f| - f.puts File.read(init) - compile_mruby f, [asslib] + mrbs, 'mrbtest_irep' + f.puts IO.read(init) + mrbc.run f, [asslib] + mrbs, 'mrbtest_irep' gems.each do |g| - f.puts "void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);" + f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb);] end - f.puts "void mrbgemtest_init(mrb_state* mrb) {" + f.puts %Q[void mrbgemtest_init(mrb_state* mrb) {] gems.each do |g| - f.puts " GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);" + f.puts %Q[ GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb);] end - f.puts "}" + f.puts %Q[}] end end end diff --git a/tools/mirb/mirb.rake b/tools/mirb/mirb.rake index 958ebe79a..9f41fff64 100644 --- a/tools/mirb/mirb.rake +++ b/tools/mirb/mirb.rake @@ -1,12 +1,15 @@ -dir = File.dirname(__FILE__).sub(%r|^\./|, '') - MRuby.each_target do - if bins.select { |s| s.to_s == 'mirb' } + dir = File.dirname(__FILE__).relative_path_from(root) + + if bins.find { |s| s.to_s == 'mirb' } exec = exefile("#{build_dir}/bin/mirb") - objs = Dir.glob("#{dir}/*.{c}").map { |f| f.pathmap("#{build_dir}/%X.o") } + objs = Dir.glob("#{dir}/*.c").map { |f| objfile(f.pathmap("#{build_dir}/%X")) } - file exec => objs + ["#{build_dir}/lib/libmruby.a"] do |t| - link t.name, t.prerequisites, gems.map { |g| g.mruby_ldflags }, gems.map { |g| g.mruby_libs } + file exec => objs + [libfile("#{build_dir}/lib/libmruby")] do |t| + gem_flags = gems.map { |g| g.linker.flags } + gem_libraries = gems.map { |g| g.linker.libraries } + gem_library_paths = gems.map { |g| g.linker.library_paths } + linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags end end end diff --git a/tools/mrbc/mrbc.rake b/tools/mrbc/mrbc.rake index 74e04bed5..248433cf0 100644 --- a/tools/mrbc/mrbc.rake +++ b/tools/mrbc/mrbc.rake @@ -1,12 +1,12 @@ -dir = File.dirname(__FILE__).sub(%r|^\./|, '') - MRuby.each_target do - if bins.select { |s| s.to_s == 'mrbc' } + dir = File.dirname(__FILE__).relative_path_from(root) + + if bins.find { |s| s.to_s == 'mrbc' } exec = exefile("#{build_dir}/bin/mrbc") - objs = Dir.glob("#{dir}/*.{c}").map { |f| f.pathmap("#{build_dir}/%X.o") } + objs = Dir.glob("#{dir}/*.c").map { |f| objfile(f.pathmap("#{build_dir}/%X")) } - file exec => objs + ["#{build_dir}/lib/libmruby_core.a"] do |t| - link t.name, t.prerequisites + file exec => objs + [libfile("#{build_dir}/lib/libmruby_core")] do |t| + linker.run t.name, t.prerequisites end end end diff --git a/tools/mruby/mruby.rake b/tools/mruby/mruby.rake index 7842c4266..d380cb9f5 100644 --- a/tools/mruby/mruby.rake +++ b/tools/mruby/mruby.rake @@ -1,12 +1,15 @@ -dir = File.dirname(__FILE__).sub(%r|^\./|, '') - MRuby.each_target do - if bins.select { |s| s.to_s == 'mruby' } + dir = File.dirname(__FILE__).relative_path_from(root) + + if bins.find { |s| s.to_s == 'mruby' } exec = exefile("#{build_dir}/bin/mruby") - objs = Dir.glob("#{dir}/*.{c}").map { |f| f.pathmap("#{build_dir}/%X.o") } + objs = Dir.glob("#{dir}/*.c").map { |f| objfile(f.pathmap("#{build_dir}/%X")) } - file exec => objs + ["#{build_dir}/lib/libmruby.a"] do |t| - link t.name, t.prerequisites, gems.map { |g| g.mruby_ldflags }, gems.map { |g| g.mruby_libs } + file exec => objs + [libfile("#{build_dir}/lib/libmruby")] do |t| + gem_flags = gems.map { |g| g.linker.flags } + gem_libraries = gems.map { |g| g.linker.libraries } + gem_library_paths = gems.map { |g| g.linker.library_paths } + linker.run t.name, t.prerequisites, gem_libraries, gem_library_paths, gem_flags end end end |
