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.
- data/Rakefile.rb +55 -33
- data/bin/cxx +10 -0
- data/lib/cxxproject/buildingblocks/binary_library.rb +16 -0
- data/lib/cxxproject/buildingblocks/building_block.rb +93 -0
- data/lib/cxxproject/buildingblocks/command_line.rb +30 -0
- data/lib/cxxproject/buildingblocks/custom_building_block.rb +17 -0
- data/lib/cxxproject/buildingblocks/executable.rb +49 -0
- data/lib/cxxproject/buildingblocks/has_dependencies_mixin.rb +57 -0
- data/lib/cxxproject/buildingblocks/has_libraries_mixin.rb +35 -0
- data/lib/cxxproject/buildingblocks/has_sources_mixin.rb +85 -0
- data/lib/cxxproject/buildingblocks/makefile.rb +35 -0
- data/lib/cxxproject/buildingblocks/module.rb +14 -0
- data/lib/cxxproject/buildingblocks/single_source.rb +11 -0
- data/lib/cxxproject/buildingblocks/source_library.rb +31 -0
- data/lib/cxxproject/extensions/file_ext.rb +47 -0
- data/lib/cxxproject/extensions/rake_dirty_ext.rb +30 -0
- data/lib/cxxproject/extensions/rake_ext.rb +158 -0
- data/lib/cxxproject/extensions/rake_listener_ext.rb +53 -0
- data/lib/cxxproject/extensions/stdout_ext.rb +35 -0
- data/lib/cxxproject/extensions/string_ext.rb +9 -0
- data/lib/cxxproject/task_maker.rb +418 -0
- data/lib/cxxproject/testinstanceeval.rb +65 -0
- data/lib/cxxproject/toolchain/base.rb +98 -0
- data/lib/cxxproject/toolchain/diab.rb +47 -0
- data/lib/cxxproject/toolchain/gcc.rb +39 -0
- data/lib/cxxproject/toolchain/provider.rb +18 -0
- data/lib/cxxproject/torake/compiler.rb +10 -0
- data/lib/cxxproject/torake.rb +152 -0
- data/lib/cxxproject/utils/dot/building_block_graph_writer.rb +19 -0
- data/lib/cxxproject/utils/dot/graph_writer.rb +53 -0
- data/lib/cxxproject/utils/dot/task_graph_writer.rb +34 -0
- data/lib/cxxproject/utils/ubigraph.rb +237 -0
- data/lib/cxxproject/{utils.rb → utils/utils.rb} +19 -1
- data/lib/cxxproject.rb +13 -223
- data/lib/tools/Rakefile.rb.template +10 -0
- data/lib/tools/project.rb.template +6 -0
- data/lib/tools/projectWizard.rb +44 -0
- data/spec/build_dependencies_spec.rb +169 -0
- data/spec/building_block_spec.rb +12 -0
- data/spec/dir_spec.rb +13 -0
- data/spec/project_path_spec.rb +73 -0
- data/spec/rake_listener_ext_spec.rb +25 -0
- data/spec/string_spec.rb +11 -0
- data/spec/testdata/basic/exe12/project.rb +5 -0
- data/spec/testdata/basic/lib1/project.rb +5 -0
- data/spec/testdata/basic/lib2/project.rb +8 -0
- data/spec/testdata/multiple_levels/libs/lib1/project.rb +5 -0
- data/spec/testdata/multiple_levels/libs/lib2/project.rb +19 -0
- data/spec/testdata/multiple_levels/mainproject/basic/project.rb +8 -0
- data/spec/testdata/onlyOneHeader/Rakefile.rb +4 -0
- data/spec/testdata/onlyOneHeader/project.rb +4 -0
- metadata +83 -19
- data/lib/cxxproject/compiler.rb +0 -80
- data/lib/cxxproject/dependencies.rb +0 -41
- data/spec/dependencies_spec.rb +0 -19
- /data/lib/cxxproject/{gcccompiler.rb → torake/gcccompiler.rb} +0 -0
- /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,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
|