cxxproject 0.2 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/Rakefile.rb +55 -33
  2. data/bin/cxx +10 -0
  3. data/lib/cxxproject/buildingblocks/binary_library.rb +16 -0
  4. data/lib/cxxproject/buildingblocks/building_block.rb +93 -0
  5. data/lib/cxxproject/buildingblocks/command_line.rb +30 -0
  6. data/lib/cxxproject/buildingblocks/custom_building_block.rb +17 -0
  7. data/lib/cxxproject/buildingblocks/executable.rb +49 -0
  8. data/lib/cxxproject/buildingblocks/has_dependencies_mixin.rb +57 -0
  9. data/lib/cxxproject/buildingblocks/has_libraries_mixin.rb +35 -0
  10. data/lib/cxxproject/buildingblocks/has_sources_mixin.rb +85 -0
  11. data/lib/cxxproject/buildingblocks/makefile.rb +35 -0
  12. data/lib/cxxproject/buildingblocks/module.rb +14 -0
  13. data/lib/cxxproject/buildingblocks/single_source.rb +11 -0
  14. data/lib/cxxproject/buildingblocks/source_library.rb +31 -0
  15. data/lib/cxxproject/extensions/file_ext.rb +47 -0
  16. data/lib/cxxproject/extensions/rake_dirty_ext.rb +30 -0
  17. data/lib/cxxproject/extensions/rake_ext.rb +158 -0
  18. data/lib/cxxproject/extensions/rake_listener_ext.rb +53 -0
  19. data/lib/cxxproject/extensions/stdout_ext.rb +35 -0
  20. data/lib/cxxproject/extensions/string_ext.rb +9 -0
  21. data/lib/cxxproject/task_maker.rb +418 -0
  22. data/lib/cxxproject/testinstanceeval.rb +65 -0
  23. data/lib/cxxproject/toolchain/base.rb +98 -0
  24. data/lib/cxxproject/toolchain/diab.rb +47 -0
  25. data/lib/cxxproject/toolchain/gcc.rb +39 -0
  26. data/lib/cxxproject/toolchain/provider.rb +18 -0
  27. data/lib/cxxproject/torake/compiler.rb +10 -0
  28. data/lib/cxxproject/torake.rb +152 -0
  29. data/lib/cxxproject/utils/dot/building_block_graph_writer.rb +19 -0
  30. data/lib/cxxproject/utils/dot/graph_writer.rb +53 -0
  31. data/lib/cxxproject/utils/dot/task_graph_writer.rb +34 -0
  32. data/lib/cxxproject/utils/ubigraph.rb +237 -0
  33. data/lib/cxxproject/{utils.rb → utils/utils.rb} +19 -1
  34. data/lib/cxxproject.rb +13 -223
  35. data/lib/tools/Rakefile.rb.template +10 -0
  36. data/lib/tools/project.rb.template +6 -0
  37. data/lib/tools/projectWizard.rb +44 -0
  38. data/spec/build_dependencies_spec.rb +169 -0
  39. data/spec/building_block_spec.rb +12 -0
  40. data/spec/dir_spec.rb +13 -0
  41. data/spec/project_path_spec.rb +73 -0
  42. data/spec/rake_listener_ext_spec.rb +25 -0
  43. data/spec/string_spec.rb +11 -0
  44. data/spec/testdata/basic/exe12/project.rb +5 -0
  45. data/spec/testdata/basic/lib1/project.rb +5 -0
  46. data/spec/testdata/basic/lib2/project.rb +8 -0
  47. data/spec/testdata/multiple_levels/libs/lib1/project.rb +5 -0
  48. data/spec/testdata/multiple_levels/libs/lib2/project.rb +19 -0
  49. data/spec/testdata/multiple_levels/mainproject/basic/project.rb +8 -0
  50. data/spec/testdata/onlyOneHeader/Rakefile.rb +4 -0
  51. data/spec/testdata/onlyOneHeader/project.rb +4 -0
  52. metadata +83 -19
  53. data/lib/cxxproject/compiler.rb +0 -80
  54. data/lib/cxxproject/dependencies.rb +0 -41
  55. data/spec/dependencies_spec.rb +0 -19
  56. /data/lib/cxxproject/{gcccompiler.rb → torake/gcccompiler.rb} +0 -0
  57. /data/lib/cxxproject/{osxcompiler.rb → torake/osxcompiler.rb} +0 -0
@@ -0,0 +1,158 @@
1
+ require 'cxxproject/extensions/stdout_ext'
2
+ require 'cxxproject/utils/dot/graph_writer'
3
+
4
+ require 'rake'
5
+ require 'stringio'
6
+
7
+ module Rake
8
+
9
+ class SyncStringIO < StringIO
10
+ def initialize(mutex)
11
+ super()
12
+ @mutex = mutex
13
+ end
14
+
15
+ def sync_flush
16
+ if string.length > 0
17
+ @mutex.synchronize { STDOUT.write string; truncate(0); rewind}
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ #############
24
+ # - Limit parallel tasks
25
+ #############
26
+ class MultiTask < Task
27
+
28
+ @@max_parallel_tasks = 8
29
+
30
+ def self.max_parallel_tasks
31
+ @@max_parallel_tasks
32
+ end
33
+
34
+ def self.set_max_parallel_tasks(number)
35
+ @@max_parallel_tasks = number
36
+ end
37
+
38
+ private
39
+ def invoke_prerequisites(args, invocation_chain)
40
+ return unless @prerequisites
41
+
42
+ jobqueue = @prerequisites.dup
43
+ m = Mutex.new
44
+
45
+ numThreads = jobqueue.length > @@max_parallel_tasks ? @@max_parallel_tasks : jobqueue.length
46
+
47
+ threads = []
48
+ numThreads.times {
49
+ threads << Thread.new(jobqueue) { |jq|
50
+ while true do
51
+ p = nil
52
+ m.synchronize { p = jq.shift }
53
+ break unless p
54
+
55
+ s = SyncStringIO.new(m)
56
+ Thread.current[:stdout] = s
57
+ prereq = application[p]
58
+ prereq.invoke_with_call_chain(args, invocation_chain)
59
+ if prereq.failure
60
+ @failure = true
61
+ end
62
+ s.sync_flush
63
+ end
64
+ }
65
+ }
66
+ threads.each { |t| t.join }
67
+ end
68
+ end
69
+
70
+ #############
71
+ # - Go on if a task fails (but to not execute the parent)
72
+ # - showInGraph is used for GraphWriter (internal tasks are not shown)
73
+ #############
74
+ class Task
75
+ attr_accessor :failure # specified if that task has failed
76
+ attr_accessor :deps # used to store deps by depfile task for the apply task (no re-read of depsfile)
77
+ attr_accessor :showInGraph
78
+ attr_accessor :transparent_timestamp
79
+ attr_accessor :dismissed_prerequisites
80
+
81
+ execute_org = self.instance_method(:execute)
82
+ initialize_org = self.instance_method(:initialize)
83
+ timestamp_org = self.instance_method(:timestamp)
84
+ invoke_prerequisites_org = self.instance_method(:invoke_prerequisites)
85
+
86
+ define_method(:initialize) do |task_name, app|
87
+ initialize_org.bind(self).call(task_name, app)
88
+ @showInGraph = GraphWriter::YES
89
+ @deps = nil
90
+ @transparent_timestamp = false
91
+ @dismissed_prerequisites = []
92
+ @neededStored = nil # cache result for performance
93
+ end
94
+
95
+ define_method(:invoke_prerequisites) do |task_args, invocation_chain|
96
+ orgLength = 0
97
+ while @prerequisites.length > orgLength do
98
+ orgLength = @prerequisites.length
99
+ @prerequisites.dup.each { |n| # dup needed when apply tasks changes that array
100
+ begin
101
+ prereq = application[n, @scope]
102
+ prereq_args = task_args.new_scope(prereq.arg_names)
103
+ prereq.invoke_with_call_chain(prereq_args, invocation_chain)
104
+ if prereq.failure
105
+ @failure = true
106
+ end
107
+ rescue
108
+ if @name.length>2 and @name[-2..-1] == ".o" # file found in dep file does not exist anymore
109
+ @prerequisites.delete(n)
110
+ def self.needed?
111
+ true
112
+ end
113
+ end
114
+ end
115
+ }
116
+ end
117
+
118
+ end
119
+
120
+ define_method(:execute) do |arg|
121
+
122
+ break if @failure # check if a prereq has failed
123
+
124
+ begin
125
+ execute_org.bind(self).call(arg)
126
+ @failure = false
127
+ rescue Exception => ex1 # todo: no rescue to stop on first error
128
+ # todo: debug log, no puts here!
129
+ puts "Error: #{@name} not built/cleaned correctly: #{ex1.message}"
130
+ begin
131
+ FileUtils.rm(@name) if File.exists?(@name) # todo: error parsing?
132
+ rescue Exception => ex2
133
+ # todo: debug log, no puts here!
134
+ puts "Error: Could not delete #{@name}: #{ex2.message}"
135
+ end
136
+ @failure = true
137
+ end
138
+
139
+ Thread.current[:stdout].sync_flush if Thread.current[:stdout]
140
+
141
+ end
142
+
143
+ define_method(:timestamp) do
144
+ if @transparent_timestamp
145
+ ts = Rake::EARLY
146
+ @prerequisites.each do |pre|
147
+ prereq_timestamp = Rake.application[pre].timestamp
148
+ ts = prereq_timestamp if prereq_timestamp > ts
149
+ end
150
+ else
151
+ ts = timestamp_org.bind(self).call()
152
+ end
153
+ ts
154
+ end
155
+
156
+ end
157
+
158
+ end
@@ -0,0 +1,53 @@
1
+ require 'rake'
2
+
3
+ module Rake
4
+
5
+ def self.add_listener(l)
6
+ get_listener() << l
7
+ puts "add->" + @@listener.inspect
8
+ end
9
+
10
+ def self.get_listener
11
+ @@listener ||= []
12
+ end
13
+ def self.remove_listener(l)
14
+ get_listener().delete(l)
15
+ puts "remove->" + @@listener.inspect
16
+ end
17
+
18
+ class MultiTask
19
+ invoke_prerequisites_original = self.instance_method(:invoke_prerequisites)
20
+ define_method(:invoke_prerequisites) do |task_args, invocation_chain|
21
+ Rake::get_listener().each {|l|l.before_prerequisites(name)}
22
+ invoke_prerequisites_original.bind(self).call(task_args, invocation_chain)
23
+ Rake::get_listener().each {|l|l.after_prerequisites(name)}
24
+ if !needed?
25
+ Rake::get_listener().each{|l|l.after_execute(name)}
26
+ end
27
+ end
28
+ end
29
+
30
+ class Task
31
+
32
+ invoke_prerequisites_original = self.instance_method(:invoke_prerequisites)
33
+ execute_original = self.instance_method(:execute)
34
+
35
+ define_method (:invoke_prerequisites) do |task_args, invocation_chain|
36
+ Rake::get_listener().each {|l|l.before_prerequisites(name)}
37
+ invoke_prerequisites_original.bind(self).call(task_args, invocation_chain)
38
+ Rake::get_listener().each {|l|l.after_prerequisites(name)}
39
+ if !needed?
40
+ Rake::get_listener().each{|l|l.after_execute(name)}
41
+ end
42
+ end
43
+
44
+ define_method(:execute) do |args|
45
+ Rake::get_listener.each {|l|l.before_execute(name)}
46
+ execute_original.bind(self).call(args)
47
+ Rake::get_listener.each {|l|l.after_execute(name)}
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
@@ -0,0 +1,35 @@
1
+ require 'stringio'
2
+
3
+ module ThreadOut
4
+
5
+ def self.write(stuff)
6
+ if Thread.current[:stdout] then
7
+ Thread.current[:stdout].write stuff
8
+ else
9
+ STDOUT.write stuff
10
+ end
11
+ end
12
+
13
+ def self.puts(stuff)
14
+ if Thread.current[:stdout] then
15
+ Thread.current[:stdout].puts stuff
16
+ else
17
+ STDERR.puts stuff
18
+ end
19
+ end
20
+
21
+ def self.flush
22
+ if Thread.current[:stdout] then
23
+ Thread.current[:stdout].flush
24
+ else
25
+ STDOUT.flush
26
+ STDERR.flush
27
+ end
28
+ end
29
+ end
30
+
31
+ STDOUT.sync = true
32
+ STDERR.sync = true
33
+ $stdout = ThreadOut
34
+ $stderr = ThreadOut
35
+
@@ -0,0 +1,9 @@
1
+ class String
2
+ def remove_from_start(text)
3
+ if index(text) == 0
4
+ self[text.size..-1]
5
+ else
6
+ self
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,418 @@
1
+ require 'cxxproject/buildingblocks/module'
2
+ require 'cxxproject/buildingblocks/makefile'
3
+ require 'cxxproject/buildingblocks/executable'
4
+ require 'cxxproject/buildingblocks/source_library'
5
+ require 'cxxproject/buildingblocks/single_source'
6
+ require 'cxxproject/buildingblocks/binary_library'
7
+ require 'cxxproject/buildingblocks/custom_building_block'
8
+ require 'cxxproject/buildingblocks/command_line'
9
+ require 'cxxproject/extensions/rake_ext'
10
+ require 'cxxproject/extensions/file_ext'
11
+ require 'cxxproject/utils/dot/graph_writer'
12
+
13
+ require 'logger'
14
+ require 'yaml'
15
+ require 'tmpdir'
16
+
17
+
18
+ # A class which encapsulates the generation of c/cpp artifacts like object-files, libraries and so on
19
+ class TaskMaker
20
+
21
+ def initialize(logger)
22
+ @log = logger
23
+ end
24
+
25
+ def set_loglevel(level)
26
+ @log.level = level
27
+ end
28
+
29
+ def add_file_to_clean_task(name)
30
+ CLEAN.include(name)
31
+ end
32
+ def add_task_to_clean_task(task)
33
+ Rake.application["clean"].enhance([task])
34
+ end
35
+ def already_added_to_clean?(task)
36
+ Rake.application["clean"].prerequisites.include?task
37
+ end
38
+
39
+ # this is the main api for the task_maker
40
+ # it will create the tasks that are needed in order to create
41
+ # one building block
42
+ #
43
+ # a building-block can be one of the following:
44
+ # * a source-library-block (a static lib that will be created)
45
+ # * an executable-block (which itself might need other libraries)
46
+ # * a binary-library-block (for which we do not need to do anything since it is already done)
47
+ # * a custom building block
48
+ # * a compile-only source file block
49
+ def create_tasks_for_building_block(bb)
50
+ @log.debug "create tasks for: #{bb.name}"
51
+ CLOBBER.include(bb.complete_output_dir)
52
+
53
+ bb.calc_transitive_dependencies()
54
+
55
+ res = nil
56
+ if HasSources === bb
57
+ res = create_tasks_for_buildingblock_with_sources(bb)
58
+ else
59
+ if (bb.instance_of?(BinaryLibrary)) then
60
+ res = create_binary_lib_task(bb)
61
+ elsif (bb.instance_of?(CustomBuildingBlock)) then
62
+ # todo...
63
+ elsif (bb.instance_of?(CommandLine)) then
64
+ res = create_commandline_task(bb)
65
+ elsif (bb.instance_of?(Makefile)) then
66
+ res = create_makefile_task(bb)
67
+ else
68
+ raise 'unknown building block'
69
+ end
70
+ end
71
+
72
+ init_show_in_graph_flags(bb)
73
+ add_building_block_deps_as_prerequisites(bb,res)
74
+ res
75
+ end
76
+
77
+ private
78
+
79
+ def create_tasks_for_buildingblock_with_sources(bb)
80
+ res = nil
81
+ bb.calc_compiler_strings()
82
+ object_tasks, objects_multitask = create_tasks_for_objects(bb)
83
+ if (bb.instance_of?(SourceLibrary)) then
84
+ res = create_source_lib(bb, object_tasks, objects_multitask)
85
+ elsif (bb.instance_of?(Executable)) then
86
+ res = create_exe_task(bb, object_tasks, objects_multitask)
87
+ elsif (bb.instance_of?(SingleSource)) then
88
+ res = create_single_source_task(bb, objects_multitask)
89
+ elsif (bb.instance_of?(ModuleBuildingBlock)) then
90
+ res = task bb.get_task_name
91
+ res.transparent_timestamp = true
92
+ end
93
+ res
94
+ end
95
+
96
+ def create_binary_lib_task(bb)
97
+ res = task bb.get_task_name
98
+ def res.needed?
99
+ return false
100
+ end
101
+ res.transparent_timestamp = true
102
+ res
103
+ end
104
+
105
+ def init_show_in_graph_flags(bb)
106
+ bb.config_files.each do |cf|
107
+ # Rake.application[cf].showInGraph = GraphWriter::NO
108
+ end
109
+ end
110
+
111
+ # convert building block deps to rake task prerequisites (e.g. exe needs lib)
112
+ def add_building_block_deps_as_prerequisites(bb,res)
113
+ bb.dependencies.reverse.each do |d|
114
+ begin
115
+ raise "ERROR: tried to add the dependencies of \"#{d}\" to \"#{bb.name}\" but such a building block could not be found!" unless ALL_BUILDING_BLOCKS[d]
116
+ res.prerequisites.unshift(ALL_BUILDING_BLOCKS[d].get_task_name)
117
+ rescue Exception => e
118
+ puts e
119
+ exit
120
+ end
121
+ end
122
+ end
123
+
124
+ def create_single_source_task(bb, objects_multitask)
125
+ res = nil
126
+ if objects_multitask
127
+ res = objects_multitask
128
+ namespace "compile" do
129
+ desc "compile sources in #{bb.name}-configuration"
130
+ task bb.name => objects_multitask
131
+ end
132
+ objects_multitask.add_description("compile sources only")
133
+ end
134
+ res
135
+ end
136
+
137
+ def create_tasks_for_objects(bb)
138
+ object_tasks = create_object_file_tasks(bb)
139
+ objects_multitask = []
140
+ if object_tasks.length > 0
141
+ objects_multitask = multitask bb.get_sources_task_name => object_tasks
142
+ def objects_multitask.needed?
143
+ return false
144
+ end
145
+ objects_multitask.transparent_timestamp = true
146
+ end
147
+ [object_tasks,objects_multitask]
148
+ end
149
+
150
+ def convert_depfile(depfile, bb)
151
+ deps = ""
152
+ File.open(depfile, "r") do |infile|
153
+ while (line = infile.gets)
154
+ deps << line
155
+ end
156
+ end
157
+
158
+ deps = deps.gsub(/\\\n/,'').split()[1..-1]
159
+ deps.map!{|d| File.expand_path(d)}
160
+
161
+ FileUtils.mkpath File.dirname(depfile)
162
+ File.open(depfile, 'wb') do |f|
163
+ f.write(deps.to_yaml)
164
+ end
165
+ end
166
+
167
+ def create_apply_task(depfile,outfileTask,bb)
168
+ res = task "#{depfile}.apply" do |task|
169
+ deps = nil
170
+ begin
171
+ deps = YAML.load_file(depfile)
172
+ rescue
173
+ deps = nil
174
+ # may happen if depfile was not converted the last time
175
+ end
176
+ if (deps)
177
+ outfileTask.enhance(deps)
178
+ else
179
+ def outfileTask.needed?
180
+ true
181
+ end
182
+ end
183
+ end
184
+ res.showInGraph = GraphWriter::NO
185
+ res.transparent_timestamp = true
186
+ res
187
+ end
188
+
189
+ def create_object_file_tasks(bb)
190
+ tasks = []
191
+
192
+ bb.sources.each do |s|
193
+ type = bb.get_source_type(s)
194
+ if type.nil?
195
+ puts "Warning: no valid source type for #{File.relFromTo(s,bb.project_dir)}, will be ignored!"
196
+ next
197
+ end
198
+
199
+ source = File.relFromTo(s,bb.project_dir)
200
+ object = bb.get_object_file(s)
201
+ depfile = bb.get_dep_file(object)
202
+
203
+ if bb.tcs4source().include?s
204
+ tcs = bb.tcs4source()[s]
205
+ iString = bb.get_include_string(tcs, type)
206
+ dString = bb.get_define_string(tcs, type)
207
+ else
208
+ tcs = bb.tcs
209
+ iString = bb.include_string(type)
210
+ dString = bb.define_string(type)
211
+ end
212
+
213
+ compiler = tcs[:COMPILER][type]
214
+ depStr = type == :ASM ? "" : (compiler[:DEP_FLAGS] + depfile) # -MMD -MF debug/src/abc.o.d
215
+
216
+ cmd = [compiler[:COMMAND], # g++
217
+ compiler[:COMPILE_FLAGS], # -c
218
+ depStr,
219
+ compiler[:FLAGS], # -g3
220
+ iString, # -I include
221
+ dString, # -DDEBUG
222
+ compiler[:OBJECT_FILE_FLAG], # -o
223
+ object, # debug/src/abc.o
224
+ source # src/abc.cpp
225
+ ].reject{|e| e == ""}.join(" ")
226
+
227
+ add_file_to_clean_task(depfile) if depStr != ""
228
+ add_file_to_clean_task(object)
229
+
230
+ outfileTask = file object => source do
231
+ puts cmd
232
+ puts `#{cmd + " 2>&1"}`
233
+ raise "System command failed" if $?.to_i != 0
234
+ convert_depfile(depfile, bb) if depStr != ""
235
+ end
236
+ outfileTask.showInGraph = GraphWriter::DETAIL
237
+ outfileTask.enhance(bb.config_files)
238
+ set_output_dir(object, outfileTask)
239
+ outfileTask.enhance([create_apply_task(depfile,outfileTask,bb)]) if depStr != ""
240
+ tasks << outfileTask
241
+ end
242
+ tasks
243
+ end
244
+
245
+ def create_commandline_task(bb)
246
+ res = task bb.get_task_name do
247
+ cmd = bb.get_command_line
248
+ puts cmd
249
+ puts `#{cmd + " 2>&1"}`
250
+ raise "System command failed" if $?.to_i != 0
251
+ end
252
+ res.transparent_timestamp = true
253
+ res
254
+ end
255
+
256
+ def create_makefile_task(bb)
257
+ mfile = bb.get_makefile()
258
+ cmd = [bb.tcs[:MAKE][:COMMAND], # make
259
+ bb.get_target, # all
260
+ bb.tcs[:MAKE][:MAKE_FLAGS], # ??
261
+ bb.tcs[:MAKE][:FLAGS], # -j
262
+ bb.tcs[:MAKE][:DIR_FLAG], # -C
263
+ File.dirname(mfile), # x/y
264
+ bb.tcs[:MAKE][:FILE_FLAG], # -f
265
+ File.basename(mfile) # x/y/makefile
266
+ ].reject{|e| e == ""}.join(" ")
267
+ mfileTask = task bb.get_task_name do
268
+ puts cmd
269
+ puts `#{cmd + " 2>&1"}`
270
+ raise "System command failed" if $?.to_i != 0
271
+ end
272
+ mfileTask.transparent_timestamp = true
273
+ mfileTask.enhance(bb.config_files)
274
+
275
+ # generate the clean task
276
+ if not already_added_to_clean?(mfile+"Clean")
277
+ cmdClean = [bb.tcs[:MAKE][:COMMAND], # make
278
+ bb.tcs[:MAKE][:CLEAN], # clean
279
+ bb.tcs[:MAKE][:DIR_FLAG], # -C
280
+ File.dirname(mfile), # x/y
281
+ bb.tcs[:MAKE][:FILE_FLAG], # -f
282
+ File.basename(mfile) # x/y/makefile
283
+ ].reject{|e| e == ""}.join(" ")
284
+ mfileCleanTask = task mfile+"Clean" do
285
+ puts cmdClean
286
+ puts `#{cmdClean + " 2>&1"}`
287
+ raise "System command failed" if $?.to_i != 0
288
+ end
289
+ add_task_to_clean_task(mfileCleanTask)
290
+ end
291
+ mfileTask
292
+ end
293
+
294
+ # task that will link the given object files to a static lib
295
+ #
296
+ def create_source_lib(bb, objects, object_multitask)
297
+ archive = bb.get_archive_name()
298
+
299
+ cmd = [bb.tcs[:ARCHIVER][:COMMAND], # ar
300
+ bb.tcs[:ARCHIVER][:ARCHIVE_FLAGS], # -r
301
+ bb.tcs[:ARCHIVER][:FLAGS], # ??
302
+ archive, # debug/x.a
303
+ objects.reject{|e| e == ""}.join(" ") # debug/src/abc.o debug/src/xy.o
304
+ ].reject{|e| e == ""}.join(" ")
305
+
306
+ res = file archive => object_multitask do
307
+ puts cmd
308
+ puts `#{cmd + " 2>&1"}`
309
+ raise "System command failed" if $?.to_i != 0
310
+ end
311
+ add_file_to_clean_task(archive)
312
+ res.enhance(bb.config_files)
313
+ set_output_dir(archive, res)
314
+ namespace 'lib' do
315
+ desc archive
316
+ task bb.name => archive
317
+ end
318
+ res
319
+ end
320
+
321
+ # create a task that will link an executable from a set of object files
322
+ #
323
+ def create_exe_task(bb, objects, object_multitask)
324
+ executable = bb.get_executable_name()
325
+ add_file_to_clean_task(executable)
326
+ scriptFile = ""
327
+ script = ""
328
+ if bb.linker_script
329
+ scriptFile = File.relFromTo(bb.linker_script, bb.project_dir)
330
+ script = "#{bb.tcs[:LINKER][:SCRIPT]} #{scriptFile}" # -T xy/xy.dld
331
+ end
332
+
333
+ mapfile = bb.mapfile ? "#{bb.tcs[:LINKER][:MAP_FILE_FLAG]} >#{File.relFromTo(bb.mapfile, bb.complete_output_dir)}" : "" # -Wl,-m6 > xy.map
334
+
335
+ # calc linkerLibString (two steps for removing duplicates)
336
+ lib_searchpaths_array = []
337
+ libs_to_search_array = []
338
+ user_libs_array = []
339
+ libs_with_path_array = []
340
+ deps = bb.all_dependencies
341
+ deps.each do |e|
342
+ d = ALL_BUILDING_BLOCKS[e]
343
+ next if not HasLibraries === d
344
+ d.lib_searchpaths.each { |k| lib_searchpaths_array << File.relFromTo(k, d.project_dir) }
345
+ d.libs_to_search.each { |k| libs_to_search_array << k }
346
+ d.user_libs.each { |k| user_libs_array << k }
347
+ d.libs_with_path.each { |k| libs_with_path_array << File.relFromTo(k, d.project_dir) }
348
+ end
349
+ strArray = []
350
+ lib_searchpaths_array.uniq.each { |k| strArray << "#{bb.tcs[:LINKER][:LIB_PATH_FLAG]}#{k}" }
351
+ libs_to_search_array.uniq.each { |k| strArray << "#{bb.tcs[:LINKER][:LIB_FLAG]}#{k}" }
352
+ user_libs_array.uniq.each { |k| strArray << "#{bb.tcs[:LINKER][:USER_LIB_FLAG]}#{k}" }
353
+ libs_with_path_array.uniq.each { |k| strArray << "#{k}" }
354
+ linkerLibString = strArray.reject{|e| e == ""}.join(" ")
355
+
356
+ cmd = [bb.tcs[:LINKER][:COMMAND], # g++
357
+ bb.tcs[:LINKER][:MUST_FLAGS], # ??
358
+ bb.tcs[:LINKER][:FLAGS], # --all_load
359
+ bb.tcs[:LINKER][:EXE_FLAG], # -o
360
+ executable, # debug/x.o
361
+ objects.reject{|e| e == ""}.join(" "), # debug/src/abc.o debug/src/xy.o
362
+ script,
363
+ mapfile,
364
+ bb.tcs[:LINKER][:LIB_PREFIX_FLAGS], # "-Wl,--whole-archive "
365
+ linkerLibString,
366
+ bb.tcs[:LINKER][:LIB_POSTFIX_FLAGS] # "-Wl,--no-whole-archive "
367
+ ].reject{|e| e == ""}.join(" ")
368
+
369
+ create_run_task(executable, bb.config_files, bb.name)
370
+
371
+ res = file executable => object_multitask do
372
+ # TempFile used, because some compilers, e.g. diab, uses ">" for piping to map files:
373
+ puts cmd
374
+ puts `#{cmd + " 2>" + get_temp_filename}`
375
+ puts read_temp_file
376
+ raise "System command failed" if $?.to_i != 0
377
+ end
378
+ res.enhance(bb.config_files)
379
+ res.enhance([scriptFile]) unless scriptFile==""
380
+ set_output_dir(executable, res)
381
+
382
+ namespace 'exe' do
383
+ desc executable
384
+ task bb.name => executable
385
+ end
386
+ res
387
+ end
388
+
389
+ def create_run_task(executable, configFiles, name)
390
+ namespace 'run' do
391
+ desc "run executable #{executable}"
392
+ task name => executable do
393
+ sh "#{executable}"
394
+ end
395
+ end
396
+ end
397
+
398
+ def set_output_dir(file, taskOfFile)
399
+ outputdir = File.dirname(file)
400
+ directory outputdir
401
+ taskOfFile.enhance([outputdir])
402
+ end
403
+
404
+ def get_temp_filename
405
+ Dir.tmpdir + "/lake.tmp"
406
+ end
407
+
408
+ def read_temp_file
409
+ lines = []
410
+ File.open(get_temp_filename, "r") do |infile|
411
+ while (line = infile.gets)
412
+ lines << line
413
+ end
414
+ end
415
+ lines
416
+ end
417
+
418
+ end