rscons 1.9.3 → 1.10.0
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.
- checksums.yaml +4 -4
 - data/lib/rscons.rb +53 -1
 - data/lib/rscons/builder.rb +184 -11
 - data/lib/rscons/builders/cfile.rb +18 -3
 - data/lib/rscons/builders/command.rb +24 -9
 - data/lib/rscons/builders/disassemble.rb +20 -4
 - data/lib/rscons/builders/library.rb +37 -16
 - data/lib/rscons/builders/object.rb +35 -22
 - data/lib/rscons/builders/preprocess.rb +25 -17
 - data/lib/rscons/builders/program.rb +35 -12
 - data/lib/rscons/builders/shared_library.rb +116 -0
 - data/lib/rscons/builders/shared_object.rb +113 -0
 - data/lib/rscons/cache.rb +7 -2
 - data/lib/rscons/cli.rb +4 -0
 - data/lib/rscons/environment.rb +394 -104
 - data/lib/rscons/job_set.rb +93 -0
 - data/lib/rscons/threaded_command.rb +63 -0
 - data/lib/rscons/version.rb +1 -1
 - metadata +7 -3
 
    
        data/lib/rscons/cache.rb
    CHANGED
    
    | 
         @@ -2,7 +2,6 @@ require "digest/md5" 
     | 
|
| 
       2 
2 
     | 
    
         
             
            require "fileutils"
         
     | 
| 
       3 
3 
     | 
    
         
             
            require "json"
         
     | 
| 
       4 
4 
     | 
    
         
             
            require "set"
         
     | 
| 
       5 
     | 
    
         
            -
            require "singleton"
         
     | 
| 
       6 
5 
     | 
    
         
             
            require "rscons/version"
         
     | 
| 
       7 
6 
     | 
    
         | 
| 
       8 
7 
     | 
    
         
             
            module Rscons
         
     | 
| 
         @@ -51,7 +50,6 @@ module Rscons 
     | 
|
| 
       51 
50 
     | 
    
         
             
              #     },
         
     | 
| 
       52 
51 
     | 
    
         
             
              #   }
         
     | 
| 
       53 
52 
     | 
    
         
             
              class Cache
         
     | 
| 
       54 
     | 
    
         
            -
                include Singleton
         
     | 
| 
       55 
53 
     | 
    
         | 
| 
       56 
54 
     | 
    
         
             
                # Name of the file to store cache information in
         
     | 
| 
       57 
55 
     | 
    
         
             
                CACHE_FILE = ".rsconscache"
         
     | 
| 
         @@ -59,6 +57,13 @@ module Rscons 
     | 
|
| 
       59 
57 
     | 
    
         
             
                # Prefix for phony cache entries.
         
     | 
| 
       60 
58 
     | 
    
         
             
                PHONY_PREFIX = ":PHONY:"
         
     | 
| 
       61 
59 
     | 
    
         | 
| 
      
 60 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # Access the singleton instance.
         
     | 
| 
      
 62 
     | 
    
         
            +
                  def instance
         
     | 
| 
      
 63 
     | 
    
         
            +
                    @instance ||= Cache.new
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
       62 
67 
     | 
    
         
             
                # Create a Cache object and load in the previous contents from the cache
         
     | 
| 
       63 
68 
     | 
    
         
             
                # file.
         
     | 
| 
       64 
69 
     | 
    
         
             
                def initialize
         
     | 
    
        data/lib/rscons/cli.rb
    CHANGED
    
    | 
         @@ -35,6 +35,10 @@ module Rscons 
     | 
|
| 
       35 
35 
     | 
    
         
             
                        rsconsfile = f
         
     | 
| 
       36 
36 
     | 
    
         
             
                      end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
      
 38 
     | 
    
         
            +
                      opts.on("-j NTHREADS", "Use NTHREADS parallel jobs (local default #{Rscons.n_threads})") do |n_threads|
         
     | 
| 
      
 39 
     | 
    
         
            +
                        Rscons.n_threads = n_threads.to_i
         
     | 
| 
      
 40 
     | 
    
         
            +
                      end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
       38 
42 
     | 
    
         
             
                      opts.on_tail("--version", "Show version") do
         
     | 
| 
       39 
43 
     | 
    
         
             
                        puts "Rscons version #{Rscons::VERSION}"
         
     | 
| 
       40 
44 
     | 
    
         
             
                        exit 0
         
     | 
    
        data/lib/rscons/environment.rb
    CHANGED
    
    | 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require "fileutils"
         
     | 
| 
       2 
2 
     | 
    
         
             
            require "set"
         
     | 
| 
       3 
3 
     | 
    
         
             
            require "shellwords"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "thwait"
         
     | 
| 
       4 
5 
     | 
    
         | 
| 
       5 
6 
     | 
    
         
             
            module Rscons
         
     | 
| 
       6 
7 
     | 
    
         
             
              # The Environment class is the main programmatic interface to Rscons. It
         
     | 
| 
         @@ -13,15 +14,15 @@ module Rscons 
     | 
|
| 
       13 
14 
     | 
    
         
             
                # @return [Symbol] :command, :short, or :off
         
     | 
| 
       14 
15 
     | 
    
         
             
                attr_accessor :echo
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
                # @return [String 
     | 
| 
      
 17 
     | 
    
         
            +
                # @return [String] The build root.
         
     | 
| 
       17 
18 
     | 
    
         
             
                attr_reader :build_root
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
                # Set the build root.
         
     | 
| 
       20 
21 
     | 
    
         
             
                #
         
     | 
| 
       21 
22 
     | 
    
         
             
                # @param build_root [String] The build root.
         
     | 
| 
       22 
23 
     | 
    
         
             
                def build_root=(build_root)
         
     | 
| 
       23 
     | 
    
         
            -
                   
     | 
| 
       24 
     | 
    
         
            -
                  @build_root.gsub 
     | 
| 
      
 24 
     | 
    
         
            +
                  raise "build_root must be non-nil" unless build_root
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @build_root = build_root.gsub("\\", "/")
         
     | 
| 
       25 
26 
     | 
    
         
             
                end
         
     | 
| 
       26 
27 
     | 
    
         | 
| 
       27 
28 
     | 
    
         
             
                # Create an Environment object.
         
     | 
| 
         @@ -30,15 +31,17 @@ module Rscons 
     | 
|
| 
       30 
31 
     | 
    
         
             
                # @option options [Symbol] :echo
         
     | 
| 
       31 
32 
     | 
    
         
             
                #   :command, :short, or :off (default :short)
         
     | 
| 
       32 
33 
     | 
    
         
             
                # @option options [String] :build_root
         
     | 
| 
       33 
     | 
    
         
            -
                #   Build root directory (default  
     | 
| 
      
 34 
     | 
    
         
            +
                #   Build root directory (default "build")
         
     | 
| 
       34 
35 
     | 
    
         
             
                # @option options [Boolean] :exclude_builders
         
     | 
| 
       35 
36 
     | 
    
         
             
                #   Whether to omit adding default builders (default false)
         
     | 
| 
       36 
37 
     | 
    
         
             
                #
         
     | 
| 
       37 
38 
     | 
    
         
             
                # If a block is given, the Environment object is yielded to the block and
         
     | 
| 
       38 
39 
     | 
    
         
             
                # when the block returns, the {#process} method is automatically called.
         
     | 
| 
       39 
40 
     | 
    
         
             
                def initialize(options = {})
         
     | 
| 
      
 41 
     | 
    
         
            +
                  @threaded_commands = Set.new
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @registered_build_dependencies = {}
         
     | 
| 
       40 
43 
     | 
    
         
             
                  @varset = VarSet.new
         
     | 
| 
       41 
     | 
    
         
            -
                  @ 
     | 
| 
      
 44 
     | 
    
         
            +
                  @job_set = JobSet.new(@registered_build_dependencies)
         
     | 
| 
       42 
45 
     | 
    
         
             
                  @user_deps = {}
         
     | 
| 
       43 
46 
     | 
    
         
             
                  @builders = {}
         
     | 
| 
       44 
47 
     | 
    
         
             
                  @build_dirs = []
         
     | 
| 
         @@ -51,7 +54,7 @@ module Rscons 
     | 
|
| 
       51 
54 
     | 
    
         
             
                    end
         
     | 
| 
       52 
55 
     | 
    
         
             
                  end
         
     | 
| 
       53 
56 
     | 
    
         
             
                  @echo = options[:echo] || :short
         
     | 
| 
       54 
     | 
    
         
            -
                  @build_root = options[:build_root]
         
     | 
| 
      
 57 
     | 
    
         
            +
                  @build_root = options[:build_root] || "build"
         
     | 
| 
       55 
58 
     | 
    
         | 
| 
       56 
59 
     | 
    
         
             
                  if block_given?
         
     | 
| 
       57 
60 
     | 
    
         
             
                    yield self
         
     | 
| 
         @@ -227,27 +230,40 @@ module Rscons 
     | 
|
| 
       227 
230 
     | 
    
         
             
                #
         
     | 
| 
       228 
231 
     | 
    
         
             
                # This method takes into account the Environment's build directories.
         
     | 
| 
       229 
232 
     | 
    
         
             
                #
         
     | 
| 
       230 
     | 
    
         
            -
                # @param source_fname [String] 
     | 
| 
       231 
     | 
    
         
            -
                #  
     | 
| 
      
 233 
     | 
    
         
            +
                # @param source_fname [String]
         
     | 
| 
      
 234 
     | 
    
         
            +
                #   Source file name.
         
     | 
| 
      
 235 
     | 
    
         
            +
                # @param suffix [String]
         
     | 
| 
      
 236 
     | 
    
         
            +
                #   Suffix, including "." if desired.
         
     | 
| 
      
 237 
     | 
    
         
            +
                # @param options [Hash]
         
     | 
| 
      
 238 
     | 
    
         
            +
                #   Extra options.
         
     | 
| 
      
 239 
     | 
    
         
            +
                # @option options [Array<String>] :features
         
     | 
| 
      
 240 
     | 
    
         
            +
                #   Builder features to be used for this build. See {#register_builds}.
         
     | 
| 
       232 
241 
     | 
    
         
             
                #
         
     | 
| 
       233 
242 
     | 
    
         
             
                # @return [String]
         
     | 
| 
       234 
243 
     | 
    
         
             
                #   The file name to be built from +source_fname+ with suffix +suffix+.
         
     | 
| 
       235 
     | 
    
         
            -
                def get_build_fname(source_fname, suffix)
         
     | 
| 
      
 244 
     | 
    
         
            +
                def get_build_fname(source_fname, suffix, options = {})
         
     | 
| 
       236 
245 
     | 
    
         
             
                  build_fname = Rscons.set_suffix(source_fname, suffix).gsub('\\', '/')
         
     | 
| 
      
 246 
     | 
    
         
            +
                  options[:features] ||= []
         
     | 
| 
      
 247 
     | 
    
         
            +
                  extra_path = options[:features].include?("shared") ? "/_shared" : ""
         
     | 
| 
       237 
248 
     | 
    
         
             
                  found_match = @build_dirs.find do |src_dir, obj_dir|
         
     | 
| 
       238 
249 
     | 
    
         
             
                    if src_dir.is_a?(Regexp)
         
     | 
| 
       239 
     | 
    
         
            -
                      build_fname.sub!(src_dir, obj_dir)
         
     | 
| 
      
 250 
     | 
    
         
            +
                      build_fname.sub!(src_dir, "#{obj_dir}#{extra_path}")
         
     | 
| 
       240 
251 
     | 
    
         
             
                    else
         
     | 
| 
       241 
     | 
    
         
            -
                      build_fname.sub!(%r{^#{src_dir}/}, "#{obj_dir}/")
         
     | 
| 
      
 252 
     | 
    
         
            +
                      build_fname.sub!(%r{^#{src_dir}/}, "#{obj_dir}#{extra_path}/")
         
     | 
| 
       242 
253 
     | 
    
         
             
                    end
         
     | 
| 
       243 
254 
     | 
    
         
             
                  end
         
     | 
| 
       244 
     | 
    
         
            -
                   
     | 
| 
       245 
     | 
    
         
            -
                     
     | 
| 
       246 
     | 
    
         
            -
                      build_fname  
     | 
| 
      
 255 
     | 
    
         
            +
                  unless found_match
         
     | 
| 
      
 256 
     | 
    
         
            +
                    if Rscons.absolute_path?(build_fname)
         
     | 
| 
      
 257 
     | 
    
         
            +
                      if build_fname =~ %r{^(\w):(.*)$}
         
     | 
| 
      
 258 
     | 
    
         
            +
                        build_fname = "#{@build_root}#{extra_path}/_#{$1}#{$2}"
         
     | 
| 
      
 259 
     | 
    
         
            +
                      else
         
     | 
| 
      
 260 
     | 
    
         
            +
                        build_fname = "#{@build_root}#{extra_path}/_#{build_fname}"
         
     | 
| 
      
 261 
     | 
    
         
            +
                      end
         
     | 
| 
      
 262 
     | 
    
         
            +
                    elsif !build_fname.start_with?("#{@build_root}/")
         
     | 
| 
      
 263 
     | 
    
         
            +
                      build_fname = "#{@build_root}#{extra_path}/#{build_fname}"
         
     | 
| 
       247 
264 
     | 
    
         
             
                    end
         
     | 
| 
       248 
265 
     | 
    
         
             
                  end
         
     | 
| 
       249 
     | 
    
         
            -
                  build_fname.gsub 
     | 
| 
       250 
     | 
    
         
            -
                  build_fname
         
     | 
| 
      
 266 
     | 
    
         
            +
                  build_fname.gsub('\\', '/')
         
     | 
| 
       251 
267 
     | 
    
         
             
                end
         
     | 
| 
       252 
268 
     | 
    
         | 
| 
       253 
269 
     | 
    
         
             
                # Get a construction variable's value.
         
     | 
| 
         @@ -280,40 +296,62 @@ module Rscons 
     | 
|
| 
       280 
296 
     | 
    
         
             
                #
         
     | 
| 
       281 
297 
     | 
    
         
             
                # @return [void]
         
     | 
| 
       282 
298 
     | 
    
         
             
                def process
         
     | 
| 
       283 
     | 
    
         
            -
                   
     | 
| 
       284 
     | 
    
         
            -
             
     | 
| 
       285 
     | 
    
         
            -
                     
     | 
| 
       286 
     | 
    
         
            -
             
     | 
| 
       287 
     | 
    
         
            -
             
     | 
| 
       288 
     | 
    
         
            -
             
     | 
| 
       289 
     | 
    
         
            -
             
     | 
| 
       290 
     | 
    
         
            -
             
     | 
| 
       291 
     | 
    
         
            -
             
     | 
| 
       292 
     | 
    
         
            -
             
     | 
| 
       293 
     | 
    
         
            -
             
     | 
| 
       294 
     | 
    
         
            -
             
     | 
| 
       295 
     | 
    
         
            -
             
     | 
| 
       296 
     | 
    
         
            -
             
     | 
| 
       297 
     | 
    
         
            -
             
     | 
| 
      
 299 
     | 
    
         
            +
                  cache = Cache.instance
         
     | 
| 
      
 300 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 301 
     | 
    
         
            +
                    while @job_set.size > 0 or @threaded_commands.size > 0
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
                      targets_still_building = @threaded_commands.map do |tc|
         
     | 
| 
      
 304 
     | 
    
         
            +
                        tc.build_operation[:target]
         
     | 
| 
      
 305 
     | 
    
         
            +
                      end
         
     | 
| 
      
 306 
     | 
    
         
            +
                      job = @job_set.get_next_job_to_run(targets_still_building)
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
                      # TODO: have Cache determine when checksums may be invalid based on
         
     | 
| 
      
 309 
     | 
    
         
            +
                      # file size and/or timestamp.
         
     | 
| 
      
 310 
     | 
    
         
            +
                      cache.clear_checksum_cache!
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                      if job
         
     | 
| 
      
 313 
     | 
    
         
            +
                        result = run_builder(job[:builder],
         
     | 
| 
      
 314 
     | 
    
         
            +
                                             job[:target],
         
     | 
| 
      
 315 
     | 
    
         
            +
                                             job[:sources],
         
     | 
| 
      
 316 
     | 
    
         
            +
                                             cache,
         
     | 
| 
      
 317 
     | 
    
         
            +
                                             job[:vars],
         
     | 
| 
      
 318 
     | 
    
         
            +
                                             allow_delayed_execution: true,
         
     | 
| 
      
 319 
     | 
    
         
            +
                                             setup_info: job[:setup_info])
         
     | 
| 
      
 320 
     | 
    
         
            +
                        unless result
         
     | 
| 
      
 321 
     | 
    
         
            +
                          raise BuildError.new("Failed to build #{job[:target]}")
         
     | 
| 
      
 322 
     | 
    
         
            +
                        end
         
     | 
| 
      
 323 
     | 
    
         
            +
                      end
         
     | 
| 
      
 324 
     | 
    
         
            +
             
     | 
| 
      
 325 
     | 
    
         
            +
                      completed_tcs = Set.new
         
     | 
| 
      
 326 
     | 
    
         
            +
                      # First do a non-blocking wait to pick up any threads that have
         
     | 
| 
      
 327 
     | 
    
         
            +
                      # completed since last time.
         
     | 
| 
      
 328 
     | 
    
         
            +
                      while tc = wait_for_threaded_commands(nonblock: true)
         
     | 
| 
      
 329 
     | 
    
         
            +
                        completed_tcs << tc
         
     | 
| 
      
 330 
     | 
    
         
            +
                      end
         
     | 
| 
      
 331 
     | 
    
         
            +
             
     | 
| 
      
 332 
     | 
    
         
            +
                      # If needed, do a blocking wait.
         
     | 
| 
      
 333 
     | 
    
         
            +
                      if (completed_tcs.empty? and job.nil?) or @threaded_commands.size >= Rscons.n_threads
         
     | 
| 
      
 334 
     | 
    
         
            +
                        completed_tcs << wait_for_threaded_commands
         
     | 
| 
      
 335 
     | 
    
         
            +
                      end
         
     | 
| 
      
 336 
     | 
    
         
            +
             
     | 
| 
      
 337 
     | 
    
         
            +
                      # Process all completed {ThreadedCommand} objects.
         
     | 
| 
      
 338 
     | 
    
         
            +
                      completed_tcs.each do |tc|
         
     | 
| 
      
 339 
     | 
    
         
            +
                        result = finalize_builder(tc)
         
     | 
| 
      
 340 
     | 
    
         
            +
                        if result
         
     | 
| 
      
 341 
     | 
    
         
            +
                          @build_hooks[:post].each do |build_hook_block|
         
     | 
| 
      
 342 
     | 
    
         
            +
                            build_hook_block.call(tc.build_operation)
         
     | 
| 
       298 
343 
     | 
    
         
             
                          end
         
     | 
| 
       299 
     | 
    
         
            -
             
     | 
| 
       300 
     | 
    
         
            -
             
     | 
| 
       301 
     | 
    
         
            -
             
     | 
| 
       302 
     | 
    
         
            -
                                               cache,
         
     | 
| 
       303 
     | 
    
         
            -
                                               target_params[:vars] || {})
         
     | 
| 
       304 
     | 
    
         
            -
                          unless result
         
     | 
| 
       305 
     | 
    
         
            -
                            raise BuildError.new("Failed to build #{target}")
         
     | 
| 
      
 344 
     | 
    
         
            +
                        else
         
     | 
| 
      
 345 
     | 
    
         
            +
                          unless @echo == :command
         
     | 
| 
      
 346 
     | 
    
         
            +
                            $stdout.puts "Failed command was: #{command_to_s(tc.command)}"
         
     | 
| 
       306 
347 
     | 
    
         
             
                          end
         
     | 
| 
      
 348 
     | 
    
         
            +
                          raise BuildError.new("Failed to build #{tc.build_operation[:target]}")
         
     | 
| 
       307 
349 
     | 
    
         
             
                        end
         
     | 
| 
       308 
350 
     | 
    
         
             
                      end
         
     | 
| 
      
 351 
     | 
    
         
            +
             
     | 
| 
       309 
352 
     | 
    
         
             
                    end
         
     | 
| 
       310 
     | 
    
         
            -
             
     | 
| 
       311 
     | 
    
         
            -
             
     | 
| 
       312 
     | 
    
         
            -
                        process_target.call(target)
         
     | 
| 
       313 
     | 
    
         
            -
                      end
         
     | 
| 
       314 
     | 
    
         
            -
                    ensure
         
     | 
| 
       315 
     | 
    
         
            -
                      cache.write
         
     | 
| 
       316 
     | 
    
         
            -
                    end
         
     | 
| 
      
 353 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 354 
     | 
    
         
            +
                    cache.write
         
     | 
| 
       317 
355 
     | 
    
         
             
                  end
         
     | 
| 
       318 
356 
     | 
    
         
             
                end
         
     | 
| 
       319 
357 
     | 
    
         | 
| 
         @@ -321,7 +359,7 @@ module Rscons 
     | 
|
| 
       321 
359 
     | 
    
         
             
                #
         
     | 
| 
       322 
360 
     | 
    
         
             
                # @return [void]
         
     | 
| 
       323 
361 
     | 
    
         
             
                def clear_targets
         
     | 
| 
       324 
     | 
    
         
            -
                  @ 
     | 
| 
      
 362 
     | 
    
         
            +
                  @job_set.clear!
         
     | 
| 
       325 
363 
     | 
    
         
             
                end
         
     | 
| 
       326 
364 
     | 
    
         | 
| 
       327 
365 
     | 
    
         
             
                # Expand a construction variable reference.
         
     | 
| 
         @@ -354,11 +392,8 @@ module Rscons 
     | 
|
| 
       354 
392 
     | 
    
         
             
                #
         
     | 
| 
       355 
393 
     | 
    
         
             
                # @return [true,false,nil] Return value from Kernel.system().
         
     | 
| 
       356 
394 
     | 
    
         
             
                def execute(short_desc, command, options = {})
         
     | 
| 
       357 
     | 
    
         
            -
                  print_command = proc do
         
     | 
| 
       358 
     | 
    
         
            -
                    puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
         
     | 
| 
       359 
     | 
    
         
            -
                  end
         
     | 
| 
       360 
395 
     | 
    
         
             
                  if @echo == :command
         
     | 
| 
       361 
     | 
    
         
            -
                     
     | 
| 
      
 396 
     | 
    
         
            +
                    puts command_to_s(command)
         
     | 
| 
       362 
397 
     | 
    
         
             
                  elsif @echo == :short
         
     | 
| 
       363 
398 
     | 
    
         
             
                    puts short_desc
         
     | 
| 
       364 
399 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -366,8 +401,7 @@ module Rscons 
     | 
|
| 
       366 
401 
     | 
    
         
             
                  options_args = options[:options] ? [options[:options]] : []
         
     | 
| 
       367 
402 
     | 
    
         
             
                  system(*env_args, *Rscons.command_executer, *command, *options_args).tap do |result|
         
     | 
| 
       368 
403 
     | 
    
         
             
                    unless result or @echo == :command
         
     | 
| 
       369 
     | 
    
         
            -
                      $stdout. 
     | 
| 
       370 
     | 
    
         
            -
                      print_command.call
         
     | 
| 
      
 404 
     | 
    
         
            +
                      $stdout.puts "Failed command was: #{command_to_s(command)}"
         
     | 
| 
       371 
405 
     | 
    
         
             
                    end
         
     | 
| 
       372 
406 
     | 
    
         
             
                  end
         
     | 
| 
       373 
407 
     | 
    
         
             
                end
         
     | 
| 
         @@ -383,12 +417,16 @@ module Rscons 
     | 
|
| 
       383 
417 
     | 
    
         
             
                def method_missing(method, *args)
         
     | 
| 
       384 
418 
     | 
    
         
             
                  if @builders.has_key?(method.to_s)
         
     | 
| 
       385 
419 
     | 
    
         
             
                    target, sources, vars, *rest = args
         
     | 
| 
       386 
     | 
    
         
            -
                     
     | 
| 
      
 420 
     | 
    
         
            +
                    vars ||= {}
         
     | 
| 
      
 421 
     | 
    
         
            +
                    unless vars.is_a?(Hash) or vars.is_a?(VarSet)
         
     | 
| 
       387 
422 
     | 
    
         
             
                      raise "Unexpected construction variable set: #{vars.inspect}"
         
     | 
| 
       388 
423 
     | 
    
         
             
                    end
         
     | 
| 
       389 
     | 
    
         
            -
                    sources = Array(sources)
         
     | 
| 
       390 
424 
     | 
    
         
             
                    builder = @builders[method.to_s]
         
     | 
| 
       391 
     | 
    
         
            -
                     
     | 
| 
      
 425 
     | 
    
         
            +
                    target = expand_path(expand_varref(target))
         
     | 
| 
      
 426 
     | 
    
         
            +
                    sources = Array(sources).map do |source|
         
     | 
| 
      
 427 
     | 
    
         
            +
                      expand_path(expand_varref(source))
         
     | 
| 
      
 428 
     | 
    
         
            +
                    end.flatten
         
     | 
| 
      
 429 
     | 
    
         
            +
                    build_target = builder.create_build_target(env: self, target: target, sources: sources, vars: vars)
         
     | 
| 
       392 
430 
     | 
    
         
             
                    add_target(build_target.to_s, builder, sources, vars, rest)
         
     | 
| 
       393 
431 
     | 
    
         
             
                    build_target
         
     | 
| 
       394 
432 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -396,25 +434,6 @@ module Rscons 
     | 
|
| 
       396 
434 
     | 
    
         
             
                  end
         
     | 
| 
       397 
435 
     | 
    
         
             
                end
         
     | 
| 
       398 
436 
     | 
    
         | 
| 
       399 
     | 
    
         
            -
                # Add a build target.
         
     | 
| 
       400 
     | 
    
         
            -
                #
         
     | 
| 
       401 
     | 
    
         
            -
                # @param target [String] Build target file name.
         
     | 
| 
       402 
     | 
    
         
            -
                # @param builder [Builder] The {Builder} to use to build the target.
         
     | 
| 
       403 
     | 
    
         
            -
                # @param sources [Array<String>] Source file name(s).
         
     | 
| 
       404 
     | 
    
         
            -
                # @param vars [Hash] Construction variable overrides.
         
     | 
| 
       405 
     | 
    
         
            -
                # @param args [Object] Any extra arguments passed to the {Builder}.
         
     | 
| 
       406 
     | 
    
         
            -
                #
         
     | 
| 
       407 
     | 
    
         
            -
                # @return [void]
         
     | 
| 
       408 
     | 
    
         
            -
                def add_target(target, builder, sources, vars, args)
         
     | 
| 
       409 
     | 
    
         
            -
                  @targets[target] ||= []
         
     | 
| 
       410 
     | 
    
         
            -
                  @targets[target] << {
         
     | 
| 
       411 
     | 
    
         
            -
                    builder: builder,
         
     | 
| 
       412 
     | 
    
         
            -
                    sources: sources,
         
     | 
| 
       413 
     | 
    
         
            -
                    vars: vars,
         
     | 
| 
       414 
     | 
    
         
            -
                    args: args,
         
     | 
| 
       415 
     | 
    
         
            -
                  }
         
     | 
| 
       416 
     | 
    
         
            -
                end
         
     | 
| 
       417 
     | 
    
         
            -
             
     | 
| 
       418 
437 
     | 
    
         
             
                # Manually record a given target as depending on the specified files.
         
     | 
| 
       419 
438 
     | 
    
         
             
                #
         
     | 
| 
       420 
439 
     | 
    
         
             
                # @param target [String,BuildTarget] Target file.
         
     | 
| 
         @@ -428,6 +447,42 @@ module Rscons 
     | 
|
| 
       428 
447 
     | 
    
         
             
                  @user_deps[target] = (@user_deps[target] + user_deps).uniq
         
     | 
| 
       429 
448 
     | 
    
         
             
                end
         
     | 
| 
       430 
449 
     | 
    
         | 
| 
      
 450 
     | 
    
         
            +
                # Manually record the given target(s) as needing to be built after the
         
     | 
| 
      
 451 
     | 
    
         
            +
                # given prerequisite(s).
         
     | 
| 
      
 452 
     | 
    
         
            +
                #
         
     | 
| 
      
 453 
     | 
    
         
            +
                # For example, consider a builder registered to generate gen.c which also
         
     | 
| 
      
 454 
     | 
    
         
            +
                # generates gen.h as a side-effect. If program.c includes gen.h, then it
         
     | 
| 
      
 455 
     | 
    
         
            +
                # should not be compiled before gen.h has been generated. When using
         
     | 
| 
      
 456 
     | 
    
         
            +
                # multiple threads to build, Rscons may attempt to compile program.c before
         
     | 
| 
      
 457 
     | 
    
         
            +
                # gen.h has been generated because it does not know that gen.h will be
         
     | 
| 
      
 458 
     | 
    
         
            +
                # generated along with gen.c. One way to prevent that situation would be
         
     | 
| 
      
 459 
     | 
    
         
            +
                # to first process the Environment with just the code-generation builders
         
     | 
| 
      
 460 
     | 
    
         
            +
                # in place and then register the compilation builders. Another way is to
         
     | 
| 
      
 461 
     | 
    
         
            +
                # use this method to record that a certain target should not be built until
         
     | 
| 
      
 462 
     | 
    
         
            +
                # another has completed. For example, for the situation previously
         
     | 
| 
      
 463 
     | 
    
         
            +
                # described:
         
     | 
| 
      
 464 
     | 
    
         
            +
                #   env.build_after("program.o", "gen.c")
         
     | 
| 
      
 465 
     | 
    
         
            +
                #
         
     | 
| 
      
 466 
     | 
    
         
            +
                # @since 1.10.0
         
     | 
| 
      
 467 
     | 
    
         
            +
                #
         
     | 
| 
      
 468 
     | 
    
         
            +
                # @param targets [String, Array<String>]
         
     | 
| 
      
 469 
     | 
    
         
            +
                #   Target files to wait to build until the prerequisites are finished
         
     | 
| 
      
 470 
     | 
    
         
            +
                #   building.
         
     | 
| 
      
 471 
     | 
    
         
            +
                # @param prerequisites [String, Array<String>]
         
     | 
| 
      
 472 
     | 
    
         
            +
                #   Files that must be built before building the specified targets.
         
     | 
| 
      
 473 
     | 
    
         
            +
                #
         
     | 
| 
      
 474 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 475 
     | 
    
         
            +
                def build_after(targets, prerequisites)
         
     | 
| 
      
 476 
     | 
    
         
            +
                  targets = Array(targets)
         
     | 
| 
      
 477 
     | 
    
         
            +
                  prerequisites = Array(prerequisites)
         
     | 
| 
      
 478 
     | 
    
         
            +
                  targets.each do |target|
         
     | 
| 
      
 479 
     | 
    
         
            +
                    @registered_build_dependencies[target] ||= Set.new
         
     | 
| 
      
 480 
     | 
    
         
            +
                    prerequisites.each do |prerequisite|
         
     | 
| 
      
 481 
     | 
    
         
            +
                      @registered_build_dependencies[target] << prerequisite
         
     | 
| 
      
 482 
     | 
    
         
            +
                    end
         
     | 
| 
      
 483 
     | 
    
         
            +
                  end
         
     | 
| 
      
 484 
     | 
    
         
            +
                end
         
     | 
| 
      
 485 
     | 
    
         
            +
             
     | 
| 
       431 
486 
     | 
    
         
             
                # Return the list of user dependencies for a given target.
         
     | 
| 
       432 
487 
     | 
    
         
             
                #
         
     | 
| 
       433 
488 
     | 
    
         
             
                # @param target [String] Target file name.
         
     | 
| 
         @@ -444,6 +499,8 @@ module Rscons 
     | 
|
| 
       444 
499 
     | 
    
         
             
                #
         
     | 
| 
       445 
500 
     | 
    
         
             
                # This method is used internally by Rscons builders.
         
     | 
| 
       446 
501 
     | 
    
         
             
                #
         
     | 
| 
      
 502 
     | 
    
         
            +
                # @deprecated Use {#register_builds} instead.
         
     | 
| 
      
 503 
     | 
    
         
            +
                #
         
     | 
| 
       447 
504 
     | 
    
         
             
                # @param sources [Array<String>] List of source files to build.
         
     | 
| 
       448 
505 
     | 
    
         
             
                # @param suffixes [Array<String>]
         
     | 
| 
       449 
506 
     | 
    
         
             
                #   List of suffixes to try to convert source files into.
         
     | 
| 
         @@ -459,8 +516,7 @@ module Rscons 
     | 
|
| 
       459 
516 
     | 
    
         
             
                      converted = nil
         
     | 
| 
       460 
517 
     | 
    
         
             
                      suffixes.each do |suffix|
         
     | 
| 
       461 
518 
     | 
    
         
             
                        converted_fname = get_build_fname(source, suffix)
         
     | 
| 
       462 
     | 
    
         
            -
                        builder =  
     | 
| 
       463 
     | 
    
         
            -
                        if builder
         
     | 
| 
      
 519 
     | 
    
         
            +
                        if builder = find_builder_for(converted_fname, source, [])
         
     | 
| 
       464 
520 
     | 
    
         
             
                          converted = run_builder(builder, converted_fname, [source], cache, vars)
         
     | 
| 
       465 
521 
     | 
    
         
             
                          return nil unless converted
         
     | 
| 
       466 
522 
     | 
    
         
             
                          break
         
     | 
| 
         @@ -471,6 +527,54 @@ module Rscons 
     | 
|
| 
       471 
527 
     | 
    
         
             
                  end
         
     | 
| 
       472 
528 
     | 
    
         
             
                end
         
     | 
| 
       473 
529 
     | 
    
         | 
| 
      
 530 
     | 
    
         
            +
                # Find and register builders to build source files into files containing
         
     | 
| 
      
 531 
     | 
    
         
            +
                # one of the suffixes given by suffixes.
         
     | 
| 
      
 532 
     | 
    
         
            +
                #
         
     | 
| 
      
 533 
     | 
    
         
            +
                # This method is used internally by Rscons builders. It should be called
         
     | 
| 
      
 534 
     | 
    
         
            +
                # from the builder's #setup method.
         
     | 
| 
      
 535 
     | 
    
         
            +
                #
         
     | 
| 
      
 536 
     | 
    
         
            +
                # @since 1.10.0
         
     | 
| 
      
 537 
     | 
    
         
            +
                #
         
     | 
| 
      
 538 
     | 
    
         
            +
                # @param target [String]
         
     | 
| 
      
 539 
     | 
    
         
            +
                #   The target that depends on these builds.
         
     | 
| 
      
 540 
     | 
    
         
            +
                # @param sources [Array<String>]
         
     | 
| 
      
 541 
     | 
    
         
            +
                #   List of source file(s) to build.
         
     | 
| 
      
 542 
     | 
    
         
            +
                # @param suffixes [Array<String>]
         
     | 
| 
      
 543 
     | 
    
         
            +
                #   List of suffixes to try to convert source files into.
         
     | 
| 
      
 544 
     | 
    
         
            +
                # @param vars [Hash]
         
     | 
| 
      
 545 
     | 
    
         
            +
                #   Extra variables to pass to the builders.
         
     | 
| 
      
 546 
     | 
    
         
            +
                # @param options [Hash]
         
     | 
| 
      
 547 
     | 
    
         
            +
                #   Extra options.
         
     | 
| 
      
 548 
     | 
    
         
            +
                # @option options [Array<String>] :features
         
     | 
| 
      
 549 
     | 
    
         
            +
                #   Set of features the builder must provide. Each feature can be proceeded
         
     | 
| 
      
 550 
     | 
    
         
            +
                #   by a "-" character to indicate that the builder must /not/ provide the
         
     | 
| 
      
 551 
     | 
    
         
            +
                #   given feature.
         
     | 
| 
      
 552 
     | 
    
         
            +
                #   * shared - builder builds a shared object/library
         
     | 
| 
      
 553 
     | 
    
         
            +
                #
         
     | 
| 
      
 554 
     | 
    
         
            +
                # @return [Array<String>]
         
     | 
| 
      
 555 
     | 
    
         
            +
                #   List of the output file name(s).
         
     | 
| 
      
 556 
     | 
    
         
            +
                def register_builds(target, sources, suffixes, vars, options = {})
         
     | 
| 
      
 557 
     | 
    
         
            +
                  options[:features] ||= []
         
     | 
| 
      
 558 
     | 
    
         
            +
                  @registered_build_dependencies[target] ||= Set.new
         
     | 
| 
      
 559 
     | 
    
         
            +
                  sources.map do |source|
         
     | 
| 
      
 560 
     | 
    
         
            +
                    if source.end_with?(*suffixes)
         
     | 
| 
      
 561 
     | 
    
         
            +
                      source
         
     | 
| 
      
 562 
     | 
    
         
            +
                    else
         
     | 
| 
      
 563 
     | 
    
         
            +
                      output_fname = nil
         
     | 
| 
      
 564 
     | 
    
         
            +
                      suffixes.each do |suffix|
         
     | 
| 
      
 565 
     | 
    
         
            +
                        attempt_output_fname = get_build_fname(source, suffix, features: options[:features])
         
     | 
| 
      
 566 
     | 
    
         
            +
                        if builder = find_builder_for(attempt_output_fname, source, options[:features])
         
     | 
| 
      
 567 
     | 
    
         
            +
                          output_fname = attempt_output_fname
         
     | 
| 
      
 568 
     | 
    
         
            +
                          self.__send__(builder.name, output_fname, source, vars)
         
     | 
| 
      
 569 
     | 
    
         
            +
                          @registered_build_dependencies[target] << output_fname
         
     | 
| 
      
 570 
     | 
    
         
            +
                          break
         
     | 
| 
      
 571 
     | 
    
         
            +
                        end
         
     | 
| 
      
 572 
     | 
    
         
            +
                      end
         
     | 
| 
      
 573 
     | 
    
         
            +
                      output_fname or raise "Could not find a builder for #{source.inspect}."
         
     | 
| 
      
 574 
     | 
    
         
            +
                    end
         
     | 
| 
      
 575 
     | 
    
         
            +
                  end
         
     | 
| 
      
 576 
     | 
    
         
            +
                end
         
     | 
| 
      
 577 
     | 
    
         
            +
             
     | 
| 
       474 
578 
     | 
    
         
             
                # Invoke a builder to build the given target based on the given sources.
         
     | 
| 
       475 
579 
     | 
    
         
             
                #
         
     | 
| 
       476 
580 
     | 
    
         
             
                # @param builder [Builder] The Builder to use.
         
     | 
| 
         @@ -478,25 +582,66 @@ module Rscons 
     | 
|
| 
       478 
582 
     | 
    
         
             
                # @param sources [Array<String>] List of source files.
         
     | 
| 
       479 
583 
     | 
    
         
             
                # @param cache [Cache] The Cache.
         
     | 
| 
       480 
584 
     | 
    
         
             
                # @param vars [Hash] Extra variables to pass to the builder.
         
     | 
| 
      
 585 
     | 
    
         
            +
                # @param options [Hash]
         
     | 
| 
      
 586 
     | 
    
         
            +
                #   @since 1.10.0
         
     | 
| 
      
 587 
     | 
    
         
            +
                #   Options.
         
     | 
| 
      
 588 
     | 
    
         
            +
                # @option options [Boolean] :allow_delayed_execution
         
     | 
| 
      
 589 
     | 
    
         
            +
                #   @since 1.10.0
         
     | 
| 
      
 590 
     | 
    
         
            +
                #   Allow a threaded command to be scheduled but not yet completed before
         
     | 
| 
      
 591 
     | 
    
         
            +
                #   this method returns.
         
     | 
| 
      
 592 
     | 
    
         
            +
                # @option options [Object] :setup_info
         
     | 
| 
      
 593 
     | 
    
         
            +
                #   Arbitrary builder info returned by Builder#setup.
         
     | 
| 
       481 
594 
     | 
    
         
             
                #
         
     | 
| 
       482 
595 
     | 
    
         
             
                # @return [String,false] Return value from the {Builder}'s +run+ method.
         
     | 
| 
       483 
     | 
    
         
            -
                def run_builder(builder, target, sources, cache, vars)
         
     | 
| 
      
 596 
     | 
    
         
            +
                def run_builder(builder, target, sources, cache, vars, options = {})
         
     | 
| 
       484 
597 
     | 
    
         
             
                  vars = @varset.merge(vars)
         
     | 
| 
      
 598 
     | 
    
         
            +
                  build_operation = {
         
     | 
| 
      
 599 
     | 
    
         
            +
                    builder: builder,
         
     | 
| 
      
 600 
     | 
    
         
            +
                    target: target,
         
     | 
| 
      
 601 
     | 
    
         
            +
                    sources: sources,
         
     | 
| 
      
 602 
     | 
    
         
            +
                    cache: cache,
         
     | 
| 
      
 603 
     | 
    
         
            +
                    env: self,
         
     | 
| 
      
 604 
     | 
    
         
            +
                    vars: vars,
         
     | 
| 
      
 605 
     | 
    
         
            +
                    setup_info: options[:setup_info]
         
     | 
| 
      
 606 
     | 
    
         
            +
                  }
         
     | 
| 
       485 
607 
     | 
    
         
             
                  call_build_hooks = lambda do |sec|
         
     | 
| 
       486 
608 
     | 
    
         
             
                    @build_hooks[sec].each do |build_hook_block|
         
     | 
| 
       487 
     | 
    
         
            -
                      build_operation = {
         
     | 
| 
       488 
     | 
    
         
            -
                        builder: builder,
         
     | 
| 
       489 
     | 
    
         
            -
                        target: target,
         
     | 
| 
       490 
     | 
    
         
            -
                        sources: sources,
         
     | 
| 
       491 
     | 
    
         
            -
                        vars: vars,
         
     | 
| 
       492 
     | 
    
         
            -
                        env: self,
         
     | 
| 
       493 
     | 
    
         
            -
                      }
         
     | 
| 
       494 
609 
     | 
    
         
             
                      build_hook_block.call(build_operation)
         
     | 
| 
       495 
610 
     | 
    
         
             
                    end
         
     | 
| 
       496 
611 
     | 
    
         
             
                  end
         
     | 
| 
      
 612 
     | 
    
         
            +
             
     | 
| 
      
 613 
     | 
    
         
            +
                  # Invoke pre-build hooks.
         
     | 
| 
       497 
614 
     | 
    
         
             
                  call_build_hooks[:pre]
         
     | 
| 
       498 
     | 
    
         
            -
             
     | 
| 
       499 
     | 
    
         
            -
                   
     | 
| 
      
 615 
     | 
    
         
            +
             
     | 
| 
      
 616 
     | 
    
         
            +
                  # Call the builder's #run method.
         
     | 
| 
      
 617 
     | 
    
         
            +
                  if builder.method(:run).arity == 5
         
     | 
| 
      
 618 
     | 
    
         
            +
                    rv = builder.run(*build_operation.values_at(:target, :sources, :cache, :env, :vars))
         
     | 
| 
      
 619 
     | 
    
         
            +
                  else
         
     | 
| 
      
 620 
     | 
    
         
            +
                    rv = builder.run(build_operation)
         
     | 
| 
      
 621 
     | 
    
         
            +
                  end
         
     | 
| 
      
 622 
     | 
    
         
            +
             
     | 
| 
      
 623 
     | 
    
         
            +
                  if rv.is_a?(ThreadedCommand)
         
     | 
| 
      
 624 
     | 
    
         
            +
                    # Store the build operation so the post-build hooks can be called
         
     | 
| 
      
 625 
     | 
    
         
            +
                    # with it when the threaded command completes.
         
     | 
| 
      
 626 
     | 
    
         
            +
                    rv.build_operation = build_operation
         
     | 
| 
      
 627 
     | 
    
         
            +
                    start_threaded_command(rv)
         
     | 
| 
      
 628 
     | 
    
         
            +
                    unless options[:allow_delayed_execution]
         
     | 
| 
      
 629 
     | 
    
         
            +
                      # Delayed command execution is not allowed, so we need to execute
         
     | 
| 
      
 630 
     | 
    
         
            +
                      # the command and finalize the builder now.
         
     | 
| 
      
 631 
     | 
    
         
            +
                      tc = wait_for_threaded_commands(which: [rv])
         
     | 
| 
      
 632 
     | 
    
         
            +
                      rv = finalize_builder(tc)
         
     | 
| 
      
 633 
     | 
    
         
            +
                      if rv
         
     | 
| 
      
 634 
     | 
    
         
            +
                        call_build_hooks[:post]
         
     | 
| 
      
 635 
     | 
    
         
            +
                      else
         
     | 
| 
      
 636 
     | 
    
         
            +
                        unless @echo == :command
         
     | 
| 
      
 637 
     | 
    
         
            +
                          $stdout.puts "Failed command was: #{command_to_s(tc.command)}"
         
     | 
| 
      
 638 
     | 
    
         
            +
                        end
         
     | 
| 
      
 639 
     | 
    
         
            +
                      end
         
     | 
| 
      
 640 
     | 
    
         
            +
                    end
         
     | 
| 
      
 641 
     | 
    
         
            +
                  else
         
     | 
| 
      
 642 
     | 
    
         
            +
                    call_build_hooks[:post] if rv
         
     | 
| 
      
 643 
     | 
    
         
            +
                  end
         
     | 
| 
      
 644 
     | 
    
         
            +
             
     | 
| 
       500 
645 
     | 
    
         
             
                  rv
         
     | 
| 
       501 
646 
     | 
    
         
             
                end
         
     | 
| 
       502 
647 
     | 
    
         | 
| 
         @@ -505,14 +650,20 @@ module Rscons 
     | 
|
| 
       505 
650 
     | 
    
         
             
                # Paths beginning with "^/" are expanded by replacing "^" with the
         
     | 
| 
       506 
651 
     | 
    
         
             
                # Environment's build root.
         
     | 
| 
       507 
652 
     | 
    
         
             
                #
         
     | 
| 
       508 
     | 
    
         
            -
                # @param path [String] 
     | 
| 
      
 653 
     | 
    
         
            +
                # @param path [String, Array<String>]
         
     | 
| 
      
 654 
     | 
    
         
            +
                #   The path(s) to expand.
         
     | 
| 
       509 
655 
     | 
    
         
             
                #
         
     | 
| 
       510 
     | 
    
         
            -
                # @return [String] 
     | 
| 
      
 656 
     | 
    
         
            +
                # @return [String, Array<String>]
         
     | 
| 
      
 657 
     | 
    
         
            +
                #   The expanded path(s).
         
     | 
| 
       511 
658 
     | 
    
         
             
                def expand_path(path)
         
     | 
| 
       512 
659 
     | 
    
         
             
                  if Rscons.phony_target?(path)
         
     | 
| 
       513 
660 
     | 
    
         
             
                    path
         
     | 
| 
      
 661 
     | 
    
         
            +
                  elsif path.is_a?(Array)
         
     | 
| 
      
 662 
     | 
    
         
            +
                    path.map do |path|
         
     | 
| 
      
 663 
     | 
    
         
            +
                      expand_path(path)
         
     | 
| 
      
 664 
     | 
    
         
            +
                    end
         
     | 
| 
       514 
665 
     | 
    
         
             
                  else
         
     | 
| 
       515 
     | 
    
         
            -
                    path.sub(%r{^\^(?=[\\/])}, @build_root)
         
     | 
| 
      
 666 
     | 
    
         
            +
                    path.sub(%r{^\^(?=[\\/])}, @build_root).gsub("\\", "/")
         
     | 
| 
       516 
667 
     | 
    
         
             
                  end
         
     | 
| 
       517 
668 
     | 
    
         
             
                end
         
     | 
| 
       518 
669 
     | 
    
         | 
| 
         @@ -676,25 +827,164 @@ module Rscons 
     | 
|
| 
       676 
827 
     | 
    
         | 
| 
       677 
828 
     | 
    
         
             
                private
         
     | 
| 
       678 
829 
     | 
    
         | 
| 
       679 
     | 
    
         
            -
                #  
     | 
| 
      
 830 
     | 
    
         
            +
                # Add a build target.
         
     | 
| 
      
 831 
     | 
    
         
            +
                #
         
     | 
| 
      
 832 
     | 
    
         
            +
                # @param target [String] Build target file name.
         
     | 
| 
      
 833 
     | 
    
         
            +
                # @param builder [Builder] The {Builder} to use to build the target.
         
     | 
| 
      
 834 
     | 
    
         
            +
                # @param sources [Array<String>] Source file name(s).
         
     | 
| 
      
 835 
     | 
    
         
            +
                # @param vars [Hash] Construction variable overrides.
         
     | 
| 
      
 836 
     | 
    
         
            +
                # @param args [Object] Deprecated; unused.
         
     | 
| 
      
 837 
     | 
    
         
            +
                #
         
     | 
| 
      
 838 
     | 
    
         
            +
                # @return [void]
         
     | 
| 
      
 839 
     | 
    
         
            +
                def add_target(target, builder, sources, vars, args)
         
     | 
| 
      
 840 
     | 
    
         
            +
                  setup_info = builder.setup(
         
     | 
| 
      
 841 
     | 
    
         
            +
                    target: target,
         
     | 
| 
      
 842 
     | 
    
         
            +
                    sources: sources,
         
     | 
| 
      
 843 
     | 
    
         
            +
                    env: self,
         
     | 
| 
      
 844 
     | 
    
         
            +
                    vars: vars)
         
     | 
| 
      
 845 
     | 
    
         
            +
                  @job_set.add_job(
         
     | 
| 
      
 846 
     | 
    
         
            +
                    builder: builder,
         
     | 
| 
      
 847 
     | 
    
         
            +
                    target: target,
         
     | 
| 
      
 848 
     | 
    
         
            +
                    sources: sources,
         
     | 
| 
      
 849 
     | 
    
         
            +
                    vars: vars,
         
     | 
| 
      
 850 
     | 
    
         
            +
                    setup_info: setup_info)
         
     | 
| 
      
 851 
     | 
    
         
            +
                end
         
     | 
| 
      
 852 
     | 
    
         
            +
             
     | 
| 
      
 853 
     | 
    
         
            +
                # Start a threaded command in a new thread.
         
     | 
| 
       680 
854 
     | 
    
         
             
                #
         
     | 
| 
       681 
     | 
    
         
            -
                #  
     | 
| 
       682 
     | 
    
         
            -
                #  
     | 
| 
       683 
     | 
    
         
            -
                # "^/" prefixes to the Environment's build root if a build root is defined.
         
     | 
| 
      
 855 
     | 
    
         
            +
                # @param tc [ThreadedCommand]
         
     | 
| 
      
 856 
     | 
    
         
            +
                #   The ThreadedCommand to start.
         
     | 
| 
       684 
857 
     | 
    
         
             
                #
         
     | 
| 
       685 
858 
     | 
    
         
             
                # @return [void]
         
     | 
| 
       686 
     | 
    
         
            -
                def  
     | 
| 
       687 
     | 
    
         
            -
                   
     | 
| 
       688 
     | 
    
         
            -
                     
     | 
| 
       689 
     | 
    
         
            -
             
     | 
| 
       690 
     | 
    
         
            -
                     
     | 
| 
       691 
     | 
    
         
            -
                       
     | 
| 
       692 
     | 
    
         
            -
             
     | 
| 
       693 
     | 
    
         
            -
             
     | 
| 
       694 
     | 
    
         
            -
             
     | 
| 
       695 
     | 
    
         
            -
             
     | 
| 
      
 859 
     | 
    
         
            +
                def start_threaded_command(tc)
         
     | 
| 
      
 860 
     | 
    
         
            +
                  if @echo == :command
         
     | 
| 
      
 861 
     | 
    
         
            +
                    puts command_to_s(tc.command)
         
     | 
| 
      
 862 
     | 
    
         
            +
                  elsif @echo == :short
         
     | 
| 
      
 863 
     | 
    
         
            +
                    if tc.short_description
         
     | 
| 
      
 864 
     | 
    
         
            +
                      puts tc.short_description
         
     | 
| 
      
 865 
     | 
    
         
            +
                    end
         
     | 
| 
      
 866 
     | 
    
         
            +
                  end
         
     | 
| 
      
 867 
     | 
    
         
            +
             
     | 
| 
      
 868 
     | 
    
         
            +
                  env_args = tc.system_env ? [tc.system_env] : []
         
     | 
| 
      
 869 
     | 
    
         
            +
                  options_args = tc.system_options ? [tc.system_options] : []
         
     | 
| 
      
 870 
     | 
    
         
            +
                  system_args = [*env_args, *Rscons.command_executer, *tc.command, *options_args]
         
     | 
| 
      
 871 
     | 
    
         
            +
             
     | 
| 
      
 872 
     | 
    
         
            +
                  tc.thread = Thread.new do
         
     | 
| 
      
 873 
     | 
    
         
            +
                    system(*system_args)
         
     | 
| 
      
 874 
     | 
    
         
            +
                  end
         
     | 
| 
      
 875 
     | 
    
         
            +
                  @threaded_commands << tc
         
     | 
| 
      
 876 
     | 
    
         
            +
                end
         
     | 
| 
      
 877 
     | 
    
         
            +
             
     | 
| 
      
 878 
     | 
    
         
            +
                # Wait for threaded commands to complete.
         
     | 
| 
      
 879 
     | 
    
         
            +
                #
         
     | 
| 
      
 880 
     | 
    
         
            +
                # @param options [Hash]
         
     | 
| 
      
 881 
     | 
    
         
            +
                #   Options.
         
     | 
| 
      
 882 
     | 
    
         
            +
                # @option options [Set<ThreadedCommand>, Array<ThreadedCommand>] :which
         
     | 
| 
      
 883 
     | 
    
         
            +
                #   Which {ThreadedCommand} objects to wait for. If not specified, this
         
     | 
| 
      
 884 
     | 
    
         
            +
                #   method will wait for any.
         
     | 
| 
      
 885 
     | 
    
         
            +
                # @option options [Boolean] :nonblock
         
     | 
| 
      
 886 
     | 
    
         
            +
                #   Set to true to not block.
         
     | 
| 
      
 887 
     | 
    
         
            +
                #
         
     | 
| 
      
 888 
     | 
    
         
            +
                # @return [ThreadedCommand, nil]
         
     | 
| 
      
 889 
     | 
    
         
            +
                #   The {ThreadedCommand} object that is finished.
         
     | 
| 
      
 890 
     | 
    
         
            +
                def wait_for_threaded_commands(options = {})
         
     | 
| 
      
 891 
     | 
    
         
            +
                  options[:which] ||= @threaded_commands
         
     | 
| 
      
 892 
     | 
    
         
            +
                  threads = options[:which].map(&:thread)
         
     | 
| 
      
 893 
     | 
    
         
            +
                  if finished_thread = find_finished_thread(threads, options[:nonblock])
         
     | 
| 
      
 894 
     | 
    
         
            +
                    threaded_command = @threaded_commands.find do |tc|
         
     | 
| 
      
 895 
     | 
    
         
            +
                      tc.thread == finished_thread
         
     | 
| 
      
 896 
     | 
    
         
            +
                    end
         
     | 
| 
      
 897 
     | 
    
         
            +
                    @threaded_commands.delete(threaded_command)
         
     | 
| 
      
 898 
     | 
    
         
            +
                    threaded_command
         
     | 
| 
      
 899 
     | 
    
         
            +
                  end
         
     | 
| 
      
 900 
     | 
    
         
            +
                end
         
     | 
| 
      
 901 
     | 
    
         
            +
             
     | 
| 
      
 902 
     | 
    
         
            +
                # Check if any of the requested threads are finished.
         
     | 
| 
      
 903 
     | 
    
         
            +
                #
         
     | 
| 
      
 904 
     | 
    
         
            +
                # @param threads [Array<Thread>]
         
     | 
| 
      
 905 
     | 
    
         
            +
                #   The threads to check.
         
     | 
| 
      
 906 
     | 
    
         
            +
                # @param nonblock [Boolean]
         
     | 
| 
      
 907 
     | 
    
         
            +
                #   Whether to be non-blocking. If true, nil will be returned if no thread
         
     | 
| 
      
 908 
     | 
    
         
            +
                #   is finished. If false, the method will wait until one of the threads
         
     | 
| 
      
 909 
     | 
    
         
            +
                #   is finished.
         
     | 
| 
      
 910 
     | 
    
         
            +
                #
         
     | 
| 
      
 911 
     | 
    
         
            +
                # @return [Thread, nil]
         
     | 
| 
      
 912 
     | 
    
         
            +
                #   The finished thread, if any.
         
     | 
| 
      
 913 
     | 
    
         
            +
                def find_finished_thread(threads, nonblock)
         
     | 
| 
      
 914 
     | 
    
         
            +
                  if nonblock
         
     | 
| 
      
 915 
     | 
    
         
            +
                    threads.find do |thread|
         
     | 
| 
      
 916 
     | 
    
         
            +
                      !thread.alive?
         
     | 
| 
      
 917 
     | 
    
         
            +
                    end
         
     | 
| 
      
 918 
     | 
    
         
            +
                  else
         
     | 
| 
      
 919 
     | 
    
         
            +
                    if threads.empty?
         
     | 
| 
      
 920 
     | 
    
         
            +
                      raise "No threads to wait for"
         
     | 
| 
      
 921 
     | 
    
         
            +
                    end
         
     | 
| 
      
 922 
     | 
    
         
            +
                    ThreadsWait.new(*threads).next_wait
         
     | 
| 
      
 923 
     | 
    
         
            +
                  end
         
     | 
| 
      
 924 
     | 
    
         
            +
                end
         
     | 
| 
      
 925 
     | 
    
         
            +
             
     | 
| 
      
 926 
     | 
    
         
            +
                # Return a string representation of a command.
         
     | 
| 
      
 927 
     | 
    
         
            +
                #
         
     | 
| 
      
 928 
     | 
    
         
            +
                # @param command [Array<String>]
         
     | 
| 
      
 929 
     | 
    
         
            +
                #   The command.
         
     | 
| 
      
 930 
     | 
    
         
            +
                #
         
     | 
| 
      
 931 
     | 
    
         
            +
                # @return [String]
         
     | 
| 
      
 932 
     | 
    
         
            +
                #   The string representation of the command.
         
     | 
| 
      
 933 
     | 
    
         
            +
                def command_to_s(command)
         
     | 
| 
      
 934 
     | 
    
         
            +
                  command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
         
     | 
| 
      
 935 
     | 
    
         
            +
                end
         
     | 
| 
      
 936 
     | 
    
         
            +
             
     | 
| 
      
 937 
     | 
    
         
            +
                # Call a builder's #finalize method after a ThreadedCommand terminates.
         
     | 
| 
      
 938 
     | 
    
         
            +
                #
         
     | 
| 
      
 939 
     | 
    
         
            +
                # @param tc [ThreadedCommand]
         
     | 
| 
      
 940 
     | 
    
         
            +
                #   The ThreadedCommand returned from the builder's #run method.
         
     | 
| 
      
 941 
     | 
    
         
            +
                #
         
     | 
| 
      
 942 
     | 
    
         
            +
                # @return [String, false]
         
     | 
| 
      
 943 
     | 
    
         
            +
                #   Result of Builder#finalize.
         
     | 
| 
      
 944 
     | 
    
         
            +
                def finalize_builder(tc)
         
     | 
| 
      
 945 
     | 
    
         
            +
                  tc.build_operation[:builder].finalize(
         
     | 
| 
      
 946 
     | 
    
         
            +
                    tc.build_operation.merge(
         
     | 
| 
      
 947 
     | 
    
         
            +
                      command_status: tc.thread.value,
         
     | 
| 
      
 948 
     | 
    
         
            +
                      tc: tc))
         
     | 
| 
      
 949 
     | 
    
         
            +
                end
         
     | 
| 
      
 950 
     | 
    
         
            +
             
     | 
| 
      
 951 
     | 
    
         
            +
                # Find a builder that meets the requested features and produces a target
         
     | 
| 
      
 952 
     | 
    
         
            +
                # of the requested name.
         
     | 
| 
      
 953 
     | 
    
         
            +
                #
         
     | 
| 
      
 954 
     | 
    
         
            +
                # @param target [String]
         
     | 
| 
      
 955 
     | 
    
         
            +
                #   Target file name.
         
     | 
| 
      
 956 
     | 
    
         
            +
                # @param source [String]
         
     | 
| 
      
 957 
     | 
    
         
            +
                #   Source file name.
         
     | 
| 
      
 958 
     | 
    
         
            +
                # @param features [Array<String>]
         
     | 
| 
      
 959 
     | 
    
         
            +
                #   See {#register_builds}.
         
     | 
| 
      
 960 
     | 
    
         
            +
                #
         
     | 
| 
      
 961 
     | 
    
         
            +
                # @return [Builder, nil]
         
     | 
| 
      
 962 
     | 
    
         
            +
                #   The builder found, if any.
         
     | 
| 
      
 963 
     | 
    
         
            +
                def find_builder_for(target, source, features)
         
     | 
| 
      
 964 
     | 
    
         
            +
                  @builders.values.find do |builder|
         
     | 
| 
      
 965 
     | 
    
         
            +
                    features_met?(builder, features) and builder.produces?(target, source, self)
         
     | 
| 
      
 966 
     | 
    
         
            +
                  end
         
     | 
| 
      
 967 
     | 
    
         
            +
                end
         
     | 
| 
      
 968 
     | 
    
         
            +
             
     | 
| 
      
 969 
     | 
    
         
            +
                # Determine if a builder meets the requested features.
         
     | 
| 
      
 970 
     | 
    
         
            +
                #
         
     | 
| 
      
 971 
     | 
    
         
            +
                # @param builder [Builder]
         
     | 
| 
      
 972 
     | 
    
         
            +
                #   The builder.
         
     | 
| 
      
 973 
     | 
    
         
            +
                # @param features [Array<String>]
         
     | 
| 
      
 974 
     | 
    
         
            +
                #   See {#register_builds}.
         
     | 
| 
      
 975 
     | 
    
         
            +
                #
         
     | 
| 
      
 976 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 977 
     | 
    
         
            +
                #   Whether the builder meets the requested features.
         
     | 
| 
      
 978 
     | 
    
         
            +
                def features_met?(builder, features)
         
     | 
| 
      
 979 
     | 
    
         
            +
                  builder_features = builder.features
         
     | 
| 
      
 980 
     | 
    
         
            +
                  features.all? do |feature|
         
     | 
| 
      
 981 
     | 
    
         
            +
                    want_feature = true
         
     | 
| 
      
 982 
     | 
    
         
            +
                    if feature =~ /^-(.*)$/
         
     | 
| 
      
 983 
     | 
    
         
            +
                      want_feature = false
         
     | 
| 
      
 984 
     | 
    
         
            +
                      feature = $1
         
     | 
| 
       696 
985 
     | 
    
         
             
                    end
         
     | 
| 
       697 
     | 
    
         
            -
                     
     | 
| 
      
 986 
     | 
    
         
            +
                    builder_has_feature = builder_features.include?(feature)
         
     | 
| 
      
 987 
     | 
    
         
            +
                    want_feature ? builder_has_feature : !builder_has_feature
         
     | 
| 
       698 
988 
     | 
    
         
             
                  end
         
     | 
| 
       699 
989 
     | 
    
         
             
                end
         
     | 
| 
       700 
990 
     | 
    
         |