Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / third-party / mruby / lib / mruby / build / command.rb
1 require 'forwardable'
2
3 module MRuby
4   class Command
5     include Rake::DSL
6     extend Forwardable
7     def_delegators :@build, :filename, :objfile, :libfile, :exefile, :cygwin_filename
8     attr_accessor :build, :command
9
10     def initialize(build)
11       @build = build
12     end
13
14     # clone is deep clone without @build
15     def clone
16       target = super
17       excepts = %w(@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)
22         end
23       end
24       target
25     end
26
27     NotFoundCommands = {}
28
29     private
30     def _run(options, params={})
31       return sh command + ' ' + ( options % params ) if NotFoundCommands.key? @command
32       begin
33         sh build.filename(command) + ' ' + ( options % params )
34       rescue RuntimeError
35         NotFoundCommands[@command] = true
36         _run options, params
37       end
38     end
39   end
40
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
45
46     def initialize(build, source_exts=[])
47       super(build)
48       @command = ENV['CC'] || 'cc'
49       @flags = [ENV['CFLAGS'] || []]
50       @source_exts = source_exts
51       @include_paths = ["#{MRUBY_ROOT}/include"]
52       @defines = %w()
53       @option_include_path = '-I%s'
54       @option_define = '-D%s'
55       @compile_options = '%{flags} -o %{outfile} -c %{infile}'
56     end
57
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')
62       end
63     end
64
65     def search_header(name)
66       path = search_header_path name
67       path && build.filename("#{path}/#{name}").sub(/^"(.*)"$/, '\1')
68     end
69
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)
75         else
76           option_include_path % filename(f)
77         end
78       end
79       [flags, define_flags, include_path_flags, _flags].flatten.join(' ')
80     end
81
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) }
88       else
89         _run compile_options, { :flags => all_flags(_defines, _include_paths, _flags),
90                                 :infile => filename(infile), :outfile => filename(outfile) }
91       end
92     end
93
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 ] : []
98
99       if build_dir.include? "mrbgems/"
100         generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(.*)#{Regexp.escape out_ext}$")
101       else
102         generated_file_matcher = Regexp.new("^#{Regexp.escape build_dir}/(?!mrbgems/.+/)(.*)#{Regexp.escape out_ext}$")
103       end
104       source_exts.each do |ext, compile|
105         rule generated_file_matcher => [
106           proc { |file|
107             file.sub(generated_file_matcher, "#{source_dir}/\\1#{ext}")
108           },
109           proc { |file|
110             get_dependencies(file) + rakedep
111           }
112         ] do |t|
113           run t.name, t.prerequisites.first
114         end
115
116         rule generated_file_matcher => [
117           proc { |file|
118             file.sub(generated_file_matcher, "#{build_dir}/\\1#{ext}")
119           },
120           proc { |file|
121             get_dependencies(file) + rakedep
122           }
123         ] do |t|
124           run t.name, t.prerequisites.first
125         end
126       end
127     end
128
129     private
130     def get_dependencies(file)
131       file = file.ext('d') unless File.extname(file) == '.d'
132       if File.exist?(file)
133         File.read(file).gsub("\\\n ", "").scan(/^\S+:\s+(.+)$/).flatten.map {|s| s.split(' ') }.flatten
134       else
135         []
136       end + [ MRUBY_CONFIG ]
137     end
138   end
139
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
143
144     def initialize(build)
145       super
146       @command = ENV['LD'] || 'ld'
147       @flags = (ENV['LDFLAGS'] || [])
148       @flags_before_libraries, @flags_after_libraries = [], []
149       @libraries = []
150       @library_paths = []
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}"
154     end
155
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)
160         else
161           option_library_path % filename(f)
162         end
163       end
164       [flags, library_path_flags, _flags].flatten.join(' ')
165     end
166
167     def library_flags(_libraries)
168       [libraries, _libraries].flatten.map{ |d| option_library % d }.join(' ')
169     end
170
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 }
174
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(' ') }
182       else
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(' ') }
188       end
189     end
190   end
191
192   class Command::Archiver < Command
193     attr_accessor :archive_options
194
195     def initialize(build)
196       super
197       @command = ENV['AR'] || 'ar'
198       @archive_options = 'rs %{outfile} %{objs}'
199     end
200
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(' ') }
206       else
207         _run archive_options, { :outfile => filename(outfile), :objs => filename(objfiles).join(' ') }
208       end
209     end
210   end
211
212   class Command::Yacc < Command
213     attr_accessor :compile_options
214
215     def initialize(build)
216       super
217       @command = 'bison'
218       @compile_options = '-o %{outfile} %{infile}'
219     end
220
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) }
225     end
226   end
227
228   class Command::Gperf < Command
229     attr_accessor :compile_options
230
231     def initialize(build)
232       super
233       @command = 'gperf'
234       @compile_options = '-L ANSI-C -C -p -j1 -i 1 -g -o -t -N mrb_reserved_word -k"1,3,$" %{infile} > %{outfile}'
235     end
236
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) }
241     end
242   end
243
244   class Command::Git < Command
245     attr_accessor :flags
246     attr_accessor :clone_options, :pull_options, :checkout_options
247
248     def initialize(build)
249       super
250       @command = 'git'
251       @flags = %w[]
252       @clone_options = "clone %{flags} %{url} %{dir}"
253       @pull_options = "pull"
254       @checkout_options = "checkout %{checksum_hash}"
255     end
256
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) }
260     end
261
262     def run_pull(dir, url)
263       root = Dir.pwd
264       Dir.chdir dir
265       _pp "GIT PULL", url, dir.relative_path
266       _run pull_options
267       Dir.chdir root
268     end
269
270     def run_checkout(dir, checksum_hash)
271       root = Dir.pwd
272       Dir.chdir dir
273       _pp "GIT CHECKOUT", checksum_hash
274       _run checkout_options, { :checksum_hash => checksum_hash }
275       Dir.chdir root
276     end
277   end
278
279   class Command::Mrbc < Command
280     attr_accessor :compile_options
281
282     def initialize(build)
283       super
284       @command = nil
285       @compile_options = "-B%{funcname} -o-"
286     end
287
288     def run(out, infiles, funcname)
289       @command ||= @build.mrbcfile
290       infiles = [infiles].flatten
291       infiles.each do |f|
292         _pp "MRBC", f.relative_path, nil, :indent => 2
293       end
294       IO.popen("#{filename @command} #{@compile_options % {:funcname => funcname}} #{filename(infiles).join(' ')}", 'r+') do |io|
295         out.puts io.read
296       end
297       # if mrbc execution fail, drop the file
298       if $?.exitstatus != 0
299         File.delete(out.path)
300         exit(-1)
301       end
302     end
303   end
304
305   class Command::CrossTestRunner < Command
306     attr_accessor :runner_options
307     attr_accessor :verbose_flag
308     attr_accessor :flags
309
310     def initialize(build)
311       super
312       @command = nil
313       @runner_options = '%{flags} %{infile}'
314       @verbose_flag = ''
315       @flags = []
316     end
317
318     def run(testbinfile)
319       puts "TEST for " + @build.name
320       _run runner_options, { :flags => [flags, verbose_flag].flatten.join(' '), :infile => testbinfile }
321     end
322   end
323
324 end