bake-toolkit 2.20.4 → 2.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile.rb +3 -3
  3. data/bin/bake +46 -46
  4. data/bin/bake-doc +11 -11
  5. data/bin/bakery +179 -179
  6. data/bin/createVSProjects +213 -213
  7. data/documentation/_build/html/_sources/changelog.txt +456 -451
  8. data/documentation/_build/html/_sources/commandline/commandline.txt +107 -107
  9. data/documentation/_build/html/_sources/concepts/build_hierarchy.txt +34 -34
  10. data/documentation/_build/html/_sources/concepts/concepts.txt +14 -14
  11. data/documentation/_build/html/_sources/concepts/inject.txt +65 -65
  12. data/documentation/_build/html/_sources/concepts/link_order.txt +91 -91
  13. data/documentation/_build/html/_sources/concepts/prebuild.txt +56 -56
  14. data/documentation/_build/html/_sources/concepts/the_main_project.txt +45 -45
  15. data/documentation/_build/html/_sources/concepts/the_project_meta_file.txt +72 -72
  16. data/documentation/_build/html/_sources/ide/eclipse/eclipse.txt +25 -25
  17. data/documentation/_build/html/_sources/ide/eclipse/how_to_convert_existing_cdt_workspace.txt +31 -31
  18. data/documentation/_build/html/_sources/ide/eclipse/how_to_create_a_new_project_in_eclipse.txt +18 -18
  19. data/documentation/_build/html/_sources/ide/eclipse/how_to_create_a_workspace_in_eclipse.txt +27 -27
  20. data/documentation/_build/html/_sources/ide/eclipse/how_to_debug_in_eclipse.txt +38 -38
  21. data/documentation/_build/html/_sources/ide/eclipse/how_to_install_eclipse_plugin.txt +44 -44
  22. data/documentation/_build/html/_sources/ide/eclipse/how_to_use_bake_in_eclipse.txt +86 -86
  23. data/documentation/_build/html/_sources/ide/ide_integrations.txt +8 -8
  24. data/documentation/_build/html/_sources/ide/vs/how_to_create_vs_projects.txt +15 -15
  25. data/documentation/_build/html/_sources/ide/vs/how_to_debug_in_vs.txt +35 -35
  26. data/documentation/_build/html/_sources/ide/vs/how_to_used_bake_in_vs.txt +35 -35
  27. data/documentation/_build/html/_sources/ide/vs/vs.txt +10 -10
  28. data/documentation/_build/html/_sources/ide/vs/vs_install.txt +43 -43
  29. data/documentation/_build/html/_sources/index.txt +33 -33
  30. data/documentation/_build/html/_sources/install/install_bake.txt +112 -112
  31. data/documentation/_build/html/_sources/internal.txt +50 -50
  32. data/documentation/_build/html/_sources/known_issues.txt +9 -9
  33. data/documentation/_build/html/_sources/license.txt +4 -4
  34. data/documentation/_build/html/_sources/performance/performance.txt +104 -104
  35. data/documentation/_build/html/_sources/quickstart/quickstart.txt +70 -70
  36. data/documentation/_build/html/_sources/syntax/adapt_configs.txt +143 -143
  37. data/documentation/_build/html/_sources/syntax/auto_adjustment.txt +43 -43
  38. data/documentation/_build/html/_sources/syntax/derive_configs.txt +93 -94
  39. data/documentation/_build/html/_sources/syntax/project_meta_syntax.txt +19 -19
  40. data/documentation/_build/html/_sources/syntax/syntax.txt +11 -11
  41. data/documentation/_build/html/_sources/syntax/variable_substitutions.txt +147 -147
  42. data/documentation/_build/html/_sources/tips_and_tricks/dot.txt +34 -34
  43. data/documentation/_build/html/_sources/tips_and_tricks/how_to_use_bake_with_cygwin.txt +62 -62
  44. data/documentation/_build/html/_sources/tips_and_tricks/static_code_analysis.txt +122 -122
  45. data/documentation/_build/html/_sources/tips_and_tricks/the_bakery.txt +72 -72
  46. data/documentation/_build/html/_sources/tips_and_tricks/the_clang.txt +43 -43
  47. data/documentation/_build/html/_sources/tips_and_tricks/tips_and_tricks.txt +34 -34
  48. data/documentation/_build/html/_sources/why_bake/why_bake.txt +40 -40
  49. data/documentation/_build/html/changelog.html +7 -0
  50. data/documentation/_build/html/commandline/commandline.html +2 -2
  51. data/documentation/_build/html/concepts/link_order.html +2 -2
  52. data/documentation/_build/html/concepts/prebuild.html +2 -2
  53. data/documentation/_build/html/index.html +4 -4
  54. data/documentation/_build/html/performance/performance.html +2 -2
  55. data/documentation/_build/html/searchindex.js +1 -1
  56. data/documentation/_build/html/syntax/adapt_configs.html +2 -2
  57. data/documentation/_build/html/syntax/syntax.html +2 -2
  58. data/documentation/_build/html/tips_and_tricks/the_clang.html +2 -2
  59. data/documentation/_build/html/why_bake/why_bake.html +2 -2
  60. data/lib/adapt/config/loader.rb +112 -112
  61. data/lib/bake/bundle.rb +158 -158
  62. data/lib/bake/cache.rb +179 -180
  63. data/lib/bake/config/checks.rb +68 -68
  64. data/lib/bake/config/loader.rb +363 -363
  65. data/lib/bake/libElement.rb +176 -176
  66. data/lib/bake/mergeConfig.rb +208 -208
  67. data/lib/bake/model/language.rb +45 -45
  68. data/lib/bake/model/loader.rb +99 -99
  69. data/lib/bake/model/metamodel.rb +307 -307
  70. data/lib/bake/model/metamodel_ext.rb +27 -27
  71. data/lib/bake/options/create.rb +95 -95
  72. data/lib/bake/options/options.rb +315 -310
  73. data/lib/bake/options/showDoc.rb +20 -20
  74. data/lib/bake/options/showLicense.rb +9 -9
  75. data/lib/bake/options/showToolchains.rb +38 -38
  76. data/lib/bake/options/usage.rb +79 -68
  77. data/lib/bake/subst.rb +313 -313
  78. data/lib/bake/toolchain/clang.rb +44 -44
  79. data/lib/bake/toolchain/clang_analyze.rb +31 -31
  80. data/lib/bake/toolchain/colorizing_formatter.rb +125 -125
  81. data/lib/bake/toolchain/diab.rb +53 -53
  82. data/lib/bake/toolchain/errorparser/diab_compiler_error_parser.rb +40 -40
  83. data/lib/bake/toolchain/errorparser/diab_linker_error_parser.rb +41 -41
  84. data/lib/bake/toolchain/errorparser/error_parser.rb +71 -71
  85. data/lib/bake/toolchain/errorparser/gcc_compiler_error_parser.rb +35 -35
  86. data/lib/bake/toolchain/errorparser/gcc_linker_error_parser.rb +35 -35
  87. data/lib/bake/toolchain/errorparser/greenhills_compiler_error_parser.rb +32 -32
  88. data/lib/bake/toolchain/errorparser/greenhills_linker_error_parser.rb +44 -44
  89. data/lib/bake/toolchain/errorparser/keil_compiler_error_parser.rb +40 -40
  90. data/lib/bake/toolchain/errorparser/keil_linker_error_parser.rb +30 -30
  91. data/lib/bake/toolchain/errorparser/lint_error_parser.rb +34 -34
  92. data/lib/bake/toolchain/errorparser/msvc_compiler_error_parser.rb +63 -63
  93. data/lib/bake/toolchain/errorparser/msvc_linker_error_parser.rb +42 -42
  94. data/lib/bake/toolchain/errorparser/process_output.rb +2 -2
  95. data/lib/bake/toolchain/errorparser/ti_compiler_error_parser.rb +30 -30
  96. data/lib/bake/toolchain/errorparser/ti_linker_error_parser.rb +30 -30
  97. data/lib/bake/toolchain/gcc.rb +49 -49
  98. data/lib/bake/toolchain/gcc_env.rb +55 -55
  99. data/lib/bake/toolchain/greenhills.rb +52 -52
  100. data/lib/bake/toolchain/keil.rb +53 -53
  101. data/lib/bake/toolchain/lint.rb +20 -20
  102. data/lib/bake/toolchain/msvc.rb +58 -58
  103. data/lib/bake/toolchain/provider.rb +146 -146
  104. data/lib/bake/toolchain/ti.rb +47 -47
  105. data/lib/bake/util.rb +149 -149
  106. data/lib/bakery/buildPattern.rb +24 -24
  107. data/lib/bakery/model/language.rb +22 -22
  108. data/lib/bakery/model/loader.rb +55 -55
  109. data/lib/bakery/model/metamodel.rb +48 -48
  110. data/lib/bakery/options/options.rb +87 -87
  111. data/lib/bakery/toBake.rb +81 -81
  112. data/lib/blocks/block.rb +324 -324
  113. data/lib/blocks/blockBase.rb +204 -204
  114. data/lib/blocks/commandLine.rb +38 -38
  115. data/lib/blocks/compile.rb +529 -528
  116. data/lib/blocks/convert.rb +41 -41
  117. data/lib/blocks/docu.rb +30 -30
  118. data/lib/blocks/executable.rb +174 -174
  119. data/lib/blocks/has_execute_command.rb +31 -31
  120. data/lib/blocks/library.rb +114 -114
  121. data/lib/blocks/lint.rb +56 -56
  122. data/lib/blocks/makefile.rb +100 -100
  123. data/lib/blocks/showIncludes.rb +140 -125
  124. data/lib/common/abortException.rb +4 -4
  125. data/lib/common/cleanup.rb +10 -10
  126. data/lib/common/exit_helper.rb +38 -38
  127. data/lib/common/ext/file.rb +88 -88
  128. data/lib/common/ext/rtext.rb +11 -11
  129. data/lib/common/ext/stdout.rb +45 -45
  130. data/lib/common/ide_interface.rb +194 -194
  131. data/lib/common/options/parser.rb +95 -85
  132. data/lib/common/process.rb +64 -64
  133. data/lib/common/utils.rb +52 -52
  134. data/lib/common/version.rb +31 -23
  135. data/lib/multithread/job.rb +44 -44
  136. data/lib/tocxx.rb +558 -555
  137. data/lib/vs/options.rb +69 -69
  138. data/license.txt +90 -90
  139. metadata +2 -2
@@ -1,529 +1,530 @@
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
- Blocks::CC2J << { :directory => @projectDir, :command => cmd, :file => source }
180
- end
181
-
182
- if not (cmdLineCheck and BlockBase.isCmdLineEqual?(cmd, cmdLineFile))
183
- BlockBase.prepareOutput(object)
184
- BlockBase.writeCmdLineFile(cmd, cmdLineFile)
185
- success, consoleOutput = ProcessHelper.run(cmd, false, false)
186
-
187
- outputType = Bake.options.analyze ? "Analyzing" : (Bake.options.prepro ? "Preprocessing" : "Compiling")
188
- incList = process_result(cmd, consoleOutput, compiler[:ERROR_PARSER], "#{outputType} #{source}", reason, success)
189
-
190
- if type != :ASM and not Bake.options.analyze and not Bake.options.prepro
191
- incList = Compile.read_depfile(dep_filename, @projectDir) if incList.nil?
192
- Compile.write_depfile(incList, dep_filename_conv)
193
- end
194
- check_config_file
195
- end
196
-
197
- Bake::Bundle.instance.addSource(source, @include_list, dep_filename_conv) if isMainProject?
198
-
199
- end
200
-
201
- def self.read_depfile(dep_filename, projDir)
202
- deps = []
203
- begin
204
- deps_string = File.read(dep_filename)
205
- if not (deps_string.include?" \\\n")
206
- deps_string.each_line do |line|
207
- splitted = line.split(": ")
208
- deps << splitted[1].gsub(/[\\]/,'/') if splitted.length > 1
209
- end
210
- else
211
- deps_string = deps_string.gsub(/\\\n/,'')
212
- dep_splitted = deps_string.split(/([^\\]) /).each_slice(2).map(&:join)[2..-1]
213
- deps = dep_splitted.map { |d| d.gsub(/[\\] /,' ').gsub(/[\\]/,'/').strip }.delete_if {|d| d == "" }
214
- end
215
- rescue Exception
216
- Bake.formatter.printWarning("Could not read '#{dep_filename}'", projDir)
217
- return nil
218
- end
219
- deps
220
- end
221
-
222
- # todo: move to toolchain util file
223
- def self.write_depfile(deps, dep_filename_conv)
224
- if deps
225
- begin
226
- File.open(dep_filename_conv, 'wb') do |f|
227
- deps.each do |dep|
228
- f.puts(dep)
229
- end
230
- end
231
- rescue Exception
232
- Bake.formatter.printWarning("Could not write '#{dep_filename_conv}'", projDir)
233
- return nil
234
- end
235
- end
236
- end
237
-
238
- def mutex
239
- @mutex ||= Mutex.new
240
- end
241
-
242
- def execute
243
- Dir.chdir(@projectDir) do
244
-
245
- calcSources
246
- calcObjects
247
-
248
- @incWarns.each do |x|
249
- 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])
250
- end if Bake.options.verbose >= 1
251
-
252
- @error_strings = {}
253
-
254
- compileJobs = Multithread::Jobs.new(@source_files) do |jobs|
255
- while source = jobs.get_next_or_nil do
256
-
257
- if (jobs.failed and Bake.options.stopOnFirstError) or Bake::IDEInterface.instance.get_abort
258
- break
259
- end
260
-
261
- s = StringIO.new
262
- tmp = Thread.current[:stdout]
263
- Thread.current[:stdout] = s unless tmp
264
-
265
- result = false
266
- begin
267
- compileFile(source)
268
- result = true
269
- rescue Bake::SystemCommandFailed => scf # normal compilation error
270
- rescue SystemExit => exSys
271
- rescue Exception => ex1
272
- if not Bake::IDEInterface.instance.get_abort
273
- Bake.formatter.printError("Error: #{ex1.message}")
274
- puts ex1.backtrace if Bake.options.debug
275
- end
276
- end
277
-
278
- jobs.set_failed if not result
279
-
280
- Thread.current[:stdout] = tmp
281
-
282
- mutex.synchronize do
283
- if s.string.length > 0
284
- if Bake.options.stopOnFirstError and not result
285
- @error_strings[source] = s.string
286
- else
287
- puts s.string
288
- end
289
- end
290
- end
291
-
292
- end
293
- end
294
- compileJobs.join
295
-
296
- # can only happen in case of bail_on_first_error.
297
- # if not sorted, it may be confusing when builing more than once and the order of the error appearances changes from build to build
298
- # (it is not deterministic which file compilation finishes first)
299
- @error_strings.sort.each {|es| puts es[1]}
300
-
301
- raise SystemCommandFailed.new if compileJobs.failed
302
-
303
-
304
- end
305
- return true
306
- end
307
-
308
- def clean
309
- if Bake.options.filename or Bake.options.analyze
310
- Dir.chdir(@projectDir) do
311
- calcSources(true)
312
- @source_files.each do |source|
313
-
314
- type = get_source_type(source)
315
- next if type.nil?
316
- object = get_object_file(source)
317
- if File.exist?object
318
- puts "Deleting file #{object}" if Bake.options.verbose >= 2
319
- FileUtils.rm_rf(object)
320
- end
321
- if not Bake.options.analyze
322
- dep_filename = calcDepFile(object, type)
323
- if dep_filename and File.exist?dep_filename
324
- puts "Deleting file #{dep_filename}" if Bake.options.verbose >= 2
325
- FileUtils.rm_rf(dep_filename)
326
- end
327
- cmdLineFile = calcCmdlineFile(object)
328
- if File.exist?cmdLineFile
329
- puts "Deleting file #{cmdLineFile}" if Bake.options.verbose >= 2
330
- FileUtils.rm_rf(cmdLineFile)
331
- end
332
- end
333
- end
334
- end
335
- end
336
- return true
337
- end
338
-
339
- def calcObjects
340
- @source_files.each do |source|
341
- type = get_source_type(source)
342
- if not type.nil?
343
- object = get_object_file(source)
344
- if @objects.include?object
345
- @object_files.each do |k,v|
346
- if (v == object) # will be found exactly once
347
- Bake.formatter.printError("Source files '#{k}' and '#{source}' would result in the same object file", source)
348
- raise SystemCommandFailed.new
349
- end
350
- end
351
- end
352
- @object_files[source] = object
353
- @objects << object
354
- end
355
- end
356
- end
357
-
358
- def calcSources(cleaning = false, keep = false)
359
- return @source_files if @source_files and not @source_files.empty?
360
- Dir.chdir(@projectDir) do
361
- @source_files = []
362
-
363
- exclude_files = Set.new
364
- @config.excludeFiles.each do |p|
365
- Dir.glob(p.name).each {|f| exclude_files << f}
366
- end
367
-
368
- source_files = Set.new
369
- @config.files.each do |sources|
370
- p = sources.name
371
- res = Dir.glob(p).sort
372
- if res.length == 0 and cleaning == false
373
- if not p.include?"*" and not p.include?"?"
374
- Bake.formatter.printError("Source file '#{p}' not found", sources)
375
- raise SystemCommandFailed.new
376
- elsif Bake.options.verbose >= 1
377
- Bake.formatter.printInfo("Source file pattern '#{p}' does not match to any file", sources)
378
- end
379
- end
380
- res.each do |f|
381
- next if exclude_files.include?(f)
382
- next if source_files.include?(f)
383
- source_files << f
384
- @source_files << f
385
- end
386
- end
387
-
388
- if Bake.options.filename
389
- @source_files.keep_if do |source|
390
- source.include?Bake.options.filename
391
- end
392
- if @source_files.length == 0 and cleaning == false
393
- Bake.formatter.printInfo("#{Bake.options.filename} does not match to any source", @config)
394
- end
395
- end
396
-
397
- if Bake.options.eclipseOrder # directories reverse order, files in directories in alphabetical order
398
- dirs = []
399
- filemap = {}
400
- @source_files.sort.reverse.each do |o|
401
- d = File.dirname(o)
402
- if filemap.include?(d)
403
- filemap[d] << o
404
- else
405
- filemap[d] = [o]
406
- dirs << d
407
- end
408
- end
409
- @source_files = []
410
- dirs.each do |d|
411
- filemap[d].reverse.each do |f|
412
- @source_files << f
413
- end
414
- end
415
- end
416
- end
417
- @source_files
418
- end
419
-
420
- def mapInclude(inc, orgBlock)
421
-
422
- if inc.name == "___ROOTS___"
423
- return Bake.options.roots.map { |r| File.rel_from_to_project(@projectDir,r,false) }
424
- end
425
-
426
- i = orgBlock.convPath(inc,nil,true)
427
- if orgBlock != @block
428
- if not File.is_absolute?(i)
429
- i = File.rel_from_to_project(@projectDir,orgBlock.config.parent.get_project_dir) + i
430
- end
431
- end
432
-
433
- x = Pathname.new(i).cleanpath
434
- if orgBlock.warnConvValid
435
- @incWarns << [inc, x]
436
- end
437
- x
438
- end
439
-
440
- def calcIncludes
441
- @incWarns = []
442
-
443
- @include_list = @config.includeDir.uniq.map do |dir|
444
- mapInclude(dir, @block)
445
- end
446
-
447
- @block.getBlocks(:childs).each do |b|
448
- b.config.includeDir.each do |inc|
449
- if inc.inherit == true
450
- @include_list << mapInclude(inc, b)
451
- end
452
- end if b.config.respond_to?("includeDir")
453
- end
454
-
455
- @block.getBlocks(:parents).each do |b|
456
- if b.config.respond_to?("includeDir")
457
- include_list_front = []
458
- b.config.includeDir.each do |inc|
459
- if inc.inject == "front"
460
- include_list_front << mapInclude(inc, b)
461
- elsif inc.inject == "back"
462
- @include_list << mapInclude(inc, b)
463
- elsif inc.infix == "front"
464
- include_list_front << mapInclude(inc, b)
465
- elsif inc.infix == "back"
466
- @include_list << mapInclude(inc, b)
467
- end
468
- end
469
- @include_list = include_list_front + @include_list
470
- end
471
- end
472
-
473
- @include_list = @include_list.flatten.uniq
474
-
475
- @include_array = {}
476
- [:CPP, :C, :ASM].each do |type|
477
- @include_array[type] = @include_list.map {|k| "#{@tcs[:COMPILER][type][:INCLUDE_PATH_FLAG]}#{k}"}
478
- end
479
- end
480
-
481
- def getDefines(compiler)
482
- compiler[:DEFINES].map {|k| "#{compiler[:DEFINE_FLAG]}#{k}"}
483
- end
484
-
485
- def getFlags(compiler)
486
- Bake::Utils::flagSplit(compiler[:FLAGS],true)
487
- end
488
-
489
- def calcDefines
490
- @define_array = {}
491
- [:CPP, :C, :ASM].each do |type|
492
- @define_array[type] = getDefines(@tcs[:COMPILER][type])
493
- end
494
- end
495
- def calcFlags
496
- @flag_array = {}
497
- [:CPP, :C, :ASM].each do |type|
498
- @flag_array[type] = getFlags(@tcs[:COMPILER][type])
499
- end
500
- end
501
-
502
- def calcFileTcs
503
- @fileTcs = {}
504
- @config.files.each do |f|
505
- if (f.define.length > 0 or f.flags.length > 0)
506
- if f.name.include?"*"
507
- Bake.formatter.printWarning("Toolchain settings not allowed for file pattern #{f.name}", f)
508
- err_res = ErrorDesc.new
509
- err_res.file_name = @config.file_name
510
- err_res.line_number = f.line_number
511
- err_res.severity = ErrorParser::SEVERITY_WARNING
512
- err_res.message = "Toolchain settings not allowed for file patterns"
513
- Bake::IDEInterface.instance.set_errors([err_res])
514
- else
515
- @fileTcs[f.name] = integrateCompilerFile(Utils.deep_copy(@tcs),f)
516
- end
517
- end
518
- end
519
- end
520
-
521
- def tcs4source(source)
522
- @fileTcs[source] || @tcs
523
- end
524
-
525
-
526
- end
527
-
528
- 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) 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)
203
+ deps = []
204
+ begin
205
+ deps_string = File.read(dep_filename)
206
+ if not (deps_string.include?" \\\n")
207
+ deps_string.each_line do |line|
208
+ splitted = line.split(": ")
209
+ deps << splitted[1].gsub(/[\\]/,'/') if splitted.length > 1
210
+ end
211
+ else
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
217
+ Bake.formatter.printWarning("Could not read '#{dep_filename}'", projDir)
218
+ return nil
219
+ end
220
+ deps
221
+ end
222
+
223
+ # todo: move to toolchain util file
224
+ def self.write_depfile(deps, dep_filename_conv)
225
+ if deps
226
+ begin
227
+ File.open(dep_filename_conv, 'wb') do |f|
228
+ deps.each do |dep|
229
+ f.puts(dep)
230
+ end
231
+ end
232
+ rescue Exception
233
+ Bake.formatter.printWarning("Could not write '#{dep_filename_conv}'", projDir)
234
+ return nil
235
+ end
236
+ end
237
+ end
238
+
239
+ def mutex
240
+ @mutex ||= Mutex.new
241
+ end
242
+
243
+ def execute
244
+ Dir.chdir(@projectDir) do
245
+
246
+ calcSources
247
+ calcObjects
248
+
249
+ @incWarns.each do |x|
250
+ 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])
251
+ end if Bake.options.verbose >= 1
252
+
253
+ @error_strings = {}
254
+
255
+ compileJobs = Multithread::Jobs.new(@source_files) do |jobs|
256
+ while source = jobs.get_next_or_nil do
257
+
258
+ if (jobs.failed and Bake.options.stopOnFirstError) or Bake::IDEInterface.instance.get_abort
259
+ break
260
+ end
261
+
262
+ s = StringIO.new
263
+ tmp = Thread.current[:stdout]
264
+ Thread.current[:stdout] = s unless tmp
265
+
266
+ result = false
267
+ begin
268
+ compileFile(source)
269
+ result = true
270
+ rescue Bake::SystemCommandFailed => scf # normal compilation error
271
+ rescue SystemExit => exSys
272
+ rescue Exception => ex1
273
+ if not Bake::IDEInterface.instance.get_abort
274
+ Bake.formatter.printError("Error: #{ex1.message}")
275
+ puts ex1.backtrace if Bake.options.debug
276
+ end
277
+ end
278
+
279
+ jobs.set_failed if not result
280
+
281
+ Thread.current[:stdout] = tmp
282
+
283
+ mutex.synchronize do
284
+ if s.string.length > 0
285
+ if Bake.options.stopOnFirstError and not result
286
+ @error_strings[source] = s.string
287
+ else
288
+ puts s.string
289
+ end
290
+ end
291
+ end
292
+
293
+ end
294
+ end
295
+ compileJobs.join
296
+
297
+ # can only happen in case of bail_on_first_error.
298
+ # if not sorted, it may be confusing when builing more than once and the order of the error appearances changes from build to build
299
+ # (it is not deterministic which file compilation finishes first)
300
+ @error_strings.sort.each {|es| puts es[1]}
301
+
302
+ raise SystemCommandFailed.new if compileJobs.failed
303
+
304
+
305
+ end
306
+ return true
307
+ end
308
+
309
+ def clean
310
+ if Bake.options.filename or Bake.options.analyze
311
+ Dir.chdir(@projectDir) do
312
+ calcSources(true)
313
+ @source_files.each do |source|
314
+
315
+ type = get_source_type(source)
316
+ next if type.nil?
317
+ object = get_object_file(source)
318
+ if File.exist?object
319
+ puts "Deleting file #{object}" if Bake.options.verbose >= 2
320
+ FileUtils.rm_rf(object)
321
+ end
322
+ if not Bake.options.analyze
323
+ dep_filename = calcDepFile(object, type)
324
+ if dep_filename and File.exist?dep_filename
325
+ puts "Deleting file #{dep_filename}" if Bake.options.verbose >= 2
326
+ FileUtils.rm_rf(dep_filename)
327
+ end
328
+ cmdLineFile = calcCmdlineFile(object)
329
+ if File.exist?cmdLineFile
330
+ puts "Deleting file #{cmdLineFile}" if Bake.options.verbose >= 2
331
+ FileUtils.rm_rf(cmdLineFile)
332
+ end
333
+ end
334
+ end
335
+ end
336
+ end
337
+ return true
338
+ end
339
+
340
+ def calcObjects
341
+ @source_files.each do |source|
342
+ type = get_source_type(source)
343
+ if not type.nil?
344
+ object = get_object_file(source)
345
+ if @objects.include?object
346
+ @object_files.each do |k,v|
347
+ if (v == object) # will be found exactly once
348
+ Bake.formatter.printError("Source files '#{k}' and '#{source}' would result in the same object file", source)
349
+ raise SystemCommandFailed.new
350
+ end
351
+ end
352
+ end
353
+ @object_files[source] = object
354
+ @objects << object
355
+ end
356
+ end
357
+ end
358
+
359
+ def calcSources(cleaning = false, keep = false)
360
+ return @source_files if @source_files and not @source_files.empty?
361
+ Dir.chdir(@projectDir) do
362
+ @source_files = []
363
+
364
+ exclude_files = Set.new
365
+ @config.excludeFiles.each do |p|
366
+ Dir.glob(p.name).each {|f| exclude_files << f}
367
+ end
368
+
369
+ source_files = Set.new
370
+ @config.files.each do |sources|
371
+ p = sources.name
372
+ res = Dir.glob(p).sort
373
+ if res.length == 0 and cleaning == false
374
+ if not p.include?"*" and not p.include?"?"
375
+ Bake.formatter.printError("Source file '#{p}' not found", sources)
376
+ raise SystemCommandFailed.new
377
+ elsif Bake.options.verbose >= 1
378
+ Bake.formatter.printInfo("Source file pattern '#{p}' does not match to any file", sources)
379
+ end
380
+ end
381
+ res.each do |f|
382
+ next if exclude_files.include?(f)
383
+ next if source_files.include?(f)
384
+ source_files << f
385
+ @source_files << f
386
+ end
387
+ end
388
+
389
+ if Bake.options.filename
390
+ @source_files.keep_if do |source|
391
+ source.include?Bake.options.filename
392
+ end
393
+ if @source_files.length == 0 and cleaning == false
394
+ Bake.formatter.printInfo("#{Bake.options.filename} does not match to any source", @config)
395
+ end
396
+ end
397
+
398
+ if Bake.options.eclipseOrder # directories reverse order, files in directories in alphabetical order
399
+ dirs = []
400
+ filemap = {}
401
+ @source_files.sort.reverse.each do |o|
402
+ d = File.dirname(o)
403
+ if filemap.include?(d)
404
+ filemap[d] << o
405
+ else
406
+ filemap[d] = [o]
407
+ dirs << d
408
+ end
409
+ end
410
+ @source_files = []
411
+ dirs.each do |d|
412
+ filemap[d].reverse.each do |f|
413
+ @source_files << f
414
+ end
415
+ end
416
+ end
417
+ end
418
+ @source_files
419
+ end
420
+
421
+ def mapInclude(inc, orgBlock)
422
+
423
+ if inc.name == "___ROOTS___"
424
+ return Bake.options.roots.map { |r| File.rel_from_to_project(@projectDir,r,false) }
425
+ end
426
+
427
+ i = orgBlock.convPath(inc,nil,true)
428
+ if orgBlock != @block
429
+ if not File.is_absolute?(i)
430
+ i = File.rel_from_to_project(@projectDir,orgBlock.config.parent.get_project_dir) + i
431
+ end
432
+ end
433
+
434
+ x = Pathname.new(i).cleanpath
435
+ if orgBlock.warnConvValid
436
+ @incWarns << [inc, x]
437
+ end
438
+ x
439
+ end
440
+
441
+ def calcIncludes
442
+ @incWarns = []
443
+
444
+ @include_list = @config.includeDir.uniq.map do |dir|
445
+ mapInclude(dir, @block)
446
+ end
447
+
448
+ @block.getBlocks(:childs).each do |b|
449
+ b.config.includeDir.each do |inc|
450
+ if inc.inherit == true
451
+ @include_list << mapInclude(inc, b)
452
+ end
453
+ end if b.config.respond_to?("includeDir")
454
+ end
455
+
456
+ @block.getBlocks(:parents).each do |b|
457
+ if b.config.respond_to?("includeDir")
458
+ include_list_front = []
459
+ b.config.includeDir.each do |inc|
460
+ if inc.inject == "front"
461
+ include_list_front << mapInclude(inc, b)
462
+ elsif inc.inject == "back"
463
+ @include_list << mapInclude(inc, b)
464
+ elsif inc.infix == "front"
465
+ include_list_front << mapInclude(inc, b)
466
+ elsif inc.infix == "back"
467
+ @include_list << mapInclude(inc, b)
468
+ end
469
+ end
470
+ @include_list = include_list_front + @include_list
471
+ end
472
+ end
473
+
474
+ @include_list = @include_list.flatten.uniq
475
+
476
+ @include_array = {}
477
+ [:CPP, :C, :ASM].each do |type|
478
+ @include_array[type] = @include_list.map {|k| "#{@tcs[:COMPILER][type][:INCLUDE_PATH_FLAG]}#{k}"}
479
+ end
480
+ end
481
+
482
+ def getDefines(compiler)
483
+ compiler[:DEFINES].map {|k| "#{compiler[:DEFINE_FLAG]}#{k}"}
484
+ end
485
+
486
+ def getFlags(compiler)
487
+ Bake::Utils::flagSplit(compiler[:FLAGS],true)
488
+ end
489
+
490
+ def calcDefines
491
+ @define_array = {}
492
+ [:CPP, :C, :ASM].each do |type|
493
+ @define_array[type] = getDefines(@tcs[:COMPILER][type])
494
+ end
495
+ end
496
+ def calcFlags
497
+ @flag_array = {}
498
+ [:CPP, :C, :ASM].each do |type|
499
+ @flag_array[type] = getFlags(@tcs[:COMPILER][type])
500
+ end
501
+ end
502
+
503
+ def calcFileTcs
504
+ @fileTcs = {}
505
+ @config.files.each do |f|
506
+ if (f.define.length > 0 or f.flags.length > 0)
507
+ if f.name.include?"*"
508
+ Bake.formatter.printWarning("Toolchain settings not allowed for file pattern #{f.name}", f)
509
+ err_res = ErrorDesc.new
510
+ err_res.file_name = @config.file_name
511
+ err_res.line_number = f.line_number
512
+ err_res.severity = ErrorParser::SEVERITY_WARNING
513
+ err_res.message = "Toolchain settings not allowed for file patterns"
514
+ Bake::IDEInterface.instance.set_errors([err_res])
515
+ else
516
+ @fileTcs[f.name] = integrateCompilerFile(Utils.deep_copy(@tcs),f)
517
+ end
518
+ end
519
+ end
520
+ end
521
+
522
+ def tcs4source(source)
523
+ @fileTcs[source] || @tcs
524
+ end
525
+
526
+
527
+ end
528
+
529
+ end
529
530
  end