bake-toolkit 1.0.1

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.
@@ -0,0 +1,66 @@
1
+ require 'cxxproject/utils/printer'
2
+ require 'cxxproject/utils/exit_helper'
3
+
4
+ module Cxxproject
5
+
6
+
7
+ class Option
8
+ attr_reader :param, :arg, :block
9
+ def initialize(param, arg, &f)
10
+ @param = param
11
+ @arg = arg # true / false
12
+ @block = f
13
+ f
14
+
15
+ end
16
+ end
17
+
18
+
19
+ class Parser
20
+
21
+ def initialize(argv)
22
+ @options = {}
23
+ @argv = argv
24
+ end
25
+
26
+ def add_option(opt)
27
+ @options[opt.param] = opt
28
+ end
29
+
30
+ def parse_internal(ignoreInvalid = true)
31
+ pos = 0
32
+ begin
33
+ while pos < @argv.length do
34
+ if not @options.include?@argv[pos]
35
+ if ignoreInvalid
36
+ pos = pos + 1
37
+ next
38
+ end
39
+ raise "Option #{@argv[pos]} unknown"
40
+ end
41
+ option = @options[@argv[pos]]
42
+ if option.arg
43
+ if pos+1 < @argv.length and @argv[pos+1][0] != "-"
44
+ option.block.call(@argv[pos+1])
45
+ pos = pos + 1
46
+ else
47
+ raise "Argument for option #{@argv[pos]} missing"
48
+ end
49
+ else
50
+ option.block.call()
51
+ end
52
+ pos = pos + 1
53
+ end
54
+ rescue SystemExit => e
55
+ raise
56
+ rescue Exception => e
57
+ Printer.printError e.message
58
+ ExitHelper.exit(1)
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+
65
+
66
+ end
data/lib/tocxx.rb ADDED
@@ -0,0 +1,883 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ gem 'rake', '>= 0.7.3'
4
+
5
+ require 'rake'
6
+ require 'rake/clean'
7
+ require 'bake/loader'
8
+ require 'bake/model/metamodel_ext'
9
+ require 'bake/util'
10
+ require 'bake/cache'
11
+ require 'bake/subst'
12
+ require 'cxxproject/buildingblocks/module'
13
+ require 'cxxproject/buildingblocks/makefile'
14
+ require 'cxxproject/buildingblocks/executable'
15
+ require 'cxxproject/buildingblocks/source_library'
16
+ require 'cxxproject/buildingblocks/binary_library'
17
+ require 'cxxproject/buildingblocks/custom_building_block'
18
+ require 'cxxproject/buildingblocks/command_line'
19
+ require 'cxxproject/buildingblocks/single_source'
20
+ require 'cxxproject/utils/exit_helper'
21
+ require 'cxxproject/ide_interface'
22
+ require 'cxxproject/ext/file'
23
+ require 'cxxproject/toolchain/provider'
24
+ require 'cxxproject/ext/stdout'
25
+ require 'cxxproject/ext/rake'
26
+ require 'cxxproject/utils/utils'
27
+ require 'cxxproject/utils/printer'
28
+
29
+ require 'set'
30
+ require 'socket'
31
+
32
+ #require 'ruby-prof'
33
+
34
+ module Cxxproject
35
+
36
+ class ToCxx
37
+
38
+ def initialize(options)
39
+ @options = options
40
+
41
+ RakeFileUtils.verbose_flag = @options.verbose
42
+ end
43
+
44
+ def set_output_taskname(bb)
45
+ return if not bb.instance_of?ModuleBuildingBlock
46
+ outputTaskname = task "Print #{bb.get_task_name}" do
47
+ num = Rake.application.idei.get_number_of_projects
48
+ @numCurrent ||= 0
49
+ @numCurrent += 1
50
+
51
+ unless @options.printLess
52
+ Printer.printAdditionalInfo "**** Building #{@numCurrent} of #{num}: #{bb.name.gsub("Project ","")} (#{bb.config_name}) ****"
53
+ end
54
+
55
+ Rake.application.idei.set_build_info(bb.name.gsub("Project ",""), bb.config_name)
56
+ Rake.application.addEmptyLine = true if @options.verbose
57
+ end
58
+ outputTaskname.type = Rake::Task::UTIL
59
+ outputTaskname.transparent_timestamp = true
60
+ insertAt = 0
61
+ t = Rake.application[bb.last_content.get_task_name]
62
+ t.prerequisites.each do |p|
63
+ pname = String === p ? p : p.name
64
+ if pname.index("Project ") == 0
65
+ insertAt = insertAt + 1
66
+ else
67
+ break
68
+ end
69
+ end
70
+ t.prerequisites.insert(insertAt, outputTaskname)
71
+ end
72
+
73
+
74
+ def calc_needed_bbs(bbChildName, needed_bbs)
75
+ bbChild = ALL_BUILDING_BLOCKS[bbChildName]
76
+ isModule = (ModuleBuildingBlock === bbChild ? 1 : 0)
77
+ return 0 if needed_bbs.include?bbChild
78
+ needed_bbs << bbChild
79
+ bbChild.dependencies.each { |d| isModule += calc_needed_bbs(d, needed_bbs) }
80
+ return isModule
81
+ end
82
+
83
+ # PRE and POST CONDITIONS
84
+ def addSteps(steps, bbModule, projDir, globalFilterStr = nil)
85
+ if steps
86
+ array = (Metamodel::Step === steps ? [steps] : steps.step)
87
+ array.reverse.each do |m|
88
+
89
+ checkDefault = true
90
+ if m.filter != "" # explicit filter = 1. prio
91
+ next if @options.exclude_filter.include?m.filter
92
+ checkDefault = false if @options.include_filter.include?m.filter
93
+ end
94
+
95
+ if globalFilterStr != nil
96
+ if checkDefault == true # global filter = 2. prio
97
+ next if @options.exclude_filter.include?globalFilterStr
98
+ checkDefault = false if @options.include_filter.include?globalFilterStr
99
+ end
100
+ end
101
+
102
+ if checkDefault # default = 3. prio
103
+ next if m.default == "off"
104
+ end
105
+
106
+ if Cxxproject::Metamodel::Makefile === m
107
+ nameOfBB = m.name+"_"+m.target
108
+ bb = Makefile.new(m.name, m.target)
109
+ if m.pathTo != ""
110
+ pathHash = {}
111
+ m.pathTo.split(",").each do |p|
112
+ nameOfP = p.strip
113
+ dirOfP = nil
114
+ if not @project2config.include?nameOfP
115
+ @options.roots.each do |r|
116
+ absIncDir = r+"/"+nameOfP
117
+ if File.exists?(absIncDir)
118
+ dirOfP = absIncDir
119
+ break
120
+ end
121
+ end
122
+ else
123
+ dirOfP = @project2config[nameOfP].parent.get_project_dir
124
+ end
125
+ if dirOfP == nil
126
+ Printer.printError "Error: Project '#{nameOfP}' not found for makefile #{projDir}/#{m.name}"
127
+ ExitHelper.exit(1)
128
+ end
129
+ pathHash[nameOfP] = File.rel_from_to_project(File.dirname(projDir),File.dirname(dirOfP))
130
+ end
131
+ bb.set_path_to(pathHash)
132
+ bb.pre_step = true if globalFilterStr
133
+ end
134
+ bb.set_flags(m.flags)
135
+ @lib_elements[m.line_number] = [HasLibraries::LIB_WITH_PATH, m.lib] if m.lib != ""
136
+ elsif Cxxproject::Metamodel::CommandLine === m
137
+ nameOfBB = m.name
138
+ bb = CommandLine.new(nameOfBB)
139
+ bb.set_defined_in_file(m.file_name.to_s)
140
+ bb.set_defined_in_line(m.line_number)
141
+ bb.pre_step = true if globalFilterStr
142
+ else
143
+ next
144
+ end
145
+ bbModule.last_content.dependencies << bb.name
146
+ bbModule.contents << bb
147
+ bbModule.last_content = bb
148
+ end
149
+ end
150
+ end
151
+
152
+ def convPath(dir, config, exe = nil)
153
+ projName = config.parent.name
154
+ projDir = config.parent.get_project_dir
155
+
156
+ d = dir.respond_to?("name") ? dir.name : dir
157
+ inc = d.split("/")
158
+ if (inc[0] == projName)
159
+ res = inc[1..-1].join("/") # within self
160
+ res = "." if res == ""
161
+ elsif @project2config.include?(inc[0])
162
+ dirOther = @project2config[inc[0]].parent.get_project_dir
163
+ res = File.rel_from_to_project(projDir, dirOther)
164
+ postfix = inc[1..-1].join("/")
165
+ res = res + postfix if postfix != ""
166
+ else
167
+ if (inc[0] != "..")
168
+ return d if File.exists?(projDir + "/" + d) # e.g. "include"
169
+
170
+ # check if dir exists without Project.meta entry
171
+ @options.roots.each do |r|
172
+ absIncDir = r+"/"+d
173
+ if File.exists?(absIncDir)
174
+ res = File.rel_from_to_project(projDir,absIncDir)
175
+ if not res.nil?
176
+ return res
177
+ end
178
+ end
179
+ end
180
+ else
181
+ Printer.printInfo "Info: #{projName} uses \"..\" in path name #{d}"
182
+ end
183
+
184
+ res = d # relative from self as last resort
185
+ end
186
+ res
187
+ end
188
+
189
+ def loadProjMeta(loader, filename, configname)
190
+
191
+ @project_files << filename
192
+ f = loader.load(filename)
193
+
194
+ config = nil
195
+
196
+ if f.root_elements.length != 1 or not Metamodel::Project === f.root_elements[0]
197
+ Printer.printError "Error: '#{filename}' must have exactly one 'Project' element as root element"
198
+ ExitHelper.exit(1)
199
+ end
200
+
201
+ f.root_elements.each do |e|
202
+ x = e.getConfig
203
+ x.each do |y|
204
+ if y.name == configname
205
+ if config
206
+ Printer.printError "Error: Config '#{configname}' found more than once in '#{filename}'"
207
+ ExitHelper.exit(1)
208
+ end
209
+ config = y
210
+ else
211
+ e.removeGeneric("Config", y)
212
+ end
213
+ end
214
+ end
215
+ f.mark_changed
216
+ f.build_index
217
+
218
+ if not config
219
+ Printer.printError "Error: Config '#{configname}' not found in '#{filename}'"
220
+ ExitHelper.exit(1)
221
+ end
222
+
223
+ config
224
+ end
225
+
226
+ def load_meta
227
+
228
+ loader = Loader.new(@options)
229
+ @project_files = []
230
+
231
+ @project2config = {}
232
+
233
+ project2config_pending = {}
234
+ project2config_pending[@mainProjectName] = @options.build_config
235
+
236
+ while project2config_pending.length > 0
237
+
238
+ pname_toload = project2config_pending.keys[0]
239
+ cname_toload = project2config_pending[pname_toload]
240
+ project2config_pending.delete(pname_toload)
241
+
242
+
243
+ # check if file is in more than one root
244
+ pmeta_filenames = []
245
+ @options.roots.each do |r|
246
+ f = r + "/" + pname_toload + "/Project.meta"
247
+ if File.exists?(f)
248
+ pmeta_filenames << f
249
+ end
250
+ end
251
+
252
+ if pmeta_filenames.empty?
253
+ Printer.printError "Error: #{pname_toload}/Project.meta not found"
254
+ ExitHelper.exit(1)
255
+ end
256
+
257
+ if pmeta_filenames.length > 1
258
+ Printer.printWarning "Warning: #{pname_toload} exists more than once:"
259
+ chosen = " (chosen)"
260
+ pmeta_filenames.each do |f|
261
+ Printer.printWarning " #{f}#{chosen}"
262
+ chosen = ""
263
+ end
264
+ end
265
+
266
+
267
+ config = loadProjMeta(loader, pmeta_filenames[0], cname_toload)
268
+
269
+ @project2config[pname_toload] = config
270
+
271
+ project2configLocal = {}
272
+
273
+ if @project2config.length == 1
274
+ if config.defaultToolchain == nil
275
+ Printer.printError "Error: Main project configuration must contain DefaultToolchain"
276
+ ExitHelper.exit(1)
277
+ else
278
+ basedOnToolchain = Cxxproject::Toolchain::Provider[config.defaultToolchain.basedOn]
279
+ if basedOnToolchain == nil
280
+ Printer.printError "Error: DefaultToolchain based on unknown compiler '#{config.defaultToolchain.basedOn}'"
281
+ ExitHelper.exit(1)
282
+ end
283
+ @defaultToolchain = Utils.deep_copy(basedOnToolchain)
284
+ integrateToolchain(@defaultToolchain, config.defaultToolchain)
285
+
286
+ if @defaultToolchainCached
287
+ unless @defaultToolchain[:LINKER][:FLAGS] == @defaultToolchainCached[:LINKER][:FLAGS] and
288
+ @defaultToolchain[:LINKER][:LIB_PREFIX_FLAGS] == @defaultToolchainCached[:LINKER][:LIB_PREFIX_FLAGS] and
289
+ @defaultToolchain[:LINKER][:LIB_POSTFIX_FLAGS] == @defaultToolchainCached[:LINKER][:LIB_POSTFIX_FLAGS] and
290
+ @defaultToolchain[:ARCHIVER][:FLAGS] == @defaultToolchainCached[:ARCHIVER][:FLAGS] and
291
+ @defaultToolchain[:COMPILER][:CPP][:FLAGS] == @defaultToolchainCached[:COMPILER][:CPP][:FLAGS] and
292
+ @defaultToolchain[:COMPILER][:CPP][:DEFINES].join("") == @defaultToolchainCached[:COMPILER][:CPP][:DEFINES].join("") and
293
+ @defaultToolchain[:COMPILER][:C][:FLAGS] == @defaultToolchainCached[:COMPILER][:C][:FLAGS] and
294
+ @defaultToolchain[:COMPILER][:C][:DEFINES].join("") == @defaultToolchainCached[:COMPILER][:C][:DEFINES].join("") and
295
+ @defaultToolchain[:COMPILER][:ASM][:FLAGS] == @defaultToolchainCached[:COMPILER][:ASM][:FLAGS] and
296
+ @defaultToolchain[:COMPILER][:ASM][:DEFINES].join("") == @defaultToolchainCached[:COMPILER][:ASM][:DEFINES].join("")
297
+ @defaultToolchainTime = @mainMetaTime
298
+ end
299
+ end
300
+
301
+ end
302
+ end
303
+
304
+ config.dependency.each do |d|
305
+ pname = d.name
306
+ cname = d.config
307
+
308
+ # check that a project is not dependent twice
309
+ if project2configLocal.include?pname
310
+ Printer.printError "Error: More than one dependencies found to '#{pname}' in config '#{config.name}'"
311
+ ExitHelper.exit(1)
312
+ end
313
+ project2configLocal[pname] = cname
314
+
315
+ # check pending loads
316
+ inconsistentConfigs = nil
317
+ if @project2config.include?pname
318
+ inconsistentConfigs = @project2config[pname].name if @project2config[pname].name != cname
319
+ else
320
+ if project2config_pending.include?pname
321
+ if project2config_pending[pname] != cname
322
+ inconsistentConfigs = project2config_pending[pname]
323
+ end
324
+ else
325
+ project2config_pending[pname] = cname
326
+ end
327
+ end
328
+ if inconsistentConfigs
329
+ Printer.printError "Error: dependency to config '#{cname}' of project '#{pname}' found (line #{d.line_number}), but config #{inconsistentConfigs} was requested earlier"
330
+ ExitHelper.exit(1)
331
+ end
332
+ end
333
+ end
334
+
335
+ end
336
+
337
+
338
+ def substVars
339
+ @project2config.each do |projName, config|
340
+ Subst.itute(config, projName, @options)
341
+ end
342
+
343
+ @mainConfig = @project2config[@mainProjectName]
344
+
345
+ basedOnToolchain = Cxxproject::Toolchain::Provider[@mainConfig.defaultToolchain.basedOn]
346
+ @defaultToolchain = Utils.deep_copy(basedOnToolchain)
347
+ integrateToolchain(@defaultToolchain, @mainConfig.defaultToolchain)
348
+
349
+ end
350
+
351
+ def convert2bb
352
+
353
+ @project2config.each do |projName, config|
354
+
355
+ projDir = config.parent.get_project_dir
356
+ @lib_elements = {}
357
+
358
+ bbModule = ModuleBuildingBlock.new("Project "+projName)
359
+ bbModule.contents = []
360
+
361
+ addSteps(config.postSteps, bbModule, projDir, "POST") if not @options.linkOnly
362
+
363
+ # LIB, EXE
364
+ if Metamodel::LibraryConfig === config
365
+ bbModule.main_content = SourceLibrary.new(projName)
366
+ elsif Metamodel::ExecutableConfig === config
367
+ bbModule.main_content = Executable.new(projName)
368
+ if not config.artifactName.nil?
369
+ x = @options.build_config + "/" + config.artifactName.name
370
+ bbModule.main_content.set_executable_name(x)
371
+ end
372
+ bbModule.main_content.set_linker_script(config.linkerScript.name) unless config.linkerScript.nil?
373
+ else # CUSTOM
374
+ if config.step
375
+ if config.step.filter != ""
376
+ Printer.printError "Error: #{config.file_name}(#{config.step.line_number}): attribute filter not allowed here"
377
+ ExitHelper.exit(1)
378
+ end
379
+ if config.step.default != "on"
380
+ Printer.printError "Error: #{config.file_name}(#{config.step.line_number}): attribute default not allowed here"
381
+ ExitHelper.exit(1)
382
+ end
383
+ addSteps(config.step, bbModule, projDir)
384
+ end
385
+ bbModule.main_content = BinaryLibrary.new(projName, false)
386
+ end
387
+ bbModule.last_content.dependencies << bbModule.main_content.name
388
+ bbModule.last_content = bbModule.main_content
389
+ bbModule.contents << bbModule.main_content
390
+
391
+ # PRE CONDITIONS
392
+ addSteps(config.preSteps, bbModule, projDir, "PRE") if not @options.linkOnly
393
+
394
+
395
+ tcs = nil
396
+ if not Metamodel::CustomConfig === config
397
+ tcs = Utils.deep_copy(@defaultToolchain)
398
+ integrateToolchain(tcs, config.toolchain)
399
+ else
400
+ tcs = Utils.deep_copy(Cxxproject::Toolchain::Provider.default)
401
+ end
402
+
403
+
404
+ ([bbModule] + bbModule.contents).each do |c|
405
+ c.set_tcs(tcs)
406
+ if (@defaultToolchainTime <= File.mtime(config.file_name))
407
+ c.set_config_files([config.file_name])
408
+ else
409
+ xxx = file "ssss"
410
+ $defaultToolchainTime = @defaultToolchainTime
411
+ def xxx.timestamp
412
+ $defaultToolchainTime
413
+ end
414
+ def xxx.needed?
415
+ true
416
+ end
417
+ @defaultToolchainTime
418
+
419
+ c.set_config_files([config.file_name, "ssss"])
420
+ end
421
+ c.set_project_dir(projDir)
422
+
423
+ if projName == @mainProjectName
424
+ c.set_output_dir(@options.build_config)
425
+ else
426
+ c.set_output_dir(@options.build_config + "_" + @mainProjectName)
427
+ end
428
+ c.set_config_name(config.name)
429
+ end
430
+
431
+ if HasLibraries === bbModule.main_content
432
+ config.userLibrary.each do |l|
433
+ ln = l.lib
434
+ ls = nil
435
+ if l.lib.include?("/")
436
+ pos = l.lib.rindex("/")
437
+ ls = convPath(l.lib[0..pos-1], config)
438
+ ln = l.lib[pos+1..-1]
439
+ end
440
+ @lib_elements[l.line_number] = ls.nil? ? [] : [HasLibraries::SEARCH_PATH, ls]
441
+ @lib_elements[l.line_number].concat [HasLibraries::USERLIB, ln]
442
+ end
443
+
444
+ config.exLib.each do |exLib|
445
+ ln = exLib.name
446
+ ls = nil
447
+ if exLib.name.include?("/")
448
+ pos = exLib.name.rindex("/")
449
+ ls = convPath(exLib.name[0..pos-1], config)
450
+ ln = exLib.name[pos+1..-1]
451
+ end
452
+ if exLib.search
453
+ @lib_elements[exLib.line_number] = ls.nil? ? [] : [HasLibraries::SEARCH_PATH, ls]
454
+ @lib_elements[exLib.line_number].concat [HasLibraries::LIB, ln]
455
+ else
456
+ @lib_elements[exLib.line_number] = [HasLibraries::LIB_WITH_PATH, (ls.nil? ? ln : (ls + "/" + ln))]
457
+ end
458
+ end
459
+
460
+ config.exLibSearchPath.each do |exLibSP|
461
+ @lib_elements[exLibSP.line_number] = [HasLibraries::SEARCH_PATH, convPath(exLibSP, config)]
462
+ end
463
+ end
464
+
465
+ if HasSources === bbModule.main_content
466
+ srcs = config.files.map do |f|
467
+ f.name
468
+ end
469
+ ex_srcs = config.excludeFiles.map {|f| f.name}
470
+
471
+ bbModule.main_content.set_local_includes( config.includeDir.map do |dir|
472
+ convPath(dir, config)
473
+ end
474
+ )
475
+
476
+ bbModule.main_content.set_source_patterns(srcs)
477
+ bbModule.main_content.set_exclude_sources(ex_srcs)
478
+
479
+ tcsMapConverted = {}
480
+ srcs = config.files.each do |f|
481
+ if (f.define.length > 0 or f.flags.length > 0)
482
+ if f.name.include?"*"
483
+ Printer.printWarning "Warning: #{config.file_name}(#{f.line_number}): toolchain settings not allowed for file pattern #{f.name}"
484
+ err_res = ErrorDesc.new
485
+ err_res.file_name = config.file_name
486
+ err_res.line_number = f.line_number
487
+ err_res.severity = ErrorParser::SEVERITY_WARNING
488
+ err_res.message = "Toolchain settings not allowed for file patterns"
489
+ Rake.application.idei.set_errors([err_res])
490
+ else
491
+ tcsMapConverted[f.name] = integrateCompilerFile(Utils.deep_copy(tcs),f)
492
+ end
493
+ end
494
+ end
495
+ bbModule.main_content.set_tcs4source(tcsMapConverted)
496
+
497
+ end
498
+
499
+ # special exe stuff
500
+ if Metamodel::ExecutableConfig === config
501
+ if not config.mapFile.nil?
502
+ if config.mapFile.name == ""
503
+ exeName = bbModule.main_content.get_executable_name
504
+ mapfileName = exeName.chomp(File.extname(exeName)) + ".map"
505
+ else
506
+ mapfileName = config.mapFile.name
507
+ end
508
+
509
+ bbModule.main_content.set_mapfile(mapfileName)
510
+ end
511
+ end
512
+ bbModule.contents.each do |c|
513
+ if Cxxproject::CommandLine === c
514
+ cmdLine = convPath(c.get_command_line, config, bbModule.main_content)
515
+ if Cxxproject::OS.windows? # CommandLine "tool/abc.exe gaga" does not work --> / must be \\
516
+ maxPos = cmdLine.index(" ")
517
+ indexQuote = cmdLine.index("\"")
518
+ if indexQuote != nil and (maxPos == nil or indexQuote < maxPos)
519
+ maxPos = indexQuote
520
+ end
521
+ if maxPos != nil
522
+ cmdLine = cmdLine[0..maxPos-1].gsub("/","\\") + cmdLine[maxPos..-1]
523
+ end
524
+ end
525
+ c.set_command_line(cmdLine)
526
+ end
527
+ end
528
+
529
+ # DEPS
530
+ projDeps = config.dependency.map { |dd| "Project "+dd.name }
531
+ projDeps.concat(bbModule.main_content.dependencies)
532
+ bbModule.main_content.set_dependencies(projDeps)
533
+ config.dependency.each { |dd| @lib_elements[dd.line_number] = [HasLibraries::DEPENDENCY, dd.name] }
534
+
535
+
536
+ @lib_elements.sort.each do |x|
537
+ v = x[1]
538
+ elem = 0
539
+ while elem < v.length do
540
+ bbModule.main_content.add_lib_elements([v[elem..elem+1]])
541
+ elem = elem + 2
542
+ end
543
+ end
544
+
545
+ end
546
+
547
+ ALL_BUILDING_BLOCKS.each do |bbname,bb|
548
+ bb.complete_init
549
+ end
550
+
551
+ end
552
+
553
+ def showConfigNames()
554
+ loader = Loader.new(@options)
555
+
556
+ f = loader.load(@options.main_dir+"/Project.meta")
557
+
558
+ if f.root_elements.length != 1 or not Metamodel::Project === f.root_elements[0]
559
+ Printer.printError "Error: '#{filename}' must have exactly one 'Project' element as root element"
560
+ ExitHelper.exit(1)
561
+ end
562
+
563
+ validConfigs = []
564
+ f.root_elements[0].getConfig.each do |c|
565
+ validConfigs << c.name unless c.defaultToolchain.nil?
566
+ end
567
+ puts "Please specify a config name (with -b)!"
568
+ puts "Possible values are:"
569
+ if validConfigs.length > 0
570
+ validConfigs.each { |v| puts "* " + v }
571
+ else
572
+ puts " No main config found!"
573
+ end
574
+
575
+ ExitHelper.exit(0)
576
+ end
577
+
578
+ def doit()
579
+ parsingOk = false
580
+ ex = nil
581
+ begin
582
+ parsingOk = doit_internal
583
+ rescue Exception => e
584
+ ex = e
585
+ end
586
+ if not parsingOk and Rake.application.idei
587
+ Rake.application.idei.set_build_info(@mainProjectName, @options.build_config.nil? ? "Not set" : @options.build_config, 0)
588
+ err_res = ErrorDesc.new
589
+ err_res.file_name = @options.main_dir
590
+ err_res.line_number = 0
591
+ err_res.severity = ErrorParser::SEVERITY_ERROR
592
+ err_res.message = "Parsing configurations failed, see log output."
593
+ Rake.application.idei.set_errors([err_res])
594
+ end
595
+
596
+ raise ex if ex
597
+ parsingOk
598
+ end
599
+
600
+ def doit_internal()
601
+
602
+ @mainProjectName = File::basename(@options.main_dir)
603
+
604
+ if @options.build_config == ""
605
+ showConfigNames()
606
+ ExitHelper.exit(1)
607
+ end
608
+
609
+ @startupFilename = @options.filename
610
+
611
+ @mainMeta = @options.main_dir + "/Project.meta"
612
+
613
+ cache = CacheAccess.new(@mainMeta, @options.build_config, @options)
614
+
615
+ if File.exists? @mainMeta
616
+ @defaultToolchainTime = File.mtime(@mainMeta)
617
+ @mainMetaTime = @defaultToolchainTime
618
+ else
619
+ @defaultToolchainTime = Time.now
620
+ end
621
+
622
+ forceLoadMeta = @options.nocache
623
+
624
+ @defaultToolchainCached = nil
625
+
626
+ if not forceLoadMeta
627
+ @project2config = cache.load_cache
628
+ @defaultToolchainCached = cache.defaultToolchain
629
+ @defaultToolchainTime = cache.defaultToolchainTime unless cache.defaultToolchainTime.nil?
630
+ if @project2config.nil?
631
+ forceLoadMeta = true
632
+ else
633
+ @defaultToolchain = @defaultToolchainCached
634
+ end
635
+ end
636
+
637
+ if forceLoadMeta
638
+ load_meta
639
+ cache.write_cache(@project_files, @project2config, @defaultToolchain, @defaultToolchainTime)
640
+ end
641
+
642
+ substVars
643
+ convert2bb
644
+
645
+ #################################################
646
+
647
+ startBBName = "Project "+@options.project
648
+ startBB = ALL_BUILDING_BLOCKS[startBBName]
649
+ if startBB.nil?
650
+ Printer.printError "Error: Project #{@options.project} is not a dependency of #{@mainProjectName}"
651
+ ExitHelper.exit(1)
652
+ end
653
+
654
+
655
+ #################################################
656
+
657
+ if @options.single or @startupFilename
658
+ content_names = startBB.contents.map { |c| c.name }
659
+ startBB.main_content.set_helper_dependencies(startBB.main_content.dependencies.dup) if Executable === startBB.main_content
660
+ startBB.main_content.dependencies.delete_if { |d| not content_names.include?d}
661
+ end
662
+
663
+ if @startupFilename
664
+ startBB.contents.each do |c|
665
+ if SourceLibrary === c or Executable === c
666
+
667
+ # check that the file is REALLY included and glob if file does not exist and guess what file can be meant
668
+ Dir.chdir(startBB.project_dir) do
669
+
670
+ theFile = []
671
+ if not File.exists?(@startupFilename)
672
+ Dir.chdir(startBB.project_dir) do
673
+ theFile = Dir.glob("**/#{@startupFilename}")
674
+ end
675
+ if theFile.length == 0
676
+ Printer.printError "Error: #{@startupFilename} not found in project #{@options.project}"
677
+ ExitHelper.exit(1)
678
+ end
679
+ else
680
+ theFile << @startupFilename
681
+ end
682
+
683
+ exclude_files = []
684
+ c.exclude_sources.each do |e|
685
+ Dir.glob(e).each {|f| exclude_files << f}
686
+ end
687
+ theFile.delete_if { |f| exclude_files.any? {|e| e==f} }
688
+ if theFile.length == 0
689
+ Printer.printError "Error: #{@startupFilename} excluded in config #{@options.build_config} of project #{@options.project}"
690
+ ExitHelper.exit(1)
691
+ end
692
+
693
+ source_files = c.sources.dup
694
+ c.source_patterns.each do |p|
695
+ Dir.glob(p).each {|f| source_files << f}
696
+ end
697
+
698
+ theFile.delete_if { |f| source_files.all? {|e| e!=f} }
699
+ if theFile.length == 0
700
+ Printer.printError "Error: #{@startupFilename} is no source file in config #{@options.build_config} of project #{@options.project}"
701
+ ExitHelper.exit(1)
702
+ elsif theFile.length > 1
703
+ Printer.printError "Error: #{@startupFilename} is ambiguous in project #{@options.project}"
704
+ ExitHelper.exit(1)
705
+ else
706
+ @startupFilename = theFile[0]
707
+ end
708
+ end
709
+
710
+ c.set_sources([@startupFilename])
711
+ c.set_source_patterns([])
712
+ c.set_exclude_sources([])
713
+ c.extend(SingleSourceModule)
714
+ break
715
+ else
716
+ def c.needed?
717
+ false
718
+ end
719
+ end
720
+ end
721
+ end
722
+
723
+
724
+ Rake.application.check_unnecessary_includes = (@startupFilename == nil) if @options.check_uninc
725
+
726
+
727
+ #################################################
728
+
729
+
730
+ startBB.contents.each do |b|
731
+ if SourceLibrary === b or Executable === b or BinaryLibrary === b
732
+ @parseBB = b
733
+ end
734
+ end
735
+
736
+
737
+ @bbs = []
738
+ @num_modules = 1
739
+ if @options.single or @startupFilename
740
+ @bbs << startBB
741
+ @bbs.concat(startBB.contents)
742
+ else
743
+ @num_modules = calc_needed_bbs(startBBName, @bbs)
744
+ end
745
+
746
+ if @options.show_includes
747
+ @bbs.each do |bb|
748
+ if HasIncludes === bb
749
+ print bb.name
750
+ li = bb.local_includes
751
+ li.each { |i| print "##{i}" }
752
+ print "\n"
753
+ end
754
+ end
755
+ exit(0)
756
+ end
757
+
758
+ theExeBB = nil
759
+ @bbs.each do |bb|
760
+ res = bb.convert_to_rake()
761
+ theExeBB = res if Executable === bb
762
+ end
763
+
764
+ if @options.linkOnly
765
+ if theExeBB.nil?
766
+ Printer.printError "Error: no executable to link"
767
+ ExitHelper.exit(1)
768
+ else
769
+ theExeBB.prerequisites.delete_if {|p| Rake::Task::SOURCEMULTI == Rake.application[p].type}
770
+ end
771
+ end
772
+
773
+ @bbs.each do |bb|
774
+ set_output_taskname(bb)
775
+ end
776
+
777
+ if @startupFilename
778
+ runTaskName = @parseBB.get_task_name
779
+ else
780
+ runTaskName = startBB.get_task_name
781
+ end
782
+
783
+
784
+ @runTask = Rake.application[runTaskName]
785
+
786
+ if @startupFilename
787
+ @runTask.prerequisites.clear
788
+ end
789
+
790
+
791
+ #RubyProf.start
792
+ #result = RubyProf.stop
793
+ #printer = RubyProf::FlatPrinter.new(result)
794
+ #printer.print(STDOUT)
795
+
796
+
797
+ return true
798
+ end
799
+
800
+ def start()
801
+
802
+ if @options.clean
803
+ cleanTask = nil
804
+ if @startupFilename
805
+ Dir.chdir(@parseBB.project_dir) do
806
+
807
+ if File.is_absolute?(@startupFilename)
808
+ @startupFilename = File.rel_from_to_project(@parseBB.project_dir, @startupFilename, false)
809
+ end
810
+
811
+ of = @parseBB.get_object_file(@startupFilename)
812
+ object = File.expand_path(of)
813
+
814
+ FileUtils.rm object, :force => true
815
+ FileUtils.rm @parseBB.get_dep_file(object), :force => true
816
+ end
817
+ else
818
+ cleanTask = Rake.application["clean"]
819
+ cleanTask.invoke
820
+ end
821
+
822
+ if Rake.application.idei and Rake.application.idei.get_abort
823
+ Printer.printError "\nClean aborted."
824
+ return false
825
+ elsif cleanTask != nil and cleanTask.failure
826
+ Printer.printError "\nClean failed."
827
+ return false
828
+ elsif not @options.rebuild
829
+ Printer.printSuccess "\nClean done."
830
+ return true
831
+ end
832
+
833
+ end
834
+ Rake::application.idei.set_build_info(@parseBB.name, @parseBB.config_name, @num_modules)
835
+
836
+ @runTask.invoke
837
+
838
+ buildType = @options.rebuild ? "Rebuild" : "Build"
839
+
840
+ if Rake.application.idei and Rake.application.idei.get_abort
841
+ Printer.printError "\n#{buildType} aborted."
842
+ return false
843
+ elsif @runTask.failure
844
+ if Rake::application.preproFlags
845
+ Printer.printSuccess "\nPreprocessing done."
846
+ return true
847
+ else
848
+ Printer.printError "\n#{buildType} failed."
849
+ return false
850
+ end
851
+ else
852
+ text = ""
853
+ # this "fun part" shall not fail in any case!
854
+ begin
855
+ #if Time.now.year == 2012 and Time.now.month == 1
856
+ # text = " -- The munich software team wishes you a happy new year 2012!"
857
+ #end
858
+ rescue Exception
859
+ end
860
+ Printer.printSuccess("\n#{buildType} done." + text)
861
+ return true
862
+ end
863
+ end
864
+
865
+ def connect()
866
+ if @options.socket != 0
867
+ Rake.application.idei.connect(@options.socket)
868
+ end
869
+ end
870
+
871
+ def disconnect()
872
+ if @options.socket != 0
873
+ Rake.application.idei.disconnect()
874
+ end
875
+ end
876
+
877
+
878
+ end
879
+ end
880
+
881
+
882
+ # metamodel Files vs File vs Dir vs Make vs ... ? merge?
883
+