cxxproject 0.2 → 0.4.6

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 (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