diff options
Diffstat (limited to 'tasks')
| -rw-r--r-- | tasks/libmruby.rake | 5 | ||||
| -rw-r--r-- | tasks/mrbgems.rake | 33 | ||||
| -rw-r--r-- | tasks/mruby_build.rake | 175 | ||||
| -rw-r--r-- | tasks/mruby_gem_spec.rake | 183 | ||||
| -rw-r--r-- | tasks/ruby_ext.rake | 24 | ||||
| -rw-r--r-- | tasks/rules.rake | 41 |
6 files changed, 461 insertions, 0 deletions
diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake new file mode 100644 index 000000000..5b785d208 --- /dev/null +++ b/tasks/libmruby.rake @@ -0,0 +1,5 @@ + MRuby.each_target do + file "#{build_dir}/lib/libmruby.a" => libmruby.flatten do |t| + archive t.name, 'r', t.prerequisites + end +end diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake new file mode 100644 index 000000000..356e40369 --- /dev/null +++ b/tasks/mrbgems.rake @@ -0,0 +1,33 @@ +dir = File.dirname(__FILE__).sub(%r|^\./|, '') + +MRuby.each_target do + if enable_gems? + self.libmruby << "#{build_dir}/mrbgems/gem_init.o" + + file "#{build_dir}/mrbgems/gem_init.o" => "#{build_dir}/mrbgems/gem_init.c" + file "#{build_dir}/mrbgems/gem_init.c" 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__ + end + end + end +end diff --git a/tasks/mruby_build.rake b/tasks/mruby_build.rake new file mode 100644 index 000000000..fad92c5e1 --- /dev/null +++ b/tasks/mruby_build.rake @@ -0,0 +1,175 @@ +module MRuby + class << self + attr_accessor :build + + def targets + @targets ||= [] + end + + def each_target(&block) + @targets.each do |target| + target.instance_eval(&block) + end + 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, :objccflags + attr_writer :asm, :asmflags + 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' + + @gems, @libmruby = [], [] + + MRuby.targets << self + MRuby.build = self + instance_eval(&block) + end + + def cxx; @cxx || cc; end + def cxxflags; @cxxflags.empty? ? cflags : @cxxflags; end + + def objcc; @objcc || cc; end + def objccflags; @objccflags.empty? ? cflags : @objccflags; end + + def asm; @asm || cc; end + def asmflags; @asmflags.empty? ? cflags : @asmflags; end + + def ld; @ld || cc; end + + def gem(gemdir) + gemdir = load_external_gem(gemdir) if gemdir.is_a?(Hash) + + [@cflags, @cxxflags, @objcflags, @asmflags].each do |f| + f.delete '-DDISABLE_GEMS' if f + end + Gem::processing_path = gemdir + load File.join(gemdir, "mrbgem.rake") + end + + def load_external_gem(params) + 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 + + def enable_gems? + end + + def gemlibs + enable_gems? ? ["#{build_dir}/mrbgems/gem_init.o"] + @gems.map{ |g| g.lib } : [] + 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(' ')}" + end + + def archive(outfile, options, objfiles) + FileUtils.mkdir_p File.dirname(outfile) + sh "#{filename ar} #{options} #{filename outfile} #{filenames objfiles}" + end + + def run_yacc(outfile, infile) + FileUtils.mkdir_p File.dirname(outfile) + sh "#{filename yacc} -o #{filename outfile} #{filename infile}" + 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}] + end + + def run_git_clone(gemdir, giturl, options=[]) + sh "#{filename git} clone #{options.join(' ')} #{filename giturl} #{filename gemdir}" + end + + + end # Build + + class CrossBuild < Build + def initialize(name, &block) + @name ||= name + super(&block) + end + end # CrossBuild +end # MRuby diff --git a/tasks/mruby_gem_spec.rake b/tasks/mruby_gem_spec.rake new file mode 100644 index 000000000..59a536e2c --- /dev/null +++ b/tasks/mruby_gem_spec.rake @@ -0,0 +1,183 @@ +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 + 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 = [] + @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 + return @build_dir if @build_dir + @build_dir = "#{build.build_dir}/mrbgems/#{name}" + FileUtils.mkdir_p @build_dir + @build_dir + end + + def add_tasks + test_rbc = "#{build_dir}/gem_test.c" + test_rbobj = test_rbc.ext('o') + + Rake::FileTask.define_task testlib => test_objs + [test_rbobj] do |t| + build.archive t.name, 'rs', t.prerequisites + end + + Rake::FileTask.define_task test_rbobj => test_rbc + Rake::FileTask.define_task test_rbc => [build.mrbcfile] + test_rbfiles do |t| + open(t.name, 'w') do |f| + f.puts gem_init_header + build.compile_mruby f, test_rbfiles, "gem_test_irep_#{funcname}" unless test_rbfiles.empty? + end + + open(t.name, 'a') do |f| + f.puts "void mrb_#{funcname}_gem_test(mrb_state *mrb);" unless test_objs.empty? + f.puts "void GENERATED_TMP_mrb_#{funcname}_gem_test(mrb_state *mrb) {" + f.puts " mrb_#{funcname}_gem_test(mrb);" unless test_objs.empty? + f.puts <<__EOF__ unless test_rbfiles.empty? + mrb_load_irep(mrb, gem_test_irep_#{funcname}); + if (mrb->exc) { + mrb_p(mrb, mrb_obj_value(mrb->exc)); + exit(0); + } + +__EOF__ + f.puts "}" + end + end + + 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(t.name) + 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, cflags }, + '.m' => proc { |t| build.compile_objc t.name, t.prerequisites.first, cflags }, + '.S' => proc { |t| build.compile_asm t.name, t.prerequisites.first, cflags } + }.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 " mrb_#{funcname}_gem_init(mrb);" unless objs.empty? + 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 "}" + 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" +__EOF__ + end # gem_init_header + + end # Specification + end # Gem +end # MRuby
\ No newline at end of file diff --git a/tasks/ruby_ext.rake b/tasks/ruby_ext.rake new file mode 100644 index 000000000..08633b4da --- /dev/null +++ b/tasks/ruby_ext.rake @@ -0,0 +1,24 @@ +def exefile(filename) + if ENV['OS'] == 'Windows_NT' + "#{filename}.exe" + else + filename + end +end + +def filename(name) + if ENV['OS'] == 'Windows_NT' + '"'+name.gsub('/', '\\')+'"' + 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 + end +end diff --git a/tasks/rules.rake b/tasks/rules.rake new file mode 100644 index 000000000..f53f3bccd --- /dev/null +++ b/tasks/rules.rake @@ -0,0 +1,41 @@ +def get_dependencies(file) + file = file.pathmap('%n.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 }, + '.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 + |
