autobuild 1.6.5 → 1.7.0.rc1

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.
@@ -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