bake-toolkit 2.24.0 → 2.24.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,531 +1,521 @@
1
- require 'blocks/blockBase'
2
- require 'multithread/job'
3
- require 'common/process'
4
- require 'common/utils'
5
- require 'bake/toolchain/colorizing_formatter'
6
- require 'bake/config/loader'
7
-
8
- module Bake
9
-
10
- module Blocks
11
-
12
- class Compile < BlockBase
13
-
14
- attr_reader :objects, :include_list
15
-
16
- def initialize(block, config, referencedConfigs, tcs)
17
- super(block, config, referencedConfigs, tcs)
18
- @objects = []
19
- @object_files = {}
20
-
21
- calcFileTcs
22
- calcIncludes
23
- calcDefines # not for files with changed tcs
24
- calcFlags # not for files with changed tcs
25
- end
26
-
27
- def get_object_file(source)
28
-
29
- # until now all OBJECT_FILE_ENDING are equal in all three types
30
- adaptedSource = source.chomp(File.extname(source)).gsub(/\.\./, "##") + (Bake.options.prepro ? ".i" : @tcs[:COMPILER][:CPP][:OBJECT_FILE_ENDING])
31
- return adaptedSource if File.is_absolute?source
32
- File.join([@output_dir, adaptedSource])
33
- end
34
-
35
- def ignore?(type)
36
- Bake.options.linkOnly or (Bake.options.prepro and type == :ASM)
37
- end
38
-
39
- def needed?(source, object, type, dep_filename_conv)
40
- return "because analyzer toolchain is configured" if Bake.options.analyze
41
- return "because prepro was specified and source is no assembler file" if Bake.options.prepro
42
-
43
- return "because object does not exist" if not File.exist?(object)
44
- oTime = File.mtime(object)
45
-
46
- return "because source is newer than object" if oTime < File.mtime(source)
47
-
48
- if type != :ASM
49
- return "because dependency file does not exist" if not File.exist?(dep_filename_conv)
50
-
51
- begin
52
- File.readlines(dep_filename_conv).map{|line| line.strip}.each do |dep|
53
- if not File.exist?(dep)
54
- # we need a hack here. with some windows configurations the compiler prints unix paths
55
- # into the dep file which cannot be found easily. this will be true for system includes,
56
- # e.g. /usr/lib/...xy.h
57
- if (Bake::Utils::OS.windows? and dep.start_with?"/") or
58
- (not Bake::Utils::OS.windows? and dep.length > 1 and dep[1] == ":")
59
- puts "Dependency header file #{dep} ignored!" if Bake.options.debug
60
- else
61
- return "because dependent header #{dep} does not exist"
62
- end
63
- else
64
- return "because dependent header #{dep} is newer than object" if oTime < File.mtime(dep)
65
- end
66
- end
67
- rescue Exception => ex
68
- if Bake.options.debug
69
- puts "While reading #{dep_filename_conv}:"
70
- puts ex.message
71
- puts ex.backtrace
72
- end
73
- return "because dependency file could not be loaded"
74
- end
75
- end
76
-
77
- false
78
- end
79
-
80
- def calcCmdlineFile(object)
81
- object[0..-3] + ".cmdline"
82
- end
83
-
84
- def calcDepFile(object, type)
85
- dep_filename = nil
86
- if type != :ASM
87
- dep_filename = object[0..-3] + ".d"
88
- end
89
- dep_filename
90
- end
91
-
92
- def calcDepFileConv(dep_filename)
93
- dep_filename + ".bake"
94
- end
95
-
96
- def get_source_type(source)
97
- ex = File.extname(source)
98
- [:CPP, :C, :ASM].each do |t|
99
- return t if @tcs[:COMPILER][t][:SOURCE_FILE_ENDINGS].include?(ex)
100
- end
101
- nil
102
- end
103
-
104
- def compileFile(source)
105
- type = get_source_type(source)
106
- return if type.nil?
107
-
108
- object = @object_files[source]
109
-
110
- dep_filename = calcDepFile(object, type)
111
- dep_filename_conv = calcDepFileConv(dep_filename) if type != :ASM
112
-
113
- cmdLineCheck = false
114
- cmdLineFile = calcCmdlineFile(object)
115
-
116
- return if ignore?(type)
117
- reason = needed?(source, object, type, dep_filename_conv)
118
- if not reason
119
- cmdLineCheck = true
120
- reason = config_changed?(cmdLineFile)
121
- end
122
-
123
- if @fileTcs.include?(source)
124
- compiler = @fileTcs[source][:COMPILER][type]
125
- defines = getDefines(compiler)
126
- flags = getFlags(compiler)
127
- else
128
- compiler = @tcs[:COMPILER][type]
129
- defines = @define_array[type]
130
- flags = @flag_array[type]
131
- end
132
- includes = @include_array[type]
133
-
134
- if Bake.options.prepro and compiler[:PREPRO_FLAGS] == ""
135
- Bake.formatter.printError("Error: No preprocessor option available for " + source)
136
- raise SystemCommandFailed.new
137
- end
138
-
139
- cmd = Utils.flagSplit(compiler[:COMMAND], false)
140
- cmd += compiler[:COMPILE_FLAGS].split(" ")
141
-
142
- if dep_filename
143
- cmd += @tcs[:COMPILER][type][:DEP_FLAGS].split(" ")
144
- if @tcs[:COMPILER][type][:DEP_FLAGS_FILENAME]
145
- if @tcs[:COMPILER][type][:DEP_FLAGS_SPACE]
146
- cmd << dep_filename
147
- else
148
- if dep_filename.include?" "
149
- cmd[cmd.length-1] << "\"" + dep_filename + "\""
150
- else
151
- cmd[cmd.length-1] << dep_filename
152
- end
153
-
154
- end
155
- end
156
- end
157
-
158
- cmd += compiler[:PREPRO_FLAGS].split(" ") if Bake.options.prepro
159
- cmd += flags
160
- cmd += includes
161
- cmd += defines
162
-
163
- offlag = compiler[:OBJECT_FILE_FLAG]
164
- offlag = compiler[:PREPRO_FILE_FLAG] if compiler[:PREPRO_FILE_FLAG] and Bake.options.prepro
165
-
166
- if compiler[:OBJ_FLAG_SPACE]
167
- cmd << offlag
168
- cmd << object
169
- else
170
- if object.include?" "
171
- cmd << offlag + "\"" + object + "\""
172
- else
173
- cmd << offlag + object
174
- end
175
- end
176
- cmd << source
177
-
178
- if Bake.options.cc2j_filename
179
- cmdJson = cmd.is_a?(Array) ? cmd.join(' ') : cmd
180
- Blocks::CC2J << { :directory => @projectDir, :command => cmdJson, :file => source }
181
- end
182
-
183
- if not (cmdLineCheck and BlockBase.isCmdLineEqual?(cmd, cmdLineFile))
184
- BlockBase.prepareOutput(object)
185
- BlockBase.writeCmdLineFile(cmd, cmdLineFile)
186
- success, consoleOutput = ProcessHelper.run(cmd, false, false)
187
-
188
- outputType = Bake.options.analyze ? "Analyzing" : (Bake.options.prepro ? "Preprocessing" : "Compiling")
189
- incList = process_result(cmd, consoleOutput, compiler[:ERROR_PARSER], "#{outputType} #{source}", reason, success)
190
-
191
- if type != :ASM and not Bake.options.analyze and not Bake.options.prepro
192
- incList = Compile.read_depfile(dep_filename, @projectDir, @tcs[:COMPILER][:DEP_FILE_SINGLE_LINE]) if incList.nil?
193
- Compile.write_depfile(incList, dep_filename_conv)
194
- end
195
- check_config_file
196
- end
197
-
198
- Bake::Bundle.instance.addSource(source, @include_list, dep_filename_conv) if isMainProject?
199
-
200
- end
201
-
202
- def self.read_depfile(dep_filename, projDir, singleLine)
203
- deps = []
204
- begin
205
- if singleLine
206
- File.readlines(dep_filename).each do |line|
207
- splitted = line.split(": ")
208
- deps << splitted[1].gsub(/[\\]/,'/') if splitted.length > 1
209
- end
210
- else
211
- deps_string = File.read(dep_filename)
212
- deps_string = deps_string.gsub(/\\\n/,'')
213
- dep_splitted = deps_string.split(/([^\\]) /).each_slice(2).map(&:join)[2..-1]
214
- deps = dep_splitted.map { |d| d.gsub(/[\\] /,' ').gsub(/[\\]/,'/').strip }.delete_if {|d| d == "" }
215
- end
216
- rescue Exception => ex1
217
- Bake.formatter.printWarning("Could not read '#{dep_filename}'", projDir)
218
- puts ex1.message if Bake.options.debug
219
- return nil
220
- end
221
- deps
222
- end
223
-
224
- # todo: move to toolchain util file
225
- def self.write_depfile(deps, dep_filename_conv)
226
- if deps
227
- begin
228
- File.open(dep_filename_conv, 'wb') do |f|
229
- deps.each do |dep|
230
- f.puts(dep)
231
- end
232
- end
233
- rescue Exception
234
- Bake.formatter.printWarning("Could not write '#{dep_filename_conv}'", projDir)
235
- return nil
236
- end
237
- end
238
- end
239
-
240
- def mutex
241
- @mutex ||= Mutex.new
242
- end
243
-
244
- def execute
245
- Dir.chdir(@projectDir) do
246
-
247
- calcSources
248
- calcObjects
249
-
250
- @incWarns.each do |x|
251
- Bake.formatter.printInfo("IncludeDir '#{x[0].name}' will be converted to '#{x[1]}' although local path exists. If not intended, use './#{x[0].name}'.", x[0])
252
- end if Bake.options.verbose >= 1
253
-
254
- @error_strings = {}
255
-
256
- compileJobs = Multithread::Jobs.new(@source_files) do |jobs|
257
- while source = jobs.get_next_or_nil do
258
-
259
- if (jobs.failed and Bake.options.stopOnFirstError) or Bake::IDEInterface.instance.get_abort
260
- break
261
- end
262
-
263
- s = StringIO.new
264
- tmp = Thread.current[:stdout]
265
- Thread.current[:stdout] = s unless tmp
266
-
267
- result = false
268
- begin
269
- compileFile(source)
270
- result = true
271
- rescue Bake::SystemCommandFailed => scf # normal compilation error
272
- rescue SystemExit => exSys
273
- rescue Exception => ex1
274
- if not Bake::IDEInterface.instance.get_abort
275
- Bake.formatter.printError("Error: #{ex1.message}")
276
- puts ex1.backtrace if Bake.options.debug
277
- end
278
- end
279
-
280
- jobs.set_failed if not result
281
-
282
- Thread.current[:stdout] = tmp
283
-
284
- mutex.synchronize do
285
- if s.string.length > 0
286
- if Bake.options.stopOnFirstError and not result
287
- @error_strings[source] = s.string
288
- else
289
- puts s.string
290
- end
291
- end
292
- end
293
-
294
- end
295
- end
296
- compileJobs.join
297
-
298
- # can only happen in case of bail_on_first_error.
299
- # if not sorted, it may be confusing when builing more than once and the order of the error appearances changes from build to build
300
- # (it is not deterministic which file compilation finishes first)
301
- @error_strings.sort.each {|es| puts es[1]}
302
-
303
- raise SystemCommandFailed.new if compileJobs.failed
304
-
305
-
306
- end
307
- return true
308
- end
309
-
310
- def clean
311
- if Bake.options.filename or Bake.options.analyze
312
- Dir.chdir(@projectDir) do
313
- calcSources(true)
314
- @source_files.each do |source|
315
-
316
- type = get_source_type(source)
317
- next if type.nil?
318
- object = get_object_file(source)
319
- if File.exist?object
320
- puts "Deleting file #{object}" if Bake.options.verbose >= 2
321
- FileUtils.rm_rf(object)
322
- end
323
- if not Bake.options.analyze
324
- dep_filename = calcDepFile(object, type)
325
- if dep_filename and File.exist?dep_filename
326
- puts "Deleting file #{dep_filename}" if Bake.options.verbose >= 2
327
- FileUtils.rm_rf(dep_filename)
328
- end
329
- cmdLineFile = calcCmdlineFile(object)
330
- if File.exist?cmdLineFile
331
- puts "Deleting file #{cmdLineFile}" if Bake.options.verbose >= 2
332
- FileUtils.rm_rf(cmdLineFile)
333
- end
334
- end
335
- end
336
- end
337
- end
338
- return true
339
- end
340
-
341
- def calcObjects
342
- @source_files.each do |source|
343
- type = get_source_type(source)
344
- if not type.nil?
345
- object = get_object_file(source)
346
- if @objects.include?object
347
- @object_files.each do |k,v|
348
- if (v == object) # will be found exactly once
349
- Bake.formatter.printError("Source files '#{k}' and '#{source}' would result in the same object file", source)
350
- raise SystemCommandFailed.new
351
- end
352
- end
353
- end
354
- @object_files[source] = object
355
- @objects << object
356
- end
357
- end
358
- end
359
-
360
- def calcSources(cleaning = false, keep = false)
361
- return @source_files if @source_files and not @source_files.empty?
362
- Dir.chdir(@projectDir) do
363
- @source_files = []
364
-
365
- exclude_files = Set.new
366
- @config.excludeFiles.each do |p|
367
- Dir.glob(p.name).each {|f| exclude_files << f}
368
- end
369
-
370
- source_files = Set.new
371
- @config.files.each do |sources|
372
- p = sources.name
373
- res = Dir.glob(p).sort
374
- if res.length == 0 and cleaning == false
375
- if not p.include?"*" and not p.include?"?"
376
- Bake.formatter.printError("Source file '#{p}' not found", sources)
377
- raise SystemCommandFailed.new
378
- elsif Bake.options.verbose >= 1
379
- Bake.formatter.printInfo("Source file pattern '#{p}' does not match to any file", sources)
380
- end
381
- end
382
- res.each do |f|
383
- next if exclude_files.include?(f)
384
- next if source_files.include?(f)
385
- source_files << f
386
- @source_files << f
387
- end
388
- end
389
-
390
- if Bake.options.filename
391
- @source_files.keep_if do |source|
392
- source.include?Bake.options.filename
393
- end
394
- if @source_files.length == 0 and cleaning == false
395
- Bake.formatter.printInfo("#{Bake.options.filename} does not match to any source", @config)
396
- end
397
- end
398
-
399
- if Bake.options.eclipseOrder # directories reverse order, files in directories in alphabetical order
400
- dirs = []
401
- filemap = {}
402
- @source_files.sort.reverse.each do |o|
403
- d = File.dirname(o)
404
- if filemap.include?(d)
405
- filemap[d] << o
406
- else
407
- filemap[d] = [o]
408
- dirs << d
409
- end
410
- end
411
- @source_files = []
412
- dirs.each do |d|
413
- filemap[d].reverse.each do |f|
414
- @source_files << f
415
- end
416
- end
417
- end
418
- end
419
- @source_files
420
- end
421
-
422
- def mapInclude(inc, orgBlock)
423
-
424
- if inc.name == "___ROOTS___"
425
- return Bake.options.roots.map { |r| File.rel_from_to_project(@projectDir,r,false) }
426
- end
427
-
428
- i = orgBlock.convPath(inc,nil,true)
429
- if orgBlock != @block
430
- if not File.is_absolute?(i)
431
- i = File.rel_from_to_project(@projectDir,orgBlock.config.parent.get_project_dir) + i
432
- end
433
- end
434
-
435
- x = Pathname.new(i).cleanpath
436
- if orgBlock.warnConvValid
437
- @incWarns << [inc, x]
438
- end
439
- x
440
- end
441
-
442
- def calcIncludes
443
- @incWarns = []
444
-
445
- @include_list = @config.includeDir.uniq.map do |dir|
446
- mapInclude(dir, @block)
447
- end
448
-
449
- @block.getBlocks(:childs).each do |b|
450
- b.config.includeDir.each do |inc|
451
- if inc.inherit == true
452
- @include_list << mapInclude(inc, b)
453
- end
454
- end if b.config.respond_to?("includeDir")
455
- end
456
-
457
- @block.getBlocks(:parents).each do |b|
458
- if b.config.respond_to?("includeDir")
459
- include_list_front = []
460
- b.config.includeDir.each do |inc|
461
- if inc.inject == "front"
462
- include_list_front << mapInclude(inc, b)
463
- elsif inc.inject == "back"
464
- @include_list << mapInclude(inc, b)
465
- elsif inc.infix == "front"
466
- include_list_front << mapInclude(inc, b)
467
- elsif inc.infix == "back"
468
- @include_list << mapInclude(inc, b)
469
- end
470
- end
471
- @include_list = include_list_front + @include_list
472
- end
473
- end
474
-
475
- @include_list = @include_list.flatten.uniq
476
-
477
- @include_array = {}
478
- [:CPP, :C, :ASM].each do |type|
479
- @include_array[type] = @include_list.map {|k| "#{@tcs[:COMPILER][type][:INCLUDE_PATH_FLAG]}#{k}"}
480
- end
481
- end
482
-
483
- def getDefines(compiler)
484
- compiler[:DEFINES].map {|k| "#{compiler[:DEFINE_FLAG]}#{k}"}
485
- end
486
-
487
- def getFlags(compiler)
488
- Bake::Utils::flagSplit(compiler[:FLAGS],true)
489
- end
490
-
491
- def calcDefines
492
- @define_array = {}
493
- [:CPP, :C, :ASM].each do |type|
494
- @define_array[type] = getDefines(@tcs[:COMPILER][type])
495
- end
496
- end
497
- def calcFlags
498
- @flag_array = {}
499
- [:CPP, :C, :ASM].each do |type|
500
- @flag_array[type] = getFlags(@tcs[:COMPILER][type])
501
- end
502
- end
503
-
504
- def calcFileTcs
505
- @fileTcs = {}
506
- @config.files.each do |f|
507
- if (f.define.length > 0 or f.flags.length > 0)
508
- if f.name.include?"*"
509
- Bake.formatter.printWarning("Toolchain settings not allowed for file pattern #{f.name}", f)
510
- err_res = ErrorDesc.new
511
- err_res.file_name = @config.file_name
512
- err_res.line_number = f.line_number
513
- err_res.severity = ErrorParser::SEVERITY_WARNING
514
- err_res.message = "Toolchain settings not allowed for file patterns"
515
- Bake::IDEInterface.instance.set_errors([err_res])
516
- else
517
- @fileTcs[f.name] = integrateCompilerFile(Utils.deep_copy(@tcs),f)
518
- end
519
- end
520
- end
521
- end
522
-
523
- def tcs4source(source)
524
- @fileTcs[source] || @tcs
525
- end
526
-
527
-
528
- end
529
-
530
- end
1
+ require 'blocks/blockBase'
2
+ require 'multithread/job'
3
+ require 'common/process'
4
+ require 'common/utils'
5
+ require 'bake/toolchain/colorizing_formatter'
6
+ require 'bake/config/loader'
7
+
8
+ module Bake
9
+
10
+ module Blocks
11
+
12
+ class Compile < BlockBase
13
+
14
+ attr_reader :objects, :include_list
15
+
16
+ def initialize(block, config, referencedConfigs, tcs)
17
+ super(block, config, referencedConfigs, tcs)
18
+ @objects = []
19
+ @object_files = {}
20
+
21
+ calcFileTcs
22
+ calcIncludes
23
+ calcDefines # not for files with changed tcs
24
+ calcFlags # not for files with changed tcs
25
+ end
26
+
27
+ def get_object_file(source)
28
+
29
+ # until now all OBJECT_FILE_ENDING are equal in all three types
30
+ adaptedSource = source.chomp(File.extname(source)).gsub(/\.\./, "##") + (Bake.options.prepro ? ".i" : @tcs[:COMPILER][:CPP][:OBJECT_FILE_ENDING])
31
+ return adaptedSource if File.is_absolute?source
32
+ File.join([@output_dir, adaptedSource])
33
+ end
34
+
35
+ def ignore?(type)
36
+ Bake.options.linkOnly or (Bake.options.prepro and type == :ASM)
37
+ end
38
+
39
+ def needed?(source, object, type, dep_filename_conv)
40
+ return "because analyzer toolchain is configured" if Bake.options.analyze
41
+ return "because prepro was specified and source is no assembler file" if Bake.options.prepro
42
+
43
+ return "because object does not exist" if not File.exist?(object)
44
+ oTime = File.mtime(object)
45
+
46
+ return "because source is newer than object" if oTime < File.mtime(source)
47
+
48
+ if type != :ASM
49
+ return "because dependency file does not exist" if not File.exist?(dep_filename_conv)
50
+
51
+ begin
52
+ File.readlines(dep_filename_conv).map{|line| line.strip}.each do |dep|
53
+ if not File.exist?(dep)
54
+ # we need a hack here. with some windows configurations the compiler prints unix paths
55
+ # into the dep file which cannot be found easily. this will be true for system includes,
56
+ # e.g. /usr/lib/...xy.h
57
+ if (Bake::Utils::OS.windows? and dep.start_with?"/") or
58
+ (not Bake::Utils::OS.windows? and dep.length > 1 and dep[1] == ":")
59
+ puts "Dependency header file #{dep} ignored!" if Bake.options.debug
60
+ else
61
+ return "because dependent header #{dep} does not exist"
62
+ end
63
+ else
64
+ return "because dependent header #{dep} is newer than object" if oTime < File.mtime(dep)
65
+ end
66
+ end
67
+ rescue Exception => ex
68
+ if Bake.options.debug
69
+ puts "While reading #{dep_filename_conv}:"
70
+ puts ex.message
71
+ puts ex.backtrace
72
+ end
73
+ return "because dependency file could not be loaded"
74
+ end
75
+ end
76
+
77
+ false
78
+ end
79
+
80
+ def calcCmdlineFile(object)
81
+ object[0..-3] + ".cmdline"
82
+ end
83
+
84
+ def calcDepFile(object, type)
85
+ dep_filename = nil
86
+ if type != :ASM
87
+ dep_filename = object[0..-3] + ".d"
88
+ end
89
+ dep_filename
90
+ end
91
+
92
+ def calcDepFileConv(dep_filename)
93
+ dep_filename + ".bake"
94
+ end
95
+
96
+ def get_source_type(source)
97
+ ex = File.extname(source)
98
+ [:CPP, :C, :ASM].each do |t|
99
+ return t if @tcs[:COMPILER][t][:SOURCE_FILE_ENDINGS].include?(ex)
100
+ end
101
+ nil
102
+ end
103
+
104
+ def compileFile(source)
105
+ type = get_source_type(source)
106
+ return if type.nil?
107
+
108
+ object = @object_files[source]
109
+
110
+ dep_filename = calcDepFile(object, type)
111
+ dep_filename_conv = calcDepFileConv(dep_filename) if type != :ASM
112
+
113
+ cmdLineCheck = false
114
+ cmdLineFile = calcCmdlineFile(object)
115
+
116
+ return if ignore?(type)
117
+ reason = needed?(source, object, type, dep_filename_conv)
118
+ if not reason
119
+ cmdLineCheck = true
120
+ reason = config_changed?(cmdLineFile)
121
+ end
122
+
123
+ if @fileTcs.include?(source)
124
+ compiler = @fileTcs[source][:COMPILER][type]
125
+ defines = getDefines(compiler)
126
+ flags = getFlags(compiler)
127
+ else
128
+ compiler = @tcs[:COMPILER][type]
129
+ defines = @define_array[type]
130
+ flags = @flag_array[type]
131
+ end
132
+ includes = @include_array[type]
133
+
134
+ if Bake.options.prepro and compiler[:PREPRO_FLAGS] == ""
135
+ Bake.formatter.printError("Error: No preprocessor option available for " + source)
136
+ raise SystemCommandFailed.new
137
+ end
138
+
139
+ cmd = Utils.flagSplit(compiler[:COMMAND], false)
140
+ cmd += compiler[:COMPILE_FLAGS].split(" ")
141
+
142
+ if dep_filename
143
+ cmd += @tcs[:COMPILER][type][:DEP_FLAGS].split(" ")
144
+ if @tcs[:COMPILER][type][:DEP_FLAGS_FILENAME]
145
+ if @tcs[:COMPILER][type][:DEP_FLAGS_SPACE]
146
+ cmd << dep_filename
147
+ else
148
+ if dep_filename.include?" "
149
+ cmd[cmd.length-1] << "\"" + dep_filename + "\""
150
+ else
151
+ cmd[cmd.length-1] << dep_filename
152
+ end
153
+
154
+ end
155
+ end
156
+ end
157
+
158
+ cmd += compiler[:PREPRO_FLAGS].split(" ") if Bake.options.prepro
159
+ cmd += flags
160
+ cmd += includes
161
+ cmd += defines
162
+
163
+ offlag = compiler[:OBJECT_FILE_FLAG]
164
+ offlag = compiler[:PREPRO_FILE_FLAG] if compiler[:PREPRO_FILE_FLAG] and Bake.options.prepro
165
+
166
+ if compiler[:OBJ_FLAG_SPACE]
167
+ cmd << offlag
168
+ cmd << object
169
+ else
170
+ if object.include?" "
171
+ cmd << offlag + "\"" + object + "\""
172
+ else
173
+ cmd << offlag + object
174
+ end
175
+ end
176
+ cmd << source
177
+
178
+ if Bake.options.cc2j_filename
179
+ cmdJson = cmd.is_a?(Array) ? cmd.join(' ') : cmd
180
+ Blocks::CC2J << { :directory => @projectDir, :command => cmdJson, :file => source }
181
+ end
182
+
183
+ if not (cmdLineCheck and BlockBase.isCmdLineEqual?(cmd, cmdLineFile))
184
+ BlockBase.prepareOutput(object)
185
+ BlockBase.writeCmdLineFile(cmd, cmdLineFile)
186
+ success, consoleOutput = ProcessHelper.run(cmd, false, false)
187
+
188
+ outputType = Bake.options.analyze ? "Analyzing" : (Bake.options.prepro ? "Preprocessing" : "Compiling")
189
+ incList = process_result(cmd, consoleOutput, compiler[:ERROR_PARSER], "#{outputType} #{source}", reason, success)
190
+
191
+ if type != :ASM and not Bake.options.analyze and not Bake.options.prepro
192
+ incList = Compile.read_depfile(dep_filename, @projectDir, @tcs[:COMPILER][:DEP_FILE_SINGLE_LINE]) if incList.nil?
193
+ Compile.write_depfile(incList, dep_filename_conv)
194
+ end
195
+ check_config_file
196
+ end
197
+
198
+ Bake::Bundle.instance.addSource(source, @include_list, dep_filename_conv) if isMainProject?
199
+
200
+ end
201
+
202
+ def self.read_depfile(dep_filename, projDir, singleLine)
203
+ deps = []
204
+ begin
205
+ if singleLine
206
+ File.readlines(dep_filename).each do |line|
207
+ splitted = line.split(": ")
208
+ deps << splitted[1].gsub(/[\\]/,'/') if splitted.length > 1
209
+ end
210
+ else
211
+ deps_string = File.read(dep_filename)
212
+ deps_string = deps_string.gsub(/\\\n/,'')
213
+ dep_splitted = deps_string.split(/([^\\]) /).each_slice(2).map(&:join)[2..-1]
214
+ deps = dep_splitted.map { |d| d.gsub(/[\\] /,' ').gsub(/[\\]/,'/').strip }.delete_if {|d| d == "" }
215
+ end
216
+ rescue Exception => ex1
217
+ Bake.formatter.printWarning("Could not read '#{dep_filename}'", projDir)
218
+ puts ex1.message if Bake.options.debug
219
+ return nil
220
+ end
221
+ deps
222
+ end
223
+
224
+ # todo: move to toolchain util file
225
+ def self.write_depfile(deps, dep_filename_conv)
226
+ if deps
227
+ begin
228
+ File.open(dep_filename_conv, 'wb') do |f|
229
+ deps.each do |dep|
230
+ f.puts(dep)
231
+ end
232
+ end
233
+ rescue Exception
234
+ Bake.formatter.printWarning("Could not write '#{dep_filename_conv}'", projDir)
235
+ return nil
236
+ end
237
+ end
238
+ end
239
+
240
+ def mutex
241
+ @mutex ||= Mutex.new
242
+ end
243
+
244
+ def execute
245
+ Dir.chdir(@projectDir) do
246
+
247
+ calcSources
248
+ calcObjects
249
+
250
+ @error_strings = {}
251
+
252
+ compileJobs = Multithread::Jobs.new(@source_files) do |jobs|
253
+ while source = jobs.get_next_or_nil do
254
+
255
+ if (jobs.failed and Bake.options.stopOnFirstError) or Bake::IDEInterface.instance.get_abort
256
+ break
257
+ end
258
+
259
+ s = StringIO.new
260
+ tmp = Thread.current[:stdout]
261
+ Thread.current[:stdout] = s unless tmp
262
+
263
+ result = false
264
+ begin
265
+ compileFile(source)
266
+ result = true
267
+ rescue Bake::SystemCommandFailed => scf # normal compilation error
268
+ rescue SystemExit => exSys
269
+ rescue Exception => ex1
270
+ if not Bake::IDEInterface.instance.get_abort
271
+ Bake.formatter.printError("Error: #{ex1.message}")
272
+ puts ex1.backtrace if Bake.options.debug
273
+ end
274
+ end
275
+
276
+ jobs.set_failed if not result
277
+
278
+ Thread.current[:stdout] = tmp
279
+
280
+ mutex.synchronize do
281
+ if s.string.length > 0
282
+ if Bake.options.stopOnFirstError and not result
283
+ @error_strings[source] = s.string
284
+ else
285
+ puts s.string
286
+ end
287
+ end
288
+ end
289
+
290
+ end
291
+ end
292
+ compileJobs.join
293
+
294
+ # can only happen in case of bail_on_first_error.
295
+ # if not sorted, it may be confusing when builing more than once and the order of the error appearances changes from build to build
296
+ # (it is not deterministic which file compilation finishes first)
297
+ @error_strings.sort.each {|es| puts es[1]}
298
+
299
+ raise SystemCommandFailed.new if compileJobs.failed
300
+
301
+
302
+ end
303
+ return true
304
+ end
305
+
306
+ def clean
307
+ if Bake.options.filename or Bake.options.analyze
308
+ Dir.chdir(@projectDir) do
309
+ calcSources(true)
310
+ @source_files.each do |source|
311
+
312
+ type = get_source_type(source)
313
+ next if type.nil?
314
+ object = get_object_file(source)
315
+ if File.exist?object
316
+ puts "Deleting file #{object}" if Bake.options.verbose >= 2
317
+ FileUtils.rm_rf(object)
318
+ end
319
+ if not Bake.options.analyze
320
+ dep_filename = calcDepFile(object, type)
321
+ if dep_filename and File.exist?dep_filename
322
+ puts "Deleting file #{dep_filename}" if Bake.options.verbose >= 2
323
+ FileUtils.rm_rf(dep_filename)
324
+ end
325
+ cmdLineFile = calcCmdlineFile(object)
326
+ if File.exist?cmdLineFile
327
+ puts "Deleting file #{cmdLineFile}" if Bake.options.verbose >= 2
328
+ FileUtils.rm_rf(cmdLineFile)
329
+ end
330
+ end
331
+ end
332
+ end
333
+ end
334
+ return true
335
+ end
336
+
337
+ def calcObjects
338
+ @source_files.each do |source|
339
+ type = get_source_type(source)
340
+ if not type.nil?
341
+ object = get_object_file(source)
342
+ if @objects.include?object
343
+ @object_files.each do |k,v|
344
+ if (v == object) # will be found exactly once
345
+ Bake.formatter.printError("Source files '#{k}' and '#{source}' would result in the same object file", source)
346
+ raise SystemCommandFailed.new
347
+ end
348
+ end
349
+ end
350
+ @object_files[source] = object
351
+ @objects << object
352
+ end
353
+ end
354
+ end
355
+
356
+ def calcSources(cleaning = false, keep = false)
357
+ return @source_files if @source_files and not @source_files.empty?
358
+ Dir.chdir(@projectDir) do
359
+ @source_files = []
360
+
361
+ exclude_files = Set.new
362
+ @config.excludeFiles.each do |p|
363
+ Dir.glob(p.name).each {|f| exclude_files << f}
364
+ end
365
+
366
+ source_files = Set.new
367
+ @config.files.each do |sources|
368
+ p = sources.name
369
+ res = Dir.glob(p).sort
370
+ if res.length == 0 and cleaning == false
371
+ if not p.include?"*" and not p.include?"?"
372
+ Bake.formatter.printError("Source file '#{p}' not found", sources)
373
+ raise SystemCommandFailed.new
374
+ elsif Bake.options.verbose >= 1
375
+ Bake.formatter.printInfo("Source file pattern '#{p}' does not match to any file", sources)
376
+ end
377
+ end
378
+ res.each do |f|
379
+ next if exclude_files.include?(f)
380
+ next if source_files.include?(f)
381
+ source_files << f
382
+ @source_files << f
383
+ end
384
+ end
385
+
386
+ if Bake.options.filename
387
+ @source_files.keep_if do |source|
388
+ source.include?Bake.options.filename
389
+ end
390
+ if @source_files.length == 0 and cleaning == false
391
+ Bake.formatter.printInfo("#{Bake.options.filename} does not match to any source", @config)
392
+ end
393
+ end
394
+
395
+ if Bake.options.eclipseOrder # directories reverse order, files in directories in alphabetical order
396
+ dirs = []
397
+ filemap = {}
398
+ @source_files.sort.reverse.each do |o|
399
+ d = File.dirname(o)
400
+ if filemap.include?(d)
401
+ filemap[d] << o
402
+ else
403
+ filemap[d] = [o]
404
+ dirs << d
405
+ end
406
+ end
407
+ @source_files = []
408
+ dirs.each do |d|
409
+ filemap[d].reverse.each do |f|
410
+ @source_files << f
411
+ end
412
+ end
413
+ end
414
+ end
415
+ @source_files
416
+ end
417
+
418
+ def mapInclude(inc, orgBlock)
419
+
420
+ if inc.name == "___ROOTS___"
421
+ return Bake.options.roots.map { |r| File.rel_from_to_project(@projectDir,r,false) }
422
+ end
423
+
424
+ i = orgBlock.convPath(inc,nil,true)
425
+ if orgBlock != @block
426
+ if not File.is_absolute?(i)
427
+ i = File.rel_from_to_project(@projectDir,orgBlock.config.parent.get_project_dir) + i
428
+ end
429
+ end
430
+
431
+ Pathname.new(i).cleanpath
432
+ end
433
+
434
+ def calcIncludes
435
+ @include_list = @config.includeDir.uniq.map do |dir|
436
+ mapInclude(dir, @block)
437
+ end
438
+
439
+ @block.getBlocks(:childs).each do |b|
440
+ b.config.includeDir.each do |inc|
441
+ if inc.inherit == true
442
+ @include_list << mapInclude(inc, b)
443
+ end
444
+ end if b.config.respond_to?("includeDir")
445
+ end
446
+
447
+ @block.getBlocks(:parents).each do |b|
448
+ if b.config.respond_to?("includeDir")
449
+ include_list_front = []
450
+ b.config.includeDir.each do |inc|
451
+ if inc.inject == "front"
452
+ include_list_front << mapInclude(inc, b)
453
+ elsif inc.inject == "back"
454
+ @include_list << mapInclude(inc, b)
455
+ elsif inc.infix == "front"
456
+ include_list_front << mapInclude(inc, b)
457
+ elsif inc.infix == "back"
458
+ @include_list << mapInclude(inc, b)
459
+ end
460
+ end
461
+ @include_list = include_list_front + @include_list
462
+ end
463
+ end
464
+
465
+ @include_list = @include_list.flatten.uniq
466
+
467
+ @include_array = {}
468
+ [:CPP, :C, :ASM].each do |type|
469
+ @include_array[type] = @include_list.map {|k| "#{@tcs[:COMPILER][type][:INCLUDE_PATH_FLAG]}#{k}"}
470
+ end
471
+ end
472
+
473
+ def getDefines(compiler)
474
+ compiler[:DEFINES].map {|k| "#{compiler[:DEFINE_FLAG]}#{k}"}
475
+ end
476
+
477
+ def getFlags(compiler)
478
+ Bake::Utils::flagSplit(compiler[:FLAGS],true)
479
+ end
480
+
481
+ def calcDefines
482
+ @define_array = {}
483
+ [:CPP, :C, :ASM].each do |type|
484
+ @define_array[type] = getDefines(@tcs[:COMPILER][type])
485
+ end
486
+ end
487
+ def calcFlags
488
+ @flag_array = {}
489
+ [:CPP, :C, :ASM].each do |type|
490
+ @flag_array[type] = getFlags(@tcs[:COMPILER][type])
491
+ end
492
+ end
493
+
494
+ def calcFileTcs
495
+ @fileTcs = {}
496
+ @config.files.each do |f|
497
+ if (f.define.length > 0 or f.flags.length > 0)
498
+ if f.name.include?"*"
499
+ Bake.formatter.printWarning("Toolchain settings not allowed for file pattern #{f.name}", f)
500
+ err_res = ErrorDesc.new
501
+ err_res.file_name = @config.file_name
502
+ err_res.line_number = f.line_number
503
+ err_res.severity = ErrorParser::SEVERITY_WARNING
504
+ err_res.message = "Toolchain settings not allowed for file patterns"
505
+ Bake::IDEInterface.instance.set_errors([err_res])
506
+ else
507
+ @fileTcs[f.name] = integrateCompilerFile(Utils.deep_copy(@tcs),f)
508
+ end
509
+ end
510
+ end
511
+ end
512
+
513
+ def tcs4source(source)
514
+ @fileTcs[source] || @tcs
515
+ end
516
+
517
+
518
+ end
519
+
520
+ end
531
521
  end