summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Rakefile19
-rw-r--r--build_config.rb113
-rw-r--r--doc/mrbgems/c_and_ruby_extension_example/mrbgem.rake21
-rw-r--r--doc/mrbgems/c_extension_example/mrbgem.rake19
-rw-r--r--doc/mrbgems/ruby_extension_example/mrbgem.rake21
-rw-r--r--include/mrbconf.h1
-rw-r--r--mrblib/mrblib.rake11
-rw-r--r--src/mruby_core.rake18
-rw-r--r--tasks/libmruby.rake4
-rw-r--r--tasks/mrbgem_spec.rake139
-rw-r--r--tasks/mrbgems.rake53
-rw-r--r--tasks/mrbgems_test.rake20
-rw-r--r--tasks/mruby_build.rake239
-rw-r--r--tasks/mruby_build_commands.rake198
-rw-r--r--tasks/mruby_build_gem.rake39
-rw-r--r--tasks/mruby_gem_spec.rake160
-rw-r--r--tasks/ruby_ext.rake43
-rw-r--r--tasks/rules.rake43
-rw-r--r--tasks/toolchains/clang.rake6
-rw-r--r--tasks/toolchains/gcc.rake21
-rw-r--r--tasks/toolchains/vs2012.rake44
-rw-r--r--test/mrbtest.rake27
-rw-r--r--tools/mirb/mirb.rake15
-rw-r--r--tools/mrbc/mrbc.rake12
-rw-r--r--tools/mruby/mruby.rake15
25 files changed, 786 insertions, 515 deletions
diff --git a/Rakefile b/Rakefile
index fd0336033..f0991d323 100644
--- a/Rakefile
+++ b/Rakefile
@@ -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