autobuild 1.6.5 → 1.7.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -267,10 +267,23 @@ module Autobuild
267
267
  task "#{name}-build" => installstamp
268
268
  end
269
269
 
270
- def process_formatting_string(msg)
271
- msg % [name]
272
- rescue ArgumentError => e
273
- msg
270
+ def process_formatting_string(msg, *prefix_style)
271
+ prefix, suffix = [], []
272
+ msg.split(" ").each do |token|
273
+ if token =~ /%s/
274
+ suffix << token.gsub(/%s/, name)
275
+ elsif suffix.empty?
276
+ prefix << token
277
+ else suffix << token
278
+ end
279
+ end
280
+ if suffix.empty?
281
+ return msg
282
+ elsif prefix_style.empty?
283
+ return (prefix + suffix).join(" ")
284
+ else
285
+ return [Autobuild.color(prefix.join(" "), *prefix_style), *suffix].join(" ")
286
+ end
274
287
  end
275
288
 
276
289
  # Display a progress message. %s in the string is replaced by the
@@ -295,7 +308,7 @@ module Autobuild
295
308
  end
296
309
 
297
310
  def progress_start(*args, &block)
298
- args[0] = process_formatting_string(args[0])
311
+ args[0] = process_formatting_string(args[0], :bold)
299
312
  if args.last.kind_of?(Hash)
300
313
  options, raw_options = Kernel.filter_options args.last, :done_message
301
314
  if options[:done_message]
@@ -308,11 +321,14 @@ module Autobuild
308
321
  end
309
322
 
310
323
  def progress(*args)
311
- args[0] = process_formatting_string(args[0])
324
+ args[0] = process_formatting_string(args[0], :bold)
312
325
  Autobuild.progress(self, *args)
313
326
  end
314
327
 
315
- def progress_done
328
+ def progress_done(done_message = nil)
329
+ if done_message
330
+ progress(process_formatting_string(done_message))
331
+ end
316
332
  Autobuild.progress_done(self)
317
333
  end
318
334
 
@@ -363,6 +379,33 @@ module Autobuild
363
379
  end
364
380
  end
365
381
 
382
+ module TaskExtension
383
+ attr_accessor :package
384
+ end
385
+
386
+ def source_tree(*args, &block)
387
+ task = Autobuild.source_tree(*args, &block)
388
+ task.extend TaskExtension
389
+ task.package = self
390
+ task
391
+ end
392
+
393
+ # Calls Rake to define a file task and then extends it with TaskExtension
394
+ def file(*args, &block)
395
+ task = super
396
+ task.extend TaskExtension
397
+ task.package = self
398
+ task
399
+ end
400
+
401
+ # Calls Rake to define a plain task and then extends it with TaskExtension
402
+ def task(*args, &block)
403
+ task = super
404
+ task.extend TaskExtension
405
+ task.package = self
406
+ task
407
+ end
408
+
366
409
  # Defines a documentation generation task. The documentation is first
367
410
  # generated by the given block, and then installed. The local attribute
368
411
  # #doc_dir defines where the documentation is generated by the
@@ -594,6 +637,25 @@ module Autobuild
594
637
  ensure
595
638
  @in_dir_stack.pop
596
639
  end
640
+
641
+ def disabled?
642
+ @disabled
643
+ end
644
+
645
+ # Make sure that this package will be ignored in the build
646
+ def disable
647
+ @disabled = true
648
+ %w{import prepare build doc}.each do |phase|
649
+ task "#{name}-#{phase}"
650
+ t = Rake::Task["#{name}-#{phase}"]
651
+ def t.needed?; false end
652
+ t.instance_variable_set :@already_invoked, true
653
+ end
654
+ task(installstamp)
655
+ t = Rake::Task[installstamp]
656
+ def t.needed?; false end
657
+ t.instance_variable_set :@already_invoked, true
658
+ end
597
659
  end
598
660
 
599
661
  def self.package_set(spec)
@@ -11,6 +11,10 @@ module Autobuild
11
11
  Autotools.new(opts, &proc)
12
12
  end
13
13
 
14
+ if Autobuild.macos?
15
+ Autobuild.programs['libtoolize'] = "glibtoolize"
16
+ end
17
+
14
18
  #
15
19
  # ==== Handles autotools-based packages
16
20
  #
@@ -32,7 +36,7 @@ module Autobuild
32
36
  def initialize(options)
33
37
  @using = Hash.new
34
38
  @configureflags = []
35
-
39
+
36
40
  super
37
41
  end
38
42
 
@@ -40,7 +44,7 @@ module Autobuild
40
44
  def with_doc(target = 'doc')
41
45
  task "#{name}-doc" => configurestamp
42
46
  doc_task do
43
- progress_start "generating documentation for %s" do
47
+ progress_start "generating documentation for %s", :done_message => 'generated_documentation for %s' do
44
48
  Subprocess.run(self, 'doc', Autobuild.tool(:make), "-j#{parallel_build_level}", target, :working_directory => builddir)
45
49
  end
46
50
  yield if block_given?
@@ -220,7 +224,7 @@ module Autobuild
220
224
 
221
225
  autodetect_needed_stages
222
226
 
223
- progress_start "generating build system for %s" do
227
+ progress_start "generating autotools for %s", :done_message => 'generated autotools for %s' do
224
228
  if using[:libtool]
225
229
  Subprocess.run(self, 'configure', Autobuild.tool('libtoolize'), '--copy')
226
230
  end
@@ -257,7 +261,7 @@ module Autobuild
257
261
  command << "--prefix=#{prefix}"
258
262
  command += Array[*configureflags]
259
263
 
260
- progress_start "configuring build system for %s" do
264
+ progress_start "configuring autotools for %s", :done_message => 'configured autotools for %s' do
261
265
  Subprocess.run(self, 'configure', *command)
262
266
  end
263
267
  end
@@ -267,7 +271,7 @@ module Autobuild
267
271
  # Do the build in builddir
268
272
  def build
269
273
  in_dir(builddir) do
270
- progress_start "building %s [progress not available]" do
274
+ progress_start "building %s [progress not available]", :done_message => 'built %s' do
271
275
  if force_config_status
272
276
  Subprocess.run(self, 'build', './config.status')
273
277
  end
@@ -280,7 +284,7 @@ module Autobuild
280
284
  # Install the result in prefix
281
285
  def install
282
286
  in_dir(builddir) do
283
- progress_start "installing %s" do
287
+ progress_start "installing %s", :done_message => 'installed %s' do
284
288
  Subprocess.run(self, 'install', Autobuild.tool(:make), 'install')
285
289
  end
286
290
  end
@@ -203,7 +203,7 @@ module Autobuild
203
203
  def with_doc(target = 'doc')
204
204
  doc_task do
205
205
  in_dir(builddir) do
206
- progress_start "generating documentation for %s" do
206
+ progress_start "generating documentation for %s", :done_message => 'generated documentation for %s' do
207
207
  if internal_doxygen_mode?
208
208
  run_doxygen
209
209
  else
@@ -303,6 +303,11 @@ module Autobuild
303
303
 
304
304
  command = [ "cmake", "-DCMAKE_INSTALL_PREFIX=#{prefix}", "-DCMAKE_MODULE_PATH=#{CMake.module_path.join(";")}" ]
305
305
 
306
+ if(RbConfig::CONFIG["host_os"] =~%r!(msdos|mswin|djgpp|mingw|[Ww]indows)!)
307
+ command << '-G'
308
+ command << "MSYS Makefiles"
309
+ end
310
+
306
311
  defines.each do |name, value|
307
312
  command << "-D#{name}=#{value}"
308
313
  end
@@ -311,7 +316,7 @@ module Autobuild
311
316
  end
312
317
  command << srcdir
313
318
 
314
- progress_start "configuring CMake build system for %s" do
319
+ progress_start "configuring CMake for %s", :done_message => "configured CMake for %s" do
315
320
  if full_reconfigures?
316
321
  FileUtils.rm_f cmake_cache
317
322
  end
@@ -324,14 +329,32 @@ module Autobuild
324
329
  # Do the build in builddir
325
330
  def build
326
331
  in_dir(builddir) do
327
- progress_start "building %s", :done_message => "building %s (100%%)" do
332
+ progress_start "building %s", :done_message => "built %s" do
328
333
  if always_reconfigure || !File.file?('Makefile')
329
334
  Subprocess.run(self, 'build', Autobuild.tool(:cmake), '.')
330
335
  end
331
336
 
332
337
  Autobuild.make_subcommand(self, 'build') do |line|
333
338
  if line =~ /\[\s+(\d+)%\]/
334
- progress "building %s (#{Integer($1)}%%)"
339
+ progress "building %s (#{Integer($1)}%)"
340
+ end
341
+ end
342
+
343
+ warning = String.new
344
+ Autobuild.make_subcommand(self, 'build') do |line|
345
+ iswarning = false
346
+ if line =~ /\[\s*(\d+)%\]/
347
+ progress "building %s (#{Integer($1)}%)"
348
+ elsif (line =~
349
+ /^(Linking)|^(Scanning)|^(Building)|^(Built)/) == nil
350
+ warning += line
351
+ iswarning = true
352
+ end
353
+ if(!iswarning && !warning.empty?)
354
+ warning.split("\n").each do |l|
355
+ message "%s: #{l}", :magenta
356
+ end
357
+ warning = ""
335
358
  end
336
359
  end
337
360
  end
@@ -342,7 +365,7 @@ module Autobuild
342
365
  # Install the result in prefix
343
366
  def install
344
367
  in_dir(builddir) do
345
- progress_start "installing %s" do
368
+ progress_start "installing %s", :done_message => 'installed %s' do
346
369
  Subprocess.run(self, 'install', Autobuild.tool(:make), "-j#{parallel_build_level}", 'install')
347
370
  end
348
371
  end
@@ -100,10 +100,10 @@ module Autobuild
100
100
  genom_pkg = PkgConfig.new('genom')
101
101
 
102
102
  includedir = File.join(genom_pkg.includedir, 'genom')
103
- Autobuild.source_tree includedir
103
+ source_tree includedir
104
104
 
105
105
  canvasdir = File.join(genom_pkg.prefix, "share", "genom", genom_pkg.version);;
106
- Autobuild.source_tree canvasdir
106
+ source_tree canvasdir
107
107
 
108
108
  binary = File.join(genom_pkg.exec_prefix, "bin", "genom")
109
109
  file binary
@@ -133,7 +133,7 @@ module Autobuild
133
133
  file genomstamp => srcdir do
134
134
  isolate_errors do
135
135
  in_dir(srcdir) do
136
- progress_start "generating GenoM files for %s" do
136
+ progress_start "generating GenoM for %s", :done_message => 'generated GenoM for %s' do
137
137
  Subprocess.run(self, 'genom', *cmdline)
138
138
  end
139
139
  end
@@ -146,7 +146,7 @@ module Autobuild
146
146
  # configure does not depend on the .gen file
147
147
  # since the generation takes care of rebuilding configure
148
148
  # if .gen has changed
149
- progress_start "generating build system for %s" do
149
+ progress_start "generating autotools for %s", :done_message => 'generated autotools for %s' do
150
150
  in_dir(srcdir) { Subprocess.run(self, 'genom', File.expand_path('autogen', srcdir)) }
151
151
  end
152
152
  end
@@ -23,7 +23,7 @@ module Autobuild
23
23
  exclude << Regexp.new("^#{Regexp.quote(doc_dir)}")
24
24
  end
25
25
 
26
- Autobuild.source_tree(srcdir) do |pkg|
26
+ source_tree(srcdir) do |pkg|
27
27
  pkg.exclude.concat exclude
28
28
  exclude.freeze
29
29
  end
@@ -206,7 +206,7 @@ module Autobuild
206
206
  # Find out where orogen is, and make sure the configurestamp depend
207
207
  # on it. Ignore if orogen is too old to have a --base-dir option
208
208
  if orogen_root = self.class.orogen_root
209
- orogen_tree = Autobuild.source_tree(orogen_root)
209
+ orogen_tree = source_tree(orogen_root)
210
210
  end
211
211
 
212
212
  # Check if there is an orogen package registered. If it is the case,
@@ -222,7 +222,7 @@ module Autobuild
222
222
  # Cache the orogen file name
223
223
  @orogen_file ||= self.orogen_file
224
224
 
225
- file genstamp => Autobuild.source_tree(srcdir) do
225
+ file genstamp => source_tree(srcdir) do
226
226
  needs_regen = true
227
227
  if File.file?(genstamp)
228
228
  genstamp_mtime = File.stat(genstamp).mtime
@@ -333,7 +333,7 @@ module Autobuild
333
333
  needs_regen ||= (Rake::Task[Orogen.orogen_root].timestamp > Rake::Task[genstamp].timestamp)
334
334
 
335
335
  if needs_regen
336
- progress_start "generating oroGen project %s" do
336
+ progress_start "generating oroGen %s", :done_message => 'generated oroGen %s' do
337
337
  in_dir(srcdir) do
338
338
  Subprocess.run self, 'orogen', guess_ruby_name, self.class.orogen_bin, *cmdline
339
339
  File.open(genstamp, 'w') do |io|
@@ -12,10 +12,6 @@ module Autobuild
12
12
 
13
13
  attr_reader :job_server
14
14
 
15
- attr_reader :roots
16
- attr_reader :tasks
17
- attr_reader :reverse_dependencies
18
-
19
15
  class JobServer
20
16
  attr_reader :rio
21
17
  attr_reader :wio
@@ -40,49 +36,97 @@ module Autobuild
40
36
 
41
37
  end
42
38
 
43
- def process_finished_task(task, processed, queue)
44
- processed << task
45
- reverse_dependencies[task].each do |candidate|
46
- if candidate.prerequisite_tasks.all? { |t| processed.include?(t) }
47
- queue << candidate
48
- end
49
- end
50
- end
51
-
52
- def wait_for_worker_to_end(processed, queue)
39
+ def wait_for_worker_to_end(state)
53
40
  w = finished_workers.pop
54
41
  finished_task, error = w.last_result
55
42
  available_workers << w
56
43
  if error
57
44
  if available_workers.size != workers.size
58
- Autobuild.message "got an error doing parallel processing, waiting for pending jobs to end"
45
+ Autobuild.error "got an error doing parallel processing, waiting for pending jobs to end"
59
46
  end
60
47
  finish_pending_work
61
48
  raise error
62
49
  end
63
50
 
64
- process_finished_task(finished_task, processed, queue)
51
+ state.process_finished_task(finished_task)
65
52
  end
66
53
 
67
- def discover_dependencies(t)
68
- return if tasks.include?(t) # already discovered or being discovered
69
- tasks << t
54
+ def discover_dependencies(all_tasks, reverse_dependencies, t)
55
+ return if all_tasks.include?(t) # already discovered or being discovered
56
+ all_tasks << t
70
57
 
71
58
  t.prerequisite_tasks.each do |dep_t|
72
59
  reverse_dependencies[dep_t] << t
73
- discover_dependencies(dep_t)
60
+ discover_dependencies(all_tasks, reverse_dependencies, dep_t)
61
+ end
62
+ end
63
+
64
+ class ProcessingState
65
+ attr_reader :reverse_dependencies
66
+ attr_reader :processed
67
+ attr_reader :started_packages
68
+ attr_reader :active_packages
69
+ attr_reader :queue
70
+
71
+ def initialize(reverse_dependencies, initial_queue = Array.new)
72
+ @reverse_dependencies = reverse_dependencies
73
+ @processed = Set.new
74
+ @active_packages = Set.new
75
+ @started_packages = Set.new
76
+ @queue = initial_queue.to_set
77
+ end
78
+
79
+ def find_task
80
+ possible_task = nil
81
+ queue.each do |task|
82
+ if task.respond_to?(:package)
83
+ if !active_packages.include?(task.package)
84
+ if started_packages.include?(task.package)
85
+ return task
86
+ end
87
+ possible_task ||= task
88
+ end
89
+ else possible_task ||= task
90
+ end
91
+ end
92
+ possible_task
93
+ end
94
+
95
+ def pop
96
+ candidate = find_task
97
+ queue.delete(candidate)
98
+ candidate
99
+ end
100
+
101
+ def mark_as_active(pending_task)
102
+ if pending_task.respond_to?(:package)
103
+ active_packages << pending_task.package
104
+ started_packages << pending_task.package
105
+ end
106
+ end
107
+
108
+ def process_finished_task(task)
109
+ if task.respond_to?(:package)
110
+ active_packages.delete(task.package)
111
+ end
112
+ processed << task
113
+ reverse_dependencies[task].each do |candidate|
114
+ if candidate.prerequisite_tasks.all? { |t| processed.include?(t) }
115
+ queue << candidate
116
+ end
117
+ end
74
118
  end
75
119
  end
76
120
 
77
121
  # Invokes the provided tasks. Unlike the rake code, this is a toplevel
78
122
  # algorithm that does not use recursion
79
123
  def invoke_parallel(required_tasks)
80
- @tasks = Set.new
81
- @reverse_dependencies = Hash.new { |h, k| h[k] = Set.new }
124
+ tasks = Set.new
125
+ reverse_dependencies = Hash.new { |h, k| h[k] = Set.new }
82
126
  required_tasks.each do |t|
83
- discover_dependencies(t)
127
+ discover_dependencies(tasks, reverse_dependencies, t)
84
128
  end
85
- @roots = tasks.find_all { |t| t.prerequisite_tasks.empty? }.to_set
129
+ roots = tasks.find_all { |t| t.prerequisite_tasks.empty? }.to_set
86
130
 
87
131
  # Build a reverse dependency graph (i.e. a mapping from a task to
88
132
  # the tasks that depend on it)
@@ -94,25 +138,25 @@ module Autobuild
94
138
  # The queue is the set of tasks for which all prerequisites have
95
139
  # been successfully executed (or where not needed). I.e. it is the
96
140
  # set of tasks that can be queued for execution.
97
- queue = roots.to_a
98
- processed = Set.new
141
+ state = ProcessingState.new(reverse_dependencies, roots.to_a)
99
142
  while true
100
- if queue.empty?
143
+ pending_task = state.pop
144
+ if !pending_task
101
145
  # If we have pending workers, wait for one to be finished
102
146
  # until either they are all finished or the queue is not
103
147
  # empty anymore
104
- while queue.empty? && available_workers.size != workers.size
105
- wait_for_worker_to_end(processed, queue)
148
+ while !pending_task && available_workers.size != workers.size
149
+ wait_for_worker_to_end(state)
150
+ pending_task = state.pop
106
151
  end
107
152
 
108
- if queue.empty? && available_workers.size == workers.size
153
+ if !pending_task && available_workers.size == workers.size
109
154
  break
110
155
  end
111
156
  end
112
157
 
113
- pending_task = queue.pop
114
158
  if pending_task.instance_variable_get(:@already_invoked) || !pending_task.needed?
115
- process_finished_task(pending_task, processed, queue)
159
+ state.process_finished_task(pending_task)
116
160
  next
117
161
  end
118
162
 
@@ -120,7 +164,7 @@ module Autobuild
120
164
  job_server.get
121
165
 
122
166
  while !finished_workers.empty?
123
- wait_for_worker_to_end(processed, queue)
167
+ wait_for_worker_to_end(state)
124
168
  end
125
169
 
126
170
  # We do have a job server token, so we are allowed to allocate a
@@ -132,10 +176,11 @@ module Autobuild
132
176
  end
133
177
 
134
178
  worker = available_workers.pop
179
+ state.mark_as_active(pending_task)
135
180
  worker.queue(pending_task)
136
181
  end
137
182
 
138
- if processed.size != tasks.size
183
+ if state.processed.size != tasks.size
139
184
  with_cycle = tasks.to_set
140
185
  raise "cycle in task graph: #{with_cycle.map(&:name).sort.join(", ")}"
141
186
  end