source: EcnlProtoTool/trunk/mruby-2.1.1/lib/mruby/build/command.rb@ 439

Last change on this file since 439 was 439, checked in by coas-nagasima, 4 years ago

mrubyを2.1.1に更新

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-ruby;charset=UTF-8
File size: 15.1 KB
Line 
1require 'forwardable'
2require 'digest/md5'
3
4module MRuby
5 class Command
6 include Rake::DSL
7 extend Forwardable
8 def_delegators :@build, :filename, :objfile, :libfile, :exefile
9 attr_accessor :build, :command
10
11 def initialize(build)
12 @build = build
13 end
14
15 # clone is deep clone without @build
16 def clone
17 target = super
18 excepts = %w(@build)
19 instance_variables.each do |attr|
20 unless excepts.include?(attr.to_s)
21 val = Marshal::load(Marshal.dump(instance_variable_get(attr))) # deep clone
22 target.instance_variable_set(attr, val)
23 end
24 end
25 target
26 end
27
28 def shellquote(s)
29 if ENV['OS'] == 'Windows_NT'
30 "\"#{s}\""
31 else
32 "#{s}"
33 end
34 end
35
36 NotFoundCommands = {}
37
38 private
39 def _run(options, params={})
40 return sh command + ' ' + ( options % params ) if NotFoundCommands.key? @command
41 begin
42 sh build.filename(command) + ' ' + ( options % params )
43 rescue RuntimeError
44 NotFoundCommands[@command] = true
45 _run options, params
46 end
47 end
48 end
49
50 class Command::Compiler < Command
51 attr_accessor :flags, :include_paths, :defines, :source_exts
52 attr_accessor :compile_options, :option_define, :option_include_path, :out_ext
53 attr_accessor :cxx_compile_flag, :cxx_exception_flag, :cxx_invalid_flags
54
55 def initialize(build, source_exts=[])
56 super(build)
57 @command = ENV['CC'] || 'cc'
58 @flags = [ENV['CFLAGS'] || []]
59 @source_exts = source_exts
60 @include_paths = ["#{MRUBY_ROOT}/include"]
61 @defines = %w()
62 @option_include_path = %q[-I"%s"]
63 @option_define = %q[-D"%s"]
64 @compile_options = %q[%{flags} -o "%{outfile}" -c "%{infile}"]
65 @cxx_invalid_flags = []
66 end
67
68 alias header_search_paths include_paths
69 def search_header_path(name)
70 header_search_paths.find do |v|
71 File.exist? build.filename("#{v}/#{name}").sub(/^"(.*)"$/, '\1')
72 end
73 end
74
75 def search_header(name)
76 path = search_header_path name
77 path && build.filename("#{path}/#{name}").sub(/^"(.*)"$/, '\1')
78 end
79
80 def all_flags(_defines=[], _include_paths=[], _flags=[], params={})
81 define_flags = [defines, _defines].flatten.map{ |d| option_define % d }
82 include_path_flags = [include_paths, _include_paths].flatten.map do |f|
83 option_include_path % filename(f)
84 end
85 if params.length > 0
86 __flags = flags.collect { |flag|
87 if flag.is_a?(Array)
88 flag.collect { |f|
89 if f.include?('%')
90 f % params
91 else
92 f
93 end
94 }.flatten
95 else
96 if flag.include?('%')
97 flag % params
98 else
99 flag
100 end
101 end
102 }.flatten
103 else
104 __flags = flags
105 end
106 [__flags, define_flags, include_path_flags, _flags].flatten.join(' ')
107 end
108
109 def run(outfile, infile, _defines=[], _include_paths=[], _flags=[])
110 mkdir_p File.dirname(outfile)
111 _pp "CC", infile.relative_path, outfile.relative_path
112 params = { :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
113 if MRUBY_BUILD_HOST_IS_CYGWIN
114 _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags, params),
115 :infile => cygwin_filename(infile), :outfile => cygwin_filename(outfile),
116 :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
117 else
118 _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags, params),
119 :infile => filename(infile), :outfile => filename(outfile),
120 :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
121 end
122 end
123
124 def define_rules(build_dir, source_dir='')
125 @out_ext = build.exts.object
126 gemrake = File.join(source_dir, "mrbgem.rake")
127 rakedep = File.exist?(gemrake) ? [ gemrake ] : []
128
129 if build_dir.include? "mrbgems/"
130 generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(.*)#{Regexp.escape out_ext}$")
131 else
132 generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(?!mrbgems/.+/)(.*)#{Regexp.escape out_ext}$")
133 end
134 source_exts.each do |ext, compile|
135 rule generated_file_matcher => [
136 proc { |file|
137 file.sub(generated_file_matcher, "#{source_dir}/\\1#{ext}")
138 },
139 proc { |file|
140 get_dependencies(file) + rakedep
141 }
142 ] do |t|
143 run t.name, t.prerequisites.first
144 end
145
146 rule generated_file_matcher => [
147 proc { |file|
148 file.sub(generated_file_matcher, "#{build_dir}/\\1#{ext}")
149 },
150 proc { |file|
151 get_dependencies(file) + rakedep
152 }
153 ] do |t|
154 run t.name, t.prerequisites.first
155 end
156 end
157 end
158
159 private
160
161 #
162 # === Example of +.d+ file
163 #
164 # ==== Without <tt>-MP</tt> compiler flag
165 #
166 # /build/host/src/array.o: \
167 # /src/array.c \
168 # /include/mruby/common.h \
169 # /include/mruby/value.h \
170 # /src/value_array.h
171 #
172 # ==== With <tt>-MP</tt> compiler flag
173 #
174 # /build/host/src/array.o: \
175 # /src/array.c \
176 # /include/mruby/common.h \
177 # /include/mruby/value.h \
178 # /src/value_array.h
179 #
180 # /include/mruby/common.h:
181 #
182 # /include/mruby/value.h:
183 #
184 # /src/value_array.h:
185 #
186 def get_dependencies(file)
187 file = file.ext('d') unless File.extname(file) == '.d'
188 deps = []
189 if File.exist?(file)
190 File.foreach(file){|line| deps << $1 if /^ +(.*?)(?: *\\)?$/ =~ line}
191 deps.uniq!
192 end
193 deps << MRUBY_CONFIG
194 end
195 end
196
197 class Command::Linker < Command
198 attr_accessor :flags, :library_paths, :flags_before_libraries, :libraries, :flags_after_libraries
199 attr_accessor :link_options, :option_library, :option_library_path
200
201 def initialize(build)
202 super
203 @build = build
204 @command = ENV['LD'] || 'ld'
205 @flags = (ENV['LDFLAGS'] || [])
206 @flags_before_libraries, @flags_after_libraries = [], []
207 @libraries = []
208 @library_paths = []
209 @option_library = %q[-l"%s"]
210 @option_library_path = %q[-L"%s"]
211 @link_options = %Q[%{flags} -o "%{outfile}" %{objs} %{flags_before_libraries} %{libs} %{flags_after_libraries}]
212 end
213
214 def all_flags(_library_paths=[], _flags=[], params={})
215 library_path_flags = [library_paths, _library_paths].flatten.map do |f|
216 option_library_path % filename(f)
217 end
218 if params.length > 0
219 __flags = flags.collect { |flag|
220 if flag.is_a?(Array)
221 flag.collect { |f|
222 if f.include?('%')
223 f % params
224 else
225 f
226 end
227 }.flatten
228 else
229 if flag.include?('%')
230 flag % params
231 else
232 flag
233 end
234 end
235 }.flatten
236 else
237 __flags = flags
238 end
239 [__flags, library_path_flags, _flags].flatten.join(' ')
240 end
241
242 def library_flags(_libraries)
243 [libraries, _libraries].flatten.map{ |d| option_library % d }.join(' ')
244 end
245
246 def run(outfile, objfiles, _libraries=[], _library_paths=[], _flags=[], _flags_before_libraries=[], _flags_after_libraries=[])
247 mkdir_p File.dirname(outfile)
248 library_flags = [libraries, _libraries].flatten.map { |d| option_library % d }
249
250 _pp "LD", outfile.relative_path
251 if MRUBY_BUILD_HOST_IS_CYGWIN
252 params = { :outfile => cygwin_filename(outfile), :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
253 _run link_options, { :flags => all_flags(_library_paths, _flags, params),
254 :outfile => cygwin_filename(outfile) , :objs => cygwin_filename(objfiles).join(' '),
255 :flags_before_libraries => [flags_before_libraries, _flags_before_libraries].flatten.join(' '),
256 :flags_after_libraries => [flags_after_libraries, _flags_after_libraries].flatten.join(' '),
257 :libs => library_flags.join(' '),
258 :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
259 else
260 params = { :outfile => filename(outfile), :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
261 _run link_options, { :flags => all_flags(_library_paths, _flags, params),
262 :outfile => filename(outfile) , :objs => filename(objfiles).map{|f| %Q["#{f}"]}.join(' '),
263 :flags_before_libraries => [flags_before_libraries, _flags_before_libraries].flatten.join(' '),
264 :flags_after_libraries => [flags_after_libraries, _flags_after_libraries].flatten.join(' '),
265 :libs => library_flags.join(' '),
266 :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
267 end
268 end
269 end
270
271 class Command::Archiver < Command
272 attr_accessor :archive_options
273
274 def initialize(build)
275 super
276 @command = ENV['AR'] || 'ar'
277 @archive_options = 'rs "%{outfile}" %{objs}'
278 end
279
280 def run(outfile, objfiles)
281 mkdir_p File.dirname(outfile)
282 _pp "AR", outfile.relative_path
283
284 # reference from emar.py
285 outfilebase = File.dirname(outfile)
286 to_delete = []
287 newargs = []
288 objfiles.each do |orig_name|
289 dir_name = File.dirname(orig_name)
290 dir_name = dir_name.relative_path_from(Dir.pwd)
291 base_name = File.basename(orig_name)
292 parts = base_name.split('.')
293 # h = Digest::MD5.new.update(orig_name).to_s
294 h = Digest::MD5.new.update(orig_name).to_s.slice(0,4)
295 parts[0] += '_' + h
296 newname = parts.join('.')
297 full_newname = File.join(dir_name, newname)
298 if not File.exists?(full_newname)
299 begin # it is ok to fail here, we just don't get hashing
300 FileUtils.cp(orig_name, full_newname)
301 newargs << full_newname
302 to_delete << full_newname
303 rescue
304 end
305 end
306 end
307
308 if MRUBY_BUILD_HOST_IS_CYGWIN
309 _run archive_options, { :outfile => cygwin_filename(outfile), :objs => cygwin_filename(objfiles).map{|f| %Q["#{f}"]}.join(' '), :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
310 else
311 _run archive_options, { :outfile => filename(outfile), :objs => filename(objfiles).map{|f| %Q["#{f}"]}.join(' '), :outdir => File.dirname(outfile).gsub('/', @build.file_separator), :outfilebase => File.basename(outfile, ".*") }
312 end
313
314 to_delete.each do |d|
315 FileUtils.rm(d)
316 end
317 end
318 end
319
320 class Command::Yacc < Command
321 attr_accessor :compile_options
322
323 def initialize(build)
324 super
325 @command = 'bison'
326 @compile_options = %q[-o "%{outfile}" "%{infile}"]
327 end
328
329 def run(outfile, infile)
330 mkdir_p File.dirname(outfile)
331 _pp "YACC", infile.relative_path, outfile.relative_path
332 _run compile_options, { :outfile => filename(outfile) , :infile => filename(infile) }
333 end
334 end
335
336 class Command::Gperf < Command
337 attr_accessor :compile_options
338
339 def initialize(build)
340 super
341 @command = 'gperf'
342 @compile_options = %q[-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" "%{infile}" > "%{outfile}"]
343 end
344
345 def run(outfile, infile)
346 mkdir_p File.dirname(outfile)
347 _pp "GPERF", infile.relative_path, outfile.relative_path
348 _run compile_options, { :outfile => filename(outfile) , :infile => filename(infile) }
349 end
350 end
351
352 class Command::Git < Command
353 attr_accessor :flags
354 attr_accessor :clone_options, :pull_options, :checkout_options, :checkout_detach_options, :reset_options
355
356 def initialize(build)
357 super
358 @command = 'git'
359 @flags = %w[]
360 @clone_options = "clone %{flags} %{url} %{dir}"
361 @pull_options = "--git-dir %{repo_dir}/.git --work-tree %{repo_dir} pull"
362 @checkout_options = "--git-dir %{repo_dir}/.git --work-tree %{repo_dir} checkout %{checksum_hash}"
363 @checkout_detach_options = "--git-dir %{repo_dir}/.git --work-tree %{repo_dir} checkout --detach %{checksum_hash}"
364 @reset_options = "--git-dir %{repo_dir}/.git --work-tree %{repo_dir} reset %{checksum_hash}"
365 end
366
367 def run_clone(dir, url, _flags = [])
368 _pp "GIT", url, dir.relative_path
369 _run clone_options, { :flags => [flags, _flags].flatten.join(' '), :url => shellquote(url), :dir => shellquote(filename(dir)) }
370 end
371
372 def run_pull(dir, url)
373 _pp "GIT PULL", url, dir.relative_path
374 _run pull_options, { :repo_dir => shellquote(dir) }
375 end
376
377 def run_checkout(dir, checksum_hash)
378 _pp "GIT CHECKOUT", dir, checksum_hash
379 _run checkout_options, { :checksum_hash => checksum_hash, :repo_dir => shellquote(dir) }
380 end
381
382 def run_checkout_detach(dir, checksum_hash)
383 _pp "GIT CHECKOUT DETACH", dir, checksum_hash
384 _run checkout_detach_options, { :checksum_hash => checksum_hash, :repo_dir => shellquote(dir) }
385 end
386
387 def run_reset_hard(dir, checksum_hash)
388 _pp "GIT RESET", dir, checksum_hash
389 _run reset_options, { :checksum_hash => checksum_hash, :repo_dir => shellquote(dir) }
390 end
391
392 def commit_hash(dir)
393 `#{@command} --git-dir #{shellquote(dir +'/.git')} --work-tree #{shellquote(dir)} rev-parse --verify HEAD`.strip
394 end
395
396 def current_branch(dir)
397 `#{@command} --git-dir #{shellquote(dir + '/.git')} --work-tree #{shellquote(dir)} rev-parse --abbrev-ref HEAD`.strip
398 end
399 end
400
401 class Command::Mrbc < Command
402 attr_accessor :compile_options
403
404 def initialize(build)
405 super
406 @command = nil
407 @compile_options = "-B%{funcname} -o-"
408 end
409
410 def run(out, infiles, funcname)
411 @command ||= @build.mrbcfile
412 infiles = [infiles].flatten
413 infiles.each do |f|
414 _pp "MRBC", f.relative_path, nil, :indent => 2
415 end
416 cmd = %Q["#{filename @command}" #{@compile_options % {:funcname => funcname}} #{filename(infiles).map{|f| %Q["#{f}"]}.join(' ')}]
417 puts cmd if Rake.verbose
418 IO.popen(cmd, 'r+') do |io|
419 out.puts io.read
420 end
421 # if mrbc execution fail, drop the file
422 if $?.exitstatus != 0
423 File.delete(out.path)
424 exit(-1)
425 end
426 end
427 end
428
429 class Command::CrossTestRunner < Command
430 attr_accessor :runner_options
431 attr_accessor :verbose_flag
432 attr_accessor :flags
433
434 def initialize(build)
435 super
436 @command = nil
437 @runner_options = '%{flags} %{infile}'
438 @verbose_flag = ''
439 @flags = []
440 end
441
442 def run(testbinfile)
443 puts "TEST for " + @build.name
444 _run runner_options, { :flags => [flags, verbose_flag].flatten.join(' '), :infile => testbinfile }
445 end
446 end
447
448end
Note: See TracBrowser for help on using the repository browser.