7 def_delegators :@build, :filename, :objfile, :libfile, :exefile, :cygwin_filename
8 attr_accessor :build, :command
14 # clone is deep clone without @build
18 instance_variables.each do |attr|
19 unless excepts.include?(attr.to_s)
20 val = Marshal::load(Marshal.dump(instance_variable_get(attr))) # deep clone
21 target.instance_variable_set(attr, val)
30 def _run(options, params={})
31 return sh command + ' ' + ( options % params ) if NotFoundCommands.key? @command
33 sh build.filename(command) + ' ' + ( options % params )
35 NotFoundCommands[@command] = true
41 class Command::Compiler < Command
42 attr_accessor :flags, :include_paths, :defines, :source_exts
43 attr_accessor :compile_options, :option_define, :option_include_path, :out_ext
44 attr_accessor :cxx_compile_flag, :cxx_exception_flag
46 def initialize(build, source_exts=[])
48 @command = ENV['CC'] || 'cc'
49 @flags = [ENV['CFLAGS'] || []]
50 @source_exts = source_exts
51 @include_paths = ["#{MRUBY_ROOT}/include"]
53 @option_include_path = '-I%s'
54 @option_define = '-D%s'
55 @compile_options = '%{flags} -o %{outfile} -c %{infile}'
58 alias header_search_paths include_paths
59 def search_header_path(name)
60 header_search_paths.find do |v|
61 File.exist? build.filename("#{v}/#{name}").sub(/^"(.*)"$/, '\1')
65 def search_header(name)
66 path = search_header_path name
67 path && build.filename("#{path}/#{name}").sub(/^"(.*)"$/, '\1')
70 def all_flags(_defines=[], _include_paths=[], _flags=[])
71 define_flags = [defines, _defines].flatten.map{ |d| option_define % d }
72 include_path_flags = [include_paths, _include_paths].flatten.map do |f|
73 if MRUBY_BUILD_HOST_IS_CYGWIN
74 option_include_path % cygwin_filename(f)
76 option_include_path % filename(f)
79 [flags, define_flags, include_path_flags, _flags].flatten.join(' ')
82 def run(outfile, infile, _defines=[], _include_paths=[], _flags=[])
83 FileUtils.mkdir_p File.dirname(outfile)
84 _pp "CC", infile.relative_path, outfile.relative_path
85 if MRUBY_BUILD_HOST_IS_CYGWIN
86 _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags),
87 :infile => cygwin_filename(infile), :outfile => cygwin_filename(outfile) }
89 _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags),
90 :infile => filename(infile), :outfile => filename(outfile) }
94 def define_rules(build_dir, source_dir='')
95 @out_ext = build.exts.object
96 gemrake = File.join(source_dir, "mrbgem.rake")
97 rakedep = File.exist?(gemrake) ? [ gemrake ] : []
99 if build_dir.include? "mrbgems/"
100 generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(.*)#{Regexp.escape out_ext}$")
102 generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(?!mrbgems/.+/)(.*)#{Regexp.escape out_ext}$")
104 source_exts.each do |ext, compile|
105 rule generated_file_matcher => [
107 file.sub(generated_file_matcher, "#{source_dir}/\\1#{ext}")
110 get_dependencies(file) + rakedep
113 run t.name, t.prerequisites.first
116 rule generated_file_matcher => [
118 file.sub(generated_file_matcher, "#{build_dir}/\\1#{ext}")
121 get_dependencies(file) + rakedep
124 run t.name, t.prerequisites.first
130 def get_dependencies(file)
131 file = file.ext('d') unless File.extname(file) == '.d'
133 File.read(file).gsub("\\\n ", "").scan(/^\S+:\s+(.+)$/).flatten.map {|s| s.split(' ') }.flatten
136 end + [ MRUBY_CONFIG ]
140 class Command::Linker < Command
141 attr_accessor :flags, :library_paths, :flags_before_libraries, :libraries, :flags_after_libraries
142 attr_accessor :link_options, :option_library, :option_library_path
144 def initialize(build)
146 @command = ENV['LD'] || 'ld'
147 @flags = (ENV['LDFLAGS'] || [])
148 @flags_before_libraries, @flags_after_libraries = [], []
151 @option_library = '-l%s'
152 @option_library_path = '-L%s'
153 @link_options = "%{flags} -o %{outfile} %{objs} %{flags_before_libraries} %{libs} %{flags_after_libraries}"
156 def all_flags(_library_paths=[], _flags=[])
157 library_path_flags = [library_paths, _library_paths].flatten.map do |f|
158 if MRUBY_BUILD_HOST_IS_CYGWIN
159 option_library_path % cygwin_filename(f)
161 option_library_path % filename(f)
164 [flags, library_path_flags, _flags].flatten.join(' ')
167 def library_flags(_libraries)
168 [libraries, _libraries].flatten.map{ |d| option_library % d }.join(' ')
171 def run(outfile, objfiles, _libraries=[], _library_paths=[], _flags=[], _flags_before_libraries=[], _flags_after_libraries=[])
172 FileUtils.mkdir_p File.dirname(outfile)
173 library_flags = [libraries, _libraries].flatten.map { |d| option_library % d }
175 _pp "LD", outfile.relative_path
176 if MRUBY_BUILD_HOST_IS_CYGWIN
177 _run link_options, { :flags => all_flags(_library_paths, _flags),
178 :outfile => cygwin_filename(outfile) , :objs => cygwin_filename(objfiles).join(' '),
179 :flags_before_libraries => [flags_before_libraries, _flags_before_libraries].flatten.join(' '),
180 :flags_after_libraries => [flags_after_libraries, _flags_after_libraries].flatten.join(' '),
181 :libs => library_flags.join(' ') }
183 _run link_options, { :flags => all_flags(_library_paths, _flags),
184 :outfile => filename(outfile) , :objs => filename(objfiles).join(' '),
185 :flags_before_libraries => [flags_before_libraries, _flags_before_libraries].flatten.join(' '),
186 :flags_after_libraries => [flags_after_libraries, _flags_after_libraries].flatten.join(' '),
187 :libs => library_flags.join(' ') }
192 class Command::Archiver < Command
193 attr_accessor :archive_options
195 def initialize(build)
197 @command = ENV['AR'] || 'ar'
198 @archive_options = 'rs %{outfile} %{objs}'
201 def run(outfile, objfiles)
202 FileUtils.mkdir_p File.dirname(outfile)
203 _pp "AR", outfile.relative_path
204 if MRUBY_BUILD_HOST_IS_CYGWIN
205 _run archive_options, { :outfile => cygwin_filename(outfile), :objs => cygwin_filename(objfiles).join(' ') }
207 _run archive_options, { :outfile => filename(outfile), :objs => filename(objfiles).join(' ') }
212 class Command::Yacc < Command
213 attr_accessor :compile_options
215 def initialize(build)
218 @compile_options = '-o %{outfile} %{infile}'
221 def run(outfile, infile)
222 FileUtils.mkdir_p File.dirname(outfile)
223 _pp "YACC", infile.relative_path, outfile.relative_path
224 _run compile_options, { :outfile => filename(outfile) , :infile => filename(infile) }
228 class Command::Gperf < Command
229 attr_accessor :compile_options
231 def initialize(build)
234 @compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}'
237 def run(outfile, infile)
238 FileUtils.mkdir_p File.dirname(outfile)
239 _pp "GPERF", infile.relative_path, outfile.relative_path
240 _run compile_options, { :outfile => filename(outfile) , :infile => filename(infile) }
244 class Command::Git < Command
246 attr_accessor :clone_options, :pull_options, :checkout_options
248 def initialize(build)
252 @clone_options = "clone %{flags} %{url} %{dir}"
253 @pull_options = "pull"
254 @checkout_options = "checkout %{checksum_hash}"
257 def run_clone(dir, url, _flags = [])
258 _pp "GIT", url, dir.relative_path
259 _run clone_options, { :flags => [flags, _flags].flatten.join(' '), :url => url, :dir => filename(dir) }
262 def run_pull(dir, url)
265 _pp "GIT PULL", url, dir.relative_path
270 def run_checkout(dir, checksum_hash)
273 _pp "GIT CHECKOUT", checksum_hash
274 _run checkout_options, { :checksum_hash => checksum_hash }
279 class Command::Mrbc < Command
280 attr_accessor :compile_options
282 def initialize(build)
285 @compile_options = "-B%{funcname} -o-"
288 def run(out, infiles, funcname)
289 @command ||= @build.mrbcfile
290 infiles = [infiles].flatten
292 _pp "MRBC", f.relative_path, nil, :indent => 2
294 IO.popen("#{filename @command} #{@compile_options % {:funcname => funcname}} #{filename(infiles).join(' ')}", 'r+') do |io|
297 # if mrbc execution fail, drop the file
298 if $?.exitstatus != 0
299 File.delete(out.path)
305 class Command::CrossTestRunner < Command
306 attr_accessor :runner_options
307 attr_accessor :verbose_flag
310 def initialize(build)
313 @runner_options = '%{flags} %{infile}'
319 puts "TEST for " + @build.name
320 _run runner_options, { :flags => [flags, verbose_flag].flatten.join(' '), :infile => testbinfile }