summaryrefslogtreecommitdiffhomepage
path: root/tasks
diff options
context:
space:
mode:
authorYuichiro MASUI <[email protected]>2012-12-29 05:37:55 +0900
committerYuichiro MASUI <[email protected]>2013-01-03 02:24:15 +0900
commit7c469c0b9dadd1de09fed18c3e5cc551012c38c1 (patch)
treeb79aa703ef7c528896c4f1be8280d0691314008b /tasks
parenta48fc0d7952ad1f10ae777637269fe6a3f9ad0a2 (diff)
downloadmruby-7c469c0b9dadd1de09fed18c3e5cc551012c38c1.tar.gz
mruby-7c469c0b9dadd1de09fed18c3e5cc551012c38c1.zip
Rebuild CRuby based building script without Makefile
Tested CRuby 1.8.6 and 1.9.3 You can see building configuration in build_config.rb
Diffstat (limited to 'tasks')
-rw-r--r--tasks/libmruby.rake5
-rw-r--r--tasks/mrbgems.rake33
-rw-r--r--tasks/mruby_build.rake175
-rw-r--r--tasks/mruby_gem_spec.rake183
-rw-r--r--tasks/ruby_ext.rake24
-rw-r--r--tasks/rules.rake41
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
+