Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / third-party / mruby / lib / mruby / build.rb
1 require "mruby/build/load_gems"
2 require "mruby/build/command"
3
4 module MRuby
5   class << self
6     def targets
7       @targets ||= {}
8     end
9
10     def each_target(&block)
11       return to_enum(:each_target) if block.nil?
12       @targets.each do |key, target|
13         target.instance_eval(&block)
14       end
15     end
16   end
17
18   class Toolchain
19     class << self
20       attr_accessor :toolchains
21     end
22
23     def initialize(name, &block)
24       @name, @initializer = name.to_s, block
25       MRuby::Toolchain.toolchains ||= {}
26       MRuby::Toolchain.toolchains[@name] = self
27     end
28
29     def setup(conf,params={})
30       conf.instance_exec(conf, params, &@initializer)
31     end
32
33     def self.load
34       Dir.glob("#{MRUBY_ROOT}/tasks/toolchains/*.rake").each do |file|
35         Kernel.load file
36       end
37     end
38   end
39   Toolchain.load
40
41   class Build
42     class << self
43       attr_accessor :current
44     end
45     include Rake::DSL
46     include LoadGems
47     attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir
48     attr_reader :libmruby_objs, :gems, :toolchains
49     attr_writer :enable_bintest, :enable_test
50
51     alias libmruby libmruby_objs
52
53     COMPILERS = %w(cc cxx objc asm)
54     COMMANDS = COMPILERS + %w(linker archiver yacc gperf git exts mrbc)
55     attr_block MRuby::Build::COMMANDS
56
57     Exts = Struct.new(:object, :executable, :library)
58
59     def initialize(name='host', build_dir=nil, &block)
60       @name = name.to_s
61
62       unless MRuby.targets[@name]
63         if ENV['OS'] == 'Windows_NT'
64           @exts = Exts.new('.o', '.exe', '.a')
65         else
66           @exts = Exts.new('.o', '', '.a')
67         end
68
69         build_dir = build_dir || ENV['MRUBY_BUILD_DIR'] || "#{MRUBY_ROOT}/build"
70
71         @file_separator = '/'
72         @build_dir = "#{build_dir}/#{@name}"
73         @gem_clone_dir = "#{build_dir}/mrbgems"
74         @cc = Command::Compiler.new(self, %w(.c))
75         @cxx = Command::Compiler.new(self, %w(.cc .cxx .cpp))
76         @objc = Command::Compiler.new(self, %w(.m))
77         @asm = Command::Compiler.new(self, %w(.S .asm))
78         @linker = Command::Linker.new(self)
79         @archiver = Command::Archiver.new(self)
80         @yacc = Command::Yacc.new(self)
81         @gperf = Command::Gperf.new(self)
82         @git = Command::Git.new(self)
83         @mrbc = Command::Mrbc.new(self)
84
85         @bins = []
86         @gems, @libmruby_objs = MRuby::Gem::List.new, []
87         @build_mrbtest_lib_only = false
88         @cxx_exception_enabled = false
89         @cxx_exception_disabled = false
90         @cxx_abi_enabled = false
91         @enable_bintest = false
92         @enable_test = false
93         @toolchains = []
94
95         MRuby.targets[@name] = self
96       end
97
98       MRuby::Build.current = MRuby.targets[@name]
99       MRuby.targets[@name].instance_eval(&block)
100
101       build_mrbc_exec if name == 'host'
102       build_mrbtest if test_enabled?
103     end
104
105     def debug_enabled?
106       @enable_debug
107     end
108
109     def enable_debug
110       compilers.each do |c|
111         c.defines += %w(MRB_DEBUG)
112         if toolchains.any? { |toolchain| toolchain == "gcc" }
113           c.flags += %w(-g3 -O0)
114         end
115       end
116       @mrbc.compile_options += ' -g'
117
118       @enable_debug = true
119     end
120
121     def disable_cxx_exception
122       if @cxx_exception_enabled or @cxx_abi_enabled
123         raise "cxx_exception already enabled"
124       end
125       @cxx_exception_disabled = true
126     end
127
128     def enable_cxx_exception
129       return if @cxx_exception_enabled
130       return if @cxx_abi_enabled
131       if @cxx_exception_disabled
132         raise "cxx_exception disabled"
133       end
134       @cxx_exception_enabled = true
135       compilers.each { |c|
136         c.defines += %w(MRB_ENABLE_CXX_EXCEPTION)
137         c.flags << c.cxx_exception_flag
138       }
139       linker.command = cxx.command if toolchains.find { |v| v == 'gcc' }
140     end
141
142     def cxx_exception_enabled?
143       @cxx_exception_enabled
144     end
145
146     def cxx_abi_enabled?
147       @cxx_abi_enabled
148     end
149
150     def enable_cxx_abi
151       return if @cxx_abi_enabled
152       if @cxx_exception_enabled
153         raise "cxx_exception already enabled"
154       end
155       compilers.each { |c|
156         c.defines += %w(MRB_ENABLE_CXX_EXCEPTION MRB_ENABLE_CXX_ABI)
157         c.flags << c.cxx_compile_flag
158       }
159       compilers.each { |c| c.flags << c.cxx_compile_flag }
160       linker.command = cxx.command if toolchains.find { |v| v == 'gcc' }
161       @cxx_abi_enabled = true
162     end
163
164     def compile_as_cxx src, cxx_src, obj = nil, includes = []
165       obj = objfile(cxx_src) if obj.nil?
166
167       file cxx_src => [src, __FILE__] do |t|
168         FileUtils.mkdir_p File.dirname t.name
169         IO.write t.name, <<EOS
170 #define __STDC_CONSTANT_MACROS
171 #define __STDC_LIMIT_MACROS
172
173 #ifndef MRB_ENABLE_CXX_ABI
174 extern "C" {
175 #endif
176 #include "#{File.absolute_path src}"
177 #ifndef MRB_ENABLE_CXX_ABI
178 }
179 #endif
180 EOS
181       end
182
183       file obj => cxx_src do |t|
184         cxx.run t.name, t.prerequisites.first, [], ["#{MRUBY_ROOT}/src"] + includes
185       end
186
187       obj
188     end
189
190     def enable_bintest
191       @enable_bintest = true
192     end
193
194     def bintest_enabled?
195       @enable_bintest
196     end
197
198     def toolchain(name, params={})
199       tc = Toolchain.toolchains[name.to_s]
200       fail "Unknown #{name} toolchain" unless tc
201       tc.setup(self, params)
202       @toolchains.unshift name.to_s
203     end
204
205     def primary_toolchain
206       @toolchains.first
207     end
208
209     def root
210       MRUBY_ROOT
211     end
212
213     def enable_test
214       @enable_test = true
215     end
216
217     def test_enabled?
218       @enable_test
219     end
220
221     def build_mrbtest
222       gem :core => 'mruby-test'
223     end
224
225     def build_mrbc_exec
226       gem :core => 'mruby-bin-mrbc'
227     end
228
229     def mrbcfile
230       return @mrbcfile if @mrbcfile
231
232       mrbc_build = MRuby.targets['host']
233       gems.each { |v| mrbc_build = self if v.name == 'mruby-bin-mrbc' }
234       @mrbcfile = mrbc_build.exefile("#{mrbc_build.build_dir}/bin/mrbc")
235     end
236
237     def compilers
238       COMPILERS.map do |c|
239         instance_variable_get("@#{c}")
240       end
241     end
242
243     def define_rules
244       compilers.each do |compiler|
245         if respond_to?(:enable_gems?) && enable_gems?
246           compiler.defines -= %w(DISABLE_GEMS)
247         else
248           compiler.defines += %w(DISABLE_GEMS)
249         end
250         compiler.define_rules build_dir, File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
251       end
252     end
253
254     def filename(name)
255       if name.is_a?(Array)
256         name.flatten.map { |n| filename(n) }
257       else
258         '"%s"' % name.gsub('/', file_separator)
259       end
260     end
261
262     def cygwin_filename(name)
263       if name.is_a?(Array)
264         name.flatten.map { |n| cygwin_filename(n) }
265       else
266         '"%s"' % `cygpath -w "#{filename(name)}"`.strip
267       end
268     end
269
270     def exefile(name)
271       if name.is_a?(Array)
272         name.flatten.map { |n| exefile(n) }
273       elsif File.extname(name).empty?
274         "#{name}#{exts.executable}"
275       else
276         # `name` sometimes have (non-standard) extension (e.g. `.bat`).
277         name
278       end
279     end
280
281     def objfile(name)
282       if name.is_a?(Array)
283         name.flatten.map { |n| objfile(n) }
284       else
285         "#{name}#{exts.object}"
286       end
287     end
288
289     def libfile(name)
290       if name.is_a?(Array)
291         name.flatten.map { |n| libfile(n) }
292       else
293         "#{name}#{exts.library}"
294       end
295     end
296
297     def build_mrbtest_lib_only
298       @build_mrbtest_lib_only = true
299     end
300
301     def build_mrbtest_lib_only?
302       @build_mrbtest_lib_only
303     end
304
305     def verbose_flag
306       $verbose ? ' -v' : ''
307     end
308
309     def run_test
310       puts ">>> Test #{name} <<<"
311       mrbtest = exefile("#{build_dir}/bin/mrbtest")
312       sh "#{filename mrbtest.relative_path}#{verbose_flag}"
313       puts
314     end
315
316     def run_bintest
317       puts ">>> Bintest #{name} <<<"
318       targets = @gems.select { |v| File.directory? "#{v.dir}/bintest" }.map { |v| filename v.dir }
319       targets << filename(".") if File.directory? "./bintest"
320       sh "ruby test/bintest.rb#{verbose_flag} #{targets.join ' '}"
321     end
322
323     def print_build_summary
324       puts "================================================"
325       puts "      Config Name: #{@name}"
326       puts " Output Directory: #{self.build_dir.relative_path}"
327       puts "         Binaries: #{@bins.join(', ')}" unless @bins.empty?
328       unless @gems.empty?
329         puts "    Included Gems:"
330         @gems.map do |gem|
331           gem_version = " - #{gem.version}" if gem.version != '0.0.0'
332           gem_summary = " - #{gem.summary}" if gem.summary
333           puts "             #{gem.name}#{gem_version}#{gem_summary}"
334           puts "               - Binaries: #{gem.bins.join(', ')}" unless gem.bins.empty?
335         end
336       end
337       puts "================================================"
338       puts
339     end
340
341     def libmruby_static
342       libfile("#{build_dir}/lib/libmruby")
343     end
344
345     def libmruby_core_static
346       libfile("#{build_dir}/lib/libmruby_core")
347     end
348
349     def libraries
350       [libmruby_static]
351     end
352   end # Build
353
354   class CrossBuild < Build
355     attr_block %w(test_runner)
356     # cross compiling targets for building native extensions.
357     # host  - arch of where the built binary will run
358     # build - arch of the machine building the binary
359     attr_accessor :host_target, :build_target
360
361     def initialize(name, build_dir=nil, &block)
362       @endian = nil
363       @test_runner = Command::CrossTestRunner.new(self)
364       super
365     end
366
367     def mrbcfile
368       MRuby.targets['host'].exefile("#{MRuby.targets['host'].build_dir}/bin/mrbc")
369     end
370
371     def run_test
372       @test_runner.runner_options << ' -v' if $verbose
373       mrbtest = exefile("#{build_dir}/bin/mrbtest")
374       if (@test_runner.command == nil)
375         puts "You should run #{mrbtest} on target device."
376         puts
377       else
378         @test_runner.run(mrbtest)
379       end
380     end
381
382     def big_endian
383       if @endian
384         puts "Endian has already specified as #{@endian}."
385         return
386       end
387       @endian = :big
388       @mrbc.compile_options += ' -E'
389       compilers.each do |c|
390         c.defines += %w(MRB_ENDIAN_BIG)
391       end
392     end
393
394     def little_endian
395       if @endian
396         puts "Endian has already specified as #{@endian}."
397         return
398       end
399       @endian = :little
400       @mrbc.compile_options += ' -e'
401     end
402   end # CrossBuild
403 end # MRuby