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