diff options
Diffstat (limited to 'tasks')
| -rw-r--r-- | tasks/mrbgem_spec.rake | 10 | ||||
| -rw-r--r-- | tasks/mrbgems_test.rake | 94 | ||||
| -rw-r--r-- | tasks/mruby_build.rake | 31 | ||||
| -rw-r--r-- | tasks/toolchains/androidndk.rake | 215 |
4 files changed, 245 insertions, 105 deletions
diff --git a/tasks/mrbgem_spec.rake b/tasks/mrbgem_spec.rake index d13e7733f..4fcfc8f83 100644 --- a/tasks/mrbgem_spec.rake +++ b/tasks/mrbgem_spec.rake @@ -52,9 +52,9 @@ module MRuby MRuby::Build::COMMANDS.each do |command| instance_variable_set("@#{command}", @build.send(command).clone) end - @linker = LinkerConfig.new([], [], [], []) + @linker = LinkerConfig.new([], [], [], [], []) - @rbfiles = Dir.glob("#{dir}/mrblib/*.rb").sort + @rbfiles = Dir.glob("#{dir}/mrblib/**/*.rb").sort @objs = Dir.glob("#{dir}/src/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| objfile(f.relative_path_from(@dir).to_s.pathmap("#{build_dir}/%X")) end @@ -62,7 +62,7 @@ module MRuby @generate_functions = !(@rbfiles.empty? && @objs.empty?) @objs << objfile("#{build_dir}/gem_init") if @generate_functions - @test_rbfiles = Dir.glob("#{dir}/test/*.rb") + @test_rbfiles = Dir.glob("#{dir}/test/**/*.rb") @test_objs = Dir.glob("#{dir}/test/*.{c,cpp,cxx,cc,m,asm,s,S}").map do |f| objfile(f.relative_path_from(dir).to_s.pathmap("#{build_dir}/%X")) end @@ -103,6 +103,10 @@ module MRuby @dependencies << {:gem => name, :requirements => requirements, :default => default_gem} end + def add_test_dependency(*args) + add_dependency(*args) if build.test_enabled? + end + def add_conflict(name, *req) @conflicts << {:gem => name, :requirements => req.empty? ? nil : req} end diff --git a/tasks/mrbgems_test.rake b/tasks/mrbgems_test.rake deleted file mode 100644 index 0ee508360..000000000 --- a/tasks/mrbgems_test.rake +++ /dev/null @@ -1,94 +0,0 @@ -MRuby.each_target do - gem_table = gems.generate_gem_table self - - gems.each do |g| - test_rbobj = g.test_rbireps.ext(exts.object) - g.test_objs << test_rbobj - dep_list = gems.tsort_dependencies(g.test_dependencies, gem_table).select(&:generate_functions) - - file test_rbobj => g.test_rbireps - file g.test_rbireps => [g.test_rbfiles].flatten + [File.join(g.dir, 'mrbgem.rake'), g.build.mrbcfile, __FILE__, "#{MRUBY_ROOT}/tasks/mrbgem_spec.rake"] do |t| - FileUtils.mkdir_p File.dirname(t.name) - open(t.name, 'w') do |f| - g.print_gem_test_header(f) - test_preload = g.test_preload and [g.dir, MRUBY_ROOT].map {|dir| - File.expand_path(g.test_preload, dir) - }.find {|file| File.exist?(file) } - - f.puts %Q[/*] - f.puts %Q[ * This file contains a test code for #{g.name} gem.] - 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[ */] - if test_preload.nil? - f.puts %Q[extern const uint8_t mrbtest_assert_irep[];] - else - g.build.mrbc.run f, test_preload, "gem_test_irep_#{g.funcname}_preload" - end - g.test_rbfiles.flatten.each_with_index do |rbfile, 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? - dep_list.each do |d| - f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb_state *mrb);] - f.puts %Q[void GENERATED_TMP_mrb_#{d.funcname}_gem_final(mrb_state *mrb);] - end - f.puts %Q[void mrb_init_test_driver(mrb_state *mrb, mrb_bool verbose);] - f.puts %Q[void mrb_t_pass_result(mrb_state *dst, mrb_state *src);] - f.puts %Q[void GENERATED_TMP_mrb_#{g.funcname}_gem_test(mrb_state *mrb) {] - unless g.test_rbfiles.empty? - f.puts %Q[ mrb_state *mrb2;] - unless g.test_args.empty? - f.puts %Q[ mrb_value test_args_hash;] - end - f.puts %Q[ int ai;] - g.test_rbfiles.count.times do |i| - f.puts %Q[ ai = mrb_gc_arena_save(mrb);] - f.puts %Q[ mrb2 = mrb_open_core(mrb_default_allocf, NULL);] - f.puts %Q[ if (mrb2 == NULL) {] - f.puts %Q[ fprintf(stderr, "Invalid mrb_state, exiting \%s", __FUNCTION__);] - f.puts %Q[ exit(EXIT_FAILURE);] - f.puts %Q[ }] - dep_list.each do |d| - f.puts %Q[ GENERATED_TMP_mrb_#{d.funcname}_gem_init(mrb2);] - f.puts %Q[ mrb_state_atexit(mrb2, GENERATED_TMP_mrb_#{d.funcname}_gem_final);] - end - f.puts %Q[ mrb_init_test_driver(mrb2, mrb_test(mrb_gv_get(mrb, mrb_intern_lit(mrb, "$mrbtest_verbose"))));] - if test_preload.nil? - f.puts %Q[ mrb_load_irep(mrb2, mrbtest_assert_irep);] - else - f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_preload);] - end - f.puts %Q[ if (mrb2->exc) {] - f.puts %Q[ mrb_print_error(mrb2);] - f.puts %Q[ exit(EXIT_FAILURE);] - f.puts %Q[ }] - f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "GEMNAME"), mrb_str_new(mrb2, "#{g.name}", #{g.name.length}));] - - unless g.test_args.empty? - f.puts %Q[ test_args_hash = mrb_hash_new_capa(mrb, #{g.test_args.length}); ] - g.test_args.each do |arg_name, arg_value| - escaped_arg_name = arg_name.gsub('\\', '\\\\\\\\').gsub('"', '\"') - escaped_arg_value = arg_value.gsub('\\', '\\\\\\\\').gsub('"', '\"') - f.puts %Q[ mrb_hash_set(mrb2, test_args_hash, mrb_str_new(mrb2, "#{escaped_arg_name.to_s}", #{escaped_arg_name.to_s.length}), mrb_str_new(mrb2, "#{escaped_arg_value.to_s}", #{escaped_arg_value.to_s.length})); ] - end - f.puts %Q[ mrb_const_set(mrb2, mrb_obj_value(mrb2->object_class), mrb_intern_lit(mrb2, "TEST_ARGS"), test_args_hash); ] - end - - f.puts %Q[ mrb_#{g.funcname}_gem_test(mrb2);] if g.custom_test_init? - - f.puts %Q[ mrb_load_irep(mrb2, gem_test_irep_#{g.funcname}_#{i});] - f.puts %Q[ ] - - f.puts %Q[ mrb_t_pass_result(mrb, mrb2);] - f.puts %Q[ mrb_close(mrb2);] - f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] - end - end - f.puts %Q[}] - end - end - end -end diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake index 9f8b4eda5..cff45ddf8 100644 --- a/tasks/mruby_build.rake +++ b/tasks/mruby_build.rake @@ -26,8 +26,8 @@ module MRuby MRuby::Toolchain.toolchains[@name] = self end - def setup(conf) - conf.instance_eval(&@initializer) + def setup(conf,params={}) + conf.instance_exec(conf, params, &@initializer) end def self.load @@ -46,7 +46,7 @@ module MRuby include LoadGems attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir attr_reader :libmruby, :gems, :toolchains - attr_writer :enable_bintest + attr_writer :enable_bintest, :enable_test COMPILERS = %w(cc cxx objc asm) COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc) @@ -85,6 +85,8 @@ module MRuby @build_mrbtest_lib_only = false @cxx_abi_enabled = false @cxx_exception_disabled = false + @enable_bintest = false + @enable_test = false @toolchains = [] MRuby.targets[@name] = self @@ -94,6 +96,7 @@ module MRuby MRuby.targets[@name].instance_eval(&block) build_mrbc_exec if name == 'host' + build_mrbtest if test_enabled? end def enable_debug @@ -155,10 +158,10 @@ EOS @enable_bintest end - def toolchain(name) + def toolchain(name, params={}) tc = Toolchain.toolchains[name.to_s] fail "Unknown #{name} toolchain" unless tc - tc.setup(self) + tc.setup(self, params) @toolchains.unshift name.to_s end @@ -170,6 +173,18 @@ EOS 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 @@ -249,10 +264,10 @@ EOS def run_test puts ">>> Test #{name} <<<" - mrbtest = exefile("#{build_dir}/test/mrbtest") + mrbtest = exefile("#{build_dir}/bin/mrbtest") sh "#{filename mrbtest.relative_path}#{$verbose ? ' -v' : ''}" puts - run_bintest if @enable_bintest + run_bintest if bintest_enabled? end def run_bintest @@ -297,7 +312,7 @@ EOS end def run_test - mrbtest = exefile("#{build_dir}/test/mrbtest") + mrbtest = exefile("#{build_dir}/bin/mrbtest") if (@test_runner.command == nil) puts "You should run #{mrbtest} on target device." puts diff --git a/tasks/toolchains/androidndk.rake b/tasks/toolchains/androidndk.rake new file mode 100644 index 000000000..ccf1a0c4d --- /dev/null +++ b/tasks/toolchains/androidndk.rake @@ -0,0 +1,215 @@ + +class MRuby::Toolchain::AndroidNDK + DEFAULT_ARCH = 'armeabi' + DEFAULT_PLATFORM = 'android-14' + DEFAULT_TOOLCHAIN = :gcc + DEFAULT_NDK_HOMES = %w{ + /usr/local/opt/android-ndk + } + TOOLCHAINS = [:gcc, :clang] + ARCHITECTURES = %w{ + armeabi armeabi-v7a arm64-v8a + mips mips64 + x86 x86_64 + } + + class AndroidNDKHomeNotFound < StandardError + def message + <<-EOM +Couldn't find Android NDK Home. +Set ANDROID_NDK_HOME environment variable or set :ndk_home parameter + EOM + end + end + + attr_reader :params + + def initialize(params) + @params = params + end + + def home_path + @home_path ||= Pathname( + params[:ndk_home] || + ENV['ANDROID_NDK_HOME'] || + DEFAULT_NDK_HOMES.find{ |path| File.directory?(path) } || + raise(AndroidNDKHomeNotFound) + ) + end + + def arch + params.fetch(:arch){ DEFAULT_ARCH } + end + + def platform + params.fetch(:platform){ DEFAULT_PLATFORM } + end + + def toolchain + params.fetch(:toolchain){ DEFAULT_TOOLCHAIN } + end + + def toolchain_version + params.fetch(:toolchain_version) do + test = case toolchain + when :gcc + case arch + when /armeabi/ + 'arm-linux-androideabi-*' + when /arm64/ + 'aarch64-linux-android-*' + when /mips64/ + 'mips64el-linux-android-*' + when /mips/ + 'mipsel-linux-android-*' + when /x86_64/ + 'x86_64-*' + when /x86/ + 'x86-*' + end + when :clang + 'llvm-*' + end + + Dir[home_path.join('toolchains',test)].map{|t| t.match(/-(\d+\.\d+)$/); $1.to_f }.max + end + end + + def toolchain_path + prefix = case toolchain + when :clang then 'llvm-' + when :gcc + case arch + when /armeabi/ then 'arm-linux-androideabi-' + when /arm64/ then 'aarch64-linux-android-' + when /x86_64/ then 'x86_64-' + when /x86/ then 'x86-' + when /mips64/ then 'mips64el-linux-android-' + when /mips/ then 'mipsel-linux-android-' + end + end + home_path.join('toolchains', prefix + toolchain_version.to_s, 'prebuilt', host_platform) + end + + def sysroot + path = case arch + when /armeabi/ then 'arch-arm' + when /arm64/ then 'arch-arm64' + when /x86_64/ then 'arch-x86_64' + when /x86/ then 'arch-x86' + when /mips64/ then 'arch-mips64' + when /mips/ then 'arch-mips' + end + + home_path.join('platforms', platform, path).to_s + end + + def bin(command) + command = command.to_s + + if toolchain == :gcc + command = case arch + when /armeabi/ then 'arm-linux-androideabi-' + when /arm64/ then 'aarch64-linux-android-' + when /x86_64/ then 'x86_64-linux-android-' + when /x86/ then 'i686-linux-android-' + when /mips64/ then 'mips64el-linux-android-' + when /mips/ then 'mipsel-linux-android-' + end + command + end + + toolchain_path.join('bin',command).to_s + end + + def cc + case toolchain + when :gcc then bin(:gcc) + when :clang then bin(:clang) + end + end + + def cflags + flags = [] + + case toolchain + when :gcc + flags += %W(-ffunction-sections -funwind-tables -no-canonical-prefixes) + flags += %W(-D__android__ -mandroid --sysroot="#{sysroot}") + case arch + when /arm64/ + flags += %W(-fpic -fstack-protector-strong) + when 'armeabi-v7a-hard' + flags += %W(-fpic -fstack-protector-strong -march=armv7-a -mhard-float -D_NDK_MATH_NO_SOFTFP=1 -mfpu=vfpv3-d16) + when 'armeabi-v7a' + flags += %W(-fpic -fstack-protector-strong -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16) + when /arm/ + flags += %W(-fpic -fstack-protector-strong -march=armv5te -mtune=xscale -msoft-float) + when /mips/ + flags += %W(-fpic -fno-strict-aliasing -finline-functions -fmessage-length=0 -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers) + when /x86/ + flags += %W(-fstack-protector-strong) + end + when :clang + end + + flags + end + + def ld + cc + end + + def ldflags + flags = [] + case toolchain + when :gcc + flags += %W(-no-canonical-prefixes) + flags += %W(-D__android__ -mandroid --sysroot="#{sysroot}") + case arch + when 'armeabi-v7a-hard' + flags += %W(-march=armv7-a -Wl,--fix-cortex-a8 -Wl,--no-warn-mismatch -lm_hard) + when 'armeabi-v7a' + flags += %W(-march=armv7-a -Wl,--fix-cortex-a8) + end + end + end + + def ar + case toolchain + when :gcc then bin(:ar) + when :clang then bin('llvm-ar') + end + end + + def host_platform + case RUBY_PLATFORM + when /cygwin|mswin|mingw|bccwin|wince|emx/i + 'windows' + when /x86_64-darwin/i + 'darwin-x86_64' + when /darwin/i + 'darwin-x86' + when /x86_64-linux/i + 'linux-x86_64' + when /linux/i + 'linux-x86' + else + raise NotImplementedError, "Unknown host platform (#{RUBY_PLATFORM})" + end + end +end + +MRuby::Toolchain.new(:androidndk) do |conf, params| + ndk = MRuby::Toolchain::AndroidNDK.new(params) + + toolchain ndk.toolchain + + [conf.cc, conf.cxx, conf.objc, conf.asm].each do |cc| + cc.command = ndk.cc + cc.flags = ndk.cflags + end + conf.linker.command = ndk.ld + conf.linker.flags = ndk.ldflags + conf.archiver.command = ndk.ar +end + |
