Rework builder interface to only use #run method - close #91
The builder's #run method will be called repeatedly until it returns true or false. The Builder#wait_for method can be used to cause a builder to wait for a Thread, Command, or another Builder.
This commit is contained in:
parent
8426a54a57
commit
b882f8de99
@ -5,7 +5,7 @@ class MySource < Rscons::Builder
|
|||||||
#define THE_VALUE 5678
|
#define THE_VALUE 5678
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ class MySource < Rscons::Builder
|
|||||||
#define THE_VALUE 678
|
#define THE_VALUE 678
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ class MySource < Rscons::Builder
|
|||||||
#define THE_VALUE #{@env.expand_varref("${the_value}")}
|
#define THE_VALUE #{@env.expand_varref("${the_value}")}
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
8
build_tests/custom_builder/error_run_return_value.rb
Normal file
8
build_tests/custom_builder/error_run_return_value.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.add_builder(:MyBuilder) do |options|
|
||||||
|
"hi"
|
||||||
|
end
|
||||||
|
env.MyBuilder("foo")
|
||||||
|
end
|
||||||
|
end
|
8
build_tests/custom_builder/error_wait_for.rb
Normal file
8
build_tests/custom_builder/error_wait_for.rb
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.add_builder(:MyBuilder) do |options|
|
||||||
|
wait_for(1)
|
||||||
|
end
|
||||||
|
env.MyBuilder("foo")
|
||||||
|
end
|
||||||
|
end
|
@ -8,7 +8,7 @@ class CHGen < Rscons::Builder
|
|||||||
File.open(h_fname, "w") {|fh| fh.puts "extern int THE_VALUE;"}
|
File.open(h_fname, "w") {|fh| fh.puts "extern int THE_VALUE;"}
|
||||||
@cache.register_build([c_fname, h_fname], "", @sources, @env)
|
@cache.register_build([c_fname, h_fname], "", @sources, @env)
|
||||||
end
|
end
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
21
build_tests/custom_builder/wait_for_thread.rb
Normal file
21
build_tests/custom_builder/wait_for_thread.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
class MyBuilder < Rscons::Builder
|
||||||
|
def run(options)
|
||||||
|
if @thread
|
||||||
|
true
|
||||||
|
else
|
||||||
|
@env.print_builder_run_message("#{name} #{target}", nil)
|
||||||
|
@thread = Thread.new do
|
||||||
|
sleep 2
|
||||||
|
FileUtils.touch(@target)
|
||||||
|
end
|
||||||
|
wait_for(@thread)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
build do
|
||||||
|
Environment.new do |env|
|
||||||
|
env.add_builder(MyBuilder)
|
||||||
|
env.MyBuilder("foo")
|
||||||
|
end
|
||||||
|
end
|
@ -10,7 +10,7 @@ build do
|
|||||||
end
|
end
|
||||||
@cache.register_build(@target, :JsonToYaml, @sources, @env)
|
@cache.register_build(@target, :JsonToYaml, @sources, @env)
|
||||||
end
|
end
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
env.JsonToYaml('foo.yml', 'foo.json')
|
env.JsonToYaml('foo.yml', 'foo.json')
|
||||||
end
|
end
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
class TestBuilder < Rscons::Builder
|
class TestBuilder < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
build do
|
build do
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
class DebugBuilder < Rscons::Builder
|
class DebugBuilder < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
command = %W[gcc -c -o #{@target} #{@sources.first}]
|
if @command
|
||||||
if Rscons.vars["command_change"]
|
finalize_command
|
||||||
command += %w[-Wall]
|
|
||||||
end
|
|
||||||
if Rscons.vars["new_dep"]
|
|
||||||
@sources += ["extra"]
|
|
||||||
end
|
|
||||||
if Rscons.vars["strict_deps1"]
|
|
||||||
@sources += ["extra"]
|
|
||||||
strict_deps = true
|
|
||||||
end
|
|
||||||
if Rscons.vars["strict_deps2"]
|
|
||||||
@sources = ["extra"] + @sources
|
|
||||||
strict_deps = true
|
|
||||||
end
|
|
||||||
if @cache.up_to_date?(@target, command, @sources, @env, debug: true, strict_deps: strict_deps)
|
|
||||||
@target
|
|
||||||
else
|
else
|
||||||
ThreadedCommand.new(command, short_description: "#{name} #{@target}")
|
@command = %W[gcc -c -o #{@target} #{@sources.first}]
|
||||||
|
if Rscons.vars["command_change"]
|
||||||
|
@command += %w[-Wall]
|
||||||
|
end
|
||||||
|
if Rscons.vars["new_dep"]
|
||||||
|
@sources += ["extra"]
|
||||||
|
end
|
||||||
|
if Rscons.vars["strict_deps1"]
|
||||||
|
@sources += ["extra"]
|
||||||
|
strict_deps = true
|
||||||
|
end
|
||||||
|
if Rscons.vars["strict_deps2"]
|
||||||
|
@sources = ["extra"] + @sources
|
||||||
|
strict_deps = true
|
||||||
|
end
|
||||||
|
if @cache.up_to_date?(@target, @command, @sources, @env, debug: true, strict_deps: strict_deps)
|
||||||
|
true
|
||||||
|
else
|
||||||
|
register_command("#{name} #{target}", @command)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def finalize(options)
|
|
||||||
standard_finalize(options)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
build do
|
build do
|
||||||
|
@ -9,7 +9,7 @@ class TestBuilder < Rscons::Builder
|
|||||||
@env.print_builder_run_message(msg, msg)
|
@env.print_builder_run_message(msg, msg)
|
||||||
@cache.register_build(@target, command, @sources, @env)
|
@cache.register_build(@target, command, @sources, @env)
|
||||||
end
|
end
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ build do
|
|||||||
puts "Checker #{@sources.first}" if @env.echo != :off
|
puts "Checker #{@sources.first}" if @env.echo != :off
|
||||||
@cache.register_build(@target, :Checker, @sources, @env)
|
@cache.register_build(@target, :Checker, @sources, @env)
|
||||||
end
|
end
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
env.Program("simple.exe", "simple.c")
|
env.Program("simple.exe", "simple.c")
|
||||||
env.Checker(:checker, "simple.exe")
|
env.Checker(:checker, "simple.exe")
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
class ThreadedTestBuilder < Rscons::Builder
|
class ThreadedTestBuilder < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
command = ["ruby", "-e", %[sleep 1]]
|
if @command
|
||||||
Rscons::ThreadedCommand.new(
|
true
|
||||||
command,
|
else
|
||||||
short_description: "ThreadedTestBuilder #{@target}")
|
@command = ["ruby", "-e", %[sleep 1]]
|
||||||
end
|
register_command("ThreadedTestBuilder #{@target}", @command)
|
||||||
def finalize(options)
|
end
|
||||||
true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -14,7 +13,7 @@ class NonThreadedTestBuilder < Rscons::Builder
|
|||||||
def run(options)
|
def run(options)
|
||||||
puts "NonThreadedTestBuilder #{@target}"
|
puts "NonThreadedTestBuilder #{@target}"
|
||||||
sleep 1
|
sleep 1
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
class TestBuilder < Rscons::Builder
|
class TestBuilder < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
if @target == "two"
|
if @command
|
||||||
return false unless File.exists?("one")
|
true
|
||||||
|
else
|
||||||
|
if @target == "two"
|
||||||
|
return false unless File.exists?("one")
|
||||||
|
end
|
||||||
|
wait_time = @env.expand_varref("${wait_time}", @vars)
|
||||||
|
@command = ["ruby", "-e", "require 'fileutils'; sleep #{wait_time}; FileUtils.touch('#{@target}');"]
|
||||||
|
register_command("TestBuilder", @command)
|
||||||
end
|
end
|
||||||
wait_time = @env.expand_varref("${wait_time}", @vars)
|
|
||||||
command = ["ruby", "-e", "require 'fileutils'; sleep #{wait_time}; FileUtils.touch('#{@target}');"]
|
|
||||||
standard_threaded_build("TestBuilder", @target, command, [], @env, @cache)
|
|
||||||
end
|
|
||||||
|
|
||||||
def finalize(options)
|
|
||||||
standard_finalize(options)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
class Fail < Rscons::Builder
|
class Fail < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
wait_time = @env.expand_varref("${wait_time}", @vars)
|
if @command
|
||||||
ruby_command = %[sleep #{wait_time}; exit 2]
|
finalize_command
|
||||||
command = %W[ruby -e #{ruby_command}]
|
else
|
||||||
standard_threaded_build("Fail #{@target}", @target, command, [], @env, @cache)
|
wait_time = @env.expand_varref("${wait_time}", @vars)
|
||||||
end
|
ruby_command = %[sleep #{wait_time}; exit 2]
|
||||||
def finalize(options)
|
@command = %W[ruby -e #{ruby_command}]
|
||||||
standard_finalize(options)
|
register_command("Fail #{@target}", @command)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
class StrictBuilder < Rscons::Builder
|
class StrictBuilder < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
command = %W[gcc -o #{@target}] + @sources.sort
|
if @command
|
||||||
if @cache.up_to_date?(@target, command, @sources, @env, strict_deps: true)
|
finalize_command
|
||||||
@target
|
|
||||||
else
|
else
|
||||||
ThreadedCommand.new(command, short_description: "#{name} #{@target}")
|
@command = %W[gcc -o #{@target}] + @sources.sort
|
||||||
|
if @cache.up_to_date?(@target, @command, @sources, @env, strict_deps: true)
|
||||||
|
true
|
||||||
|
else
|
||||||
|
register_command("#{name} #{@target}", @command)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def finalize(options)
|
|
||||||
standard_finalize(options)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
build do
|
build do
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
class MyBuilder < Rscons::Builder
|
class MyBuilder < Rscons::Builder
|
||||||
def run(options)
|
def run(options)
|
||||||
@env.print_builder_run_message("MyBuilder #{@target}", "MyBuilder #{@target} command")
|
@env.print_builder_run_message("MyBuilder #{@target}", "MyBuilder #{@target} command")
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ require_relative "rscons/builder_builder"
|
|||||||
require_relative "rscons/builder_set"
|
require_relative "rscons/builder_set"
|
||||||
require_relative "rscons/cache"
|
require_relative "rscons/cache"
|
||||||
require_relative "rscons/configure_op"
|
require_relative "rscons/configure_op"
|
||||||
|
require_relative "rscons/command"
|
||||||
require_relative "rscons/environment"
|
require_relative "rscons/environment"
|
||||||
require_relative "rscons/script"
|
require_relative "rscons/script"
|
||||||
require_relative "rscons/threaded_command"
|
|
||||||
require_relative "rscons/util"
|
require_relative "rscons/util"
|
||||||
require_relative "rscons/varset"
|
require_relative "rscons/varset"
|
||||||
require_relative "rscons/version"
|
require_relative "rscons/version"
|
||||||
|
@ -6,6 +6,7 @@ module Rscons
|
|||||||
|
|
||||||
# Class to hold an object that knows how to build a certain type of file.
|
# Class to hold an object that knows how to build a certain type of file.
|
||||||
class Builder
|
class Builder
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
# Return the name of the builder.
|
# Return the name of the builder.
|
||||||
#
|
#
|
||||||
@ -108,104 +109,97 @@ module Rscons
|
|||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Run options.
|
# Run options.
|
||||||
#
|
#
|
||||||
# @return [ThreadedCommand,String,false]
|
# @return [Object]
|
||||||
# Name of the target file on success or false on failure.
|
# If the build operation fails, this method should return +false+.
|
||||||
# Since 1.10.0, this method may return an instance of {ThreadedCommand}.
|
# If the build operation succeeds, this method should return +true+.
|
||||||
# In that case, the build operation has not actually been completed yet
|
# If the build operation is not yet complete and is waiting on other
|
||||||
# but the command to do so will be executed by Rscons in a separate
|
# operations, this method should return the return value from the
|
||||||
# thread. This allows for build parallelization. If a {ThreadedCommand}
|
# {#wait_for} method.
|
||||||
# object is returned, the {#finalize} method will be called after the
|
|
||||||
# command has completed. The {#finalize} method should then be used to
|
|
||||||
# record cache info, if needed, and to return the true result of the
|
|
||||||
# build operation. The builder can store information to be passed in to
|
|
||||||
# the {#finalize} method by populating the :builder_info field of the
|
|
||||||
# {ThreadedCommand} object returned here.
|
|
||||||
def run(options)
|
def run(options)
|
||||||
raise "This method must be overridden in a subclass"
|
raise "This method must be overridden in a subclass"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Finalize a build operation.
|
# Create a {Command} object to execute the build command in a thread.
|
||||||
#
|
#
|
||||||
# This method is called after the {#run} method if the {#run} method
|
# @param short_description [String]
|
||||||
# returns a {ThreadedCommand} object.
|
|
||||||
#
|
|
||||||
# @since 1.10.0
|
|
||||||
#
|
|
||||||
# @param options [Hash]
|
|
||||||
# Options.
|
|
||||||
# @option options [String] :target
|
|
||||||
# Target file name.
|
|
||||||
# @option options [Array<String>] :sources
|
|
||||||
# Source file name(s).
|
|
||||||
# @option options [Cache] :cache
|
|
||||||
# The Cache object.
|
|
||||||
# @option options [Environment] :env
|
|
||||||
# The Environment executing the builder.
|
|
||||||
# @option options [Hash,VarSet] :vars
|
|
||||||
# Extra construction variables.
|
|
||||||
# @option options [true,false,nil] :command_status
|
|
||||||
# If the {#run} method returns a {ThreadedCommand}, this field will
|
|
||||||
# contain the return value from executing the command with
|
|
||||||
# Kernel.system().
|
|
||||||
# @option options [ThreadedCommand] :tc
|
|
||||||
# The {ThreadedCommand} object that was returned by the #run method.
|
|
||||||
#
|
|
||||||
# @return [String,false]
|
|
||||||
# Name of the target file on success or false on failure.
|
|
||||||
def finalize(options)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Check if the cache is up to date for the target and if not create a
|
|
||||||
# {ThreadedCommand} object to execute the build command in a thread.
|
|
||||||
#
|
|
||||||
# @since 1.10.0
|
|
||||||
#
|
|
||||||
# @param short_cmd_string [String]
|
|
||||||
# Short description of build action to be printed when env.echo ==
|
# Short description of build action to be printed when env.echo ==
|
||||||
# :short.
|
# :short.
|
||||||
# @param target [String] Name of the target file.
|
|
||||||
# @param command [Array<String>]
|
# @param command [Array<String>]
|
||||||
# The command to execute to build the target.
|
# The command to execute.
|
||||||
# @param sources [Array<String>] Source file name(s).
|
# @param options [Hash]
|
||||||
# @param env [Environment] The Environment executing the builder.
|
# Options.
|
||||||
# @param cache [Cache] The Cache object.
|
|
||||||
# @param options [Hash] Options.
|
|
||||||
# @option options [String] :stdout
|
# @option options [String] :stdout
|
||||||
# File name to redirect standard output to.
|
# File name to redirect standard output to.
|
||||||
#
|
#
|
||||||
# @return [String,ThreadedCommand]
|
# @return [Object]
|
||||||
# The name of the target if it is already up to date or the
|
# Return value for {#run} method.
|
||||||
# {ThreadedCommand} object created to update it.
|
def register_command(short_description, command, options = {})
|
||||||
def standard_threaded_build(short_cmd_string, target, command, sources, env, cache, options = {})
|
command_options = {}
|
||||||
if cache.up_to_date?(target, command, sources, env)
|
if options[:stdout]
|
||||||
target
|
command_options[:system_options] = {out: options[:stdout]}
|
||||||
|
end
|
||||||
|
@env.print_builder_run_message(short_description, @command)
|
||||||
|
wait_for(Command.new(command, self, command_options))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if the cache is up to date for the target and if not create a
|
||||||
|
# {Command} object to execute the build command in a thread.
|
||||||
|
#
|
||||||
|
# @param short_description [String]
|
||||||
|
# Short description of build action to be printed when env.echo ==
|
||||||
|
# :short.
|
||||||
|
# @param command [Array<String>]
|
||||||
|
# The command to execute.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Options.
|
||||||
|
# @option options [Array<String>] :sources
|
||||||
|
# Sources to override @sources.
|
||||||
|
# @option options [String] :stdout
|
||||||
|
# File name to redirect standard output to.
|
||||||
|
#
|
||||||
|
# @return [Object]
|
||||||
|
# Return value for {#run} method.
|
||||||
|
def standard_command(short_description, command, options = {})
|
||||||
|
@command = command
|
||||||
|
sources = options[:sources] || @sources
|
||||||
|
if @cache.up_to_date?(@target, @command, sources, @env)
|
||||||
|
true
|
||||||
else
|
else
|
||||||
unless Rscons.phony_target?(target)
|
unless Rscons.phony_target?(@target)
|
||||||
cache.mkdir_p(File.dirname(target))
|
@cache.mkdir_p(File.dirname(@target))
|
||||||
FileUtils.rm_f(target)
|
FileUtils.rm_f(@target)
|
||||||
end
|
end
|
||||||
tc_options = {short_description: short_cmd_string}
|
register_command(short_description, @command, options)
|
||||||
if options[:stdout]
|
|
||||||
tc_options[:system_options] = {out: options[:stdout]}
|
|
||||||
end
|
|
||||||
ThreadedCommand.new(command, tc_options)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Register build results from a {ThreadedCommand} with the cache.
|
# Register build results from a {Command} with the cache.
|
||||||
#
|
#
|
||||||
# @since 1.10.0
|
# @since 1.10.0
|
||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Builder finalize options.
|
# Builder finalize options.
|
||||||
|
# @option options [String] :stdout
|
||||||
|
# File name to redirect standard output to.
|
||||||
#
|
#
|
||||||
# @return [String, nil]
|
# @return [true]
|
||||||
# The target name on success or nil on failure.
|
# Return value for {#run} method.
|
||||||
def standard_finalize(options)
|
def finalize_command(options = {})
|
||||||
if options[:command_status]
|
sources = options[:sources] || @sources
|
||||||
@cache.register_build(@target, options[:tc].command, @sources, @env)
|
@cache.register_build(@target, @command, sources, @env)
|
||||||
@target
|
true
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# A builder can indicate to Rscons that it needs to wait for a separate
|
||||||
|
# operation to complete by using this method. The return value from this
|
||||||
|
# method should be returned from the builder's #run method.
|
||||||
|
#
|
||||||
|
# @param things [Builder, Command, Thread, Array<Builder, Command, Thread>]
|
||||||
|
# Builder(s) or Command(s) or Thread(s) that this builder needs to wait
|
||||||
|
# for.
|
||||||
|
def wait_for(things)
|
||||||
|
Array(things)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -3,21 +3,15 @@ module Rscons
|
|||||||
# it is needed.
|
# it is needed.
|
||||||
class BuilderBuilder
|
class BuilderBuilder
|
||||||
|
|
||||||
# @return [String] Builder name.
|
|
||||||
attr_reader :name
|
|
||||||
|
|
||||||
# Create a BuilderBuilder.
|
# Create a BuilderBuilder.
|
||||||
#
|
#
|
||||||
# @param name [String]
|
|
||||||
# Builder name.
|
|
||||||
# @param builder_class [Class]
|
# @param builder_class [Class]
|
||||||
# The {Builder} class to be instantiated.
|
# The {Builder} class to be instantiated.
|
||||||
# @param builder_args [Array]
|
# @param builder_args [Array]
|
||||||
# Any extra arguments to be passed to the builder class.
|
# Any extra arguments to be passed to the builder class.
|
||||||
# @param builder_block [Proc, nil]
|
# @param builder_block [Proc, nil]
|
||||||
# Optional block to be passed to the {Builder} class's #new method.
|
# Optional block to be passed to the {Builder} class's #new method.
|
||||||
def initialize(name, builder_class, *builder_args, &builder_block)
|
def initialize(builder_class, *builder_args, &builder_block)
|
||||||
@name = name
|
|
||||||
@builder_class = builder_class
|
@builder_class = builder_class
|
||||||
@builder_args = builder_args
|
@builder_args = builder_args
|
||||||
@builder_block = builder_block
|
@builder_block = builder_block
|
||||||
@ -26,7 +20,7 @@ module Rscons
|
|||||||
# Act like a regular {Builder} class object but really instantiate the
|
# Act like a regular {Builder} class object but really instantiate the
|
||||||
# requested {Builder} class, potentially with extra arguments and a block.
|
# requested {Builder} class, potentially with extra arguments and a block.
|
||||||
def new(*args)
|
def new(*args)
|
||||||
@builder_class.new(*args, *@builder_args, &@builder_block)
|
@builder_class.new(*@builder_args, *args, &@builder_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -21,30 +21,23 @@ module Rscons
|
|||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
def run(options)
|
def run(options)
|
||||||
@vars["_TARGET"] = @target
|
if @command
|
||||||
@vars["_SOURCES"] = @sources
|
finalize_command
|
||||||
cmd =
|
else
|
||||||
case
|
@vars["_TARGET"] = @target
|
||||||
when @sources.first.end_with?(*@env.expand_varref("${LEXSUFFIX}"))
|
@vars["_SOURCES"] = @sources
|
||||||
"LEX"
|
cmd =
|
||||||
when @sources.first.end_with?(*@env.expand_varref("${YACCSUFFIX}"))
|
case
|
||||||
"YACC"
|
when @sources.first.end_with?(*@env.expand_varref("${LEXSUFFIX}"))
|
||||||
else
|
"LEX"
|
||||||
raise "Unknown source file #{@sources.first.inspect} for CFile builder"
|
when @sources.first.end_with?(*@env.expand_varref("${YACCSUFFIX}"))
|
||||||
end
|
"YACC"
|
||||||
command = @env.build_command("${#{cmd}_CMD}", @vars)
|
else
|
||||||
standard_threaded_build("#{cmd} #{@target}", @target, command, @sources, @env, @cache)
|
raise "Unknown source file #{@sources.first.inspect} for CFile builder"
|
||||||
end
|
end
|
||||||
|
command = @env.build_command("${#{cmd}_CMD}", @vars)
|
||||||
# Finalize a build.
|
standard_command("#{cmd} #{@target}", command)
|
||||||
#
|
end
|
||||||
# @param options [Hash]
|
|
||||||
# Finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# The target name on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
standard_finalize(options)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
module Rscons
|
module Rscons
|
||||||
module Builders
|
module Builders
|
||||||
# Execute a command that will produce the given target based on the given
|
# A builder to execute an arbitrary command that will produce the given
|
||||||
# sources.
|
# target based on the given sources.
|
||||||
#
|
#
|
||||||
# @since 1.8.0
|
# @since 1.8.0
|
||||||
#
|
#
|
||||||
@ -11,33 +11,20 @@ module Rscons
|
|||||||
class Command < Builder
|
class Command < Builder
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
#
|
|
||||||
# @param options [Hash] Builder run options.
|
|
||||||
#
|
|
||||||
# @return [String, ThreadedCommand]
|
|
||||||
# Target file name if target is up to date or a {ThreadedCommand}
|
|
||||||
# to execute to build the target.
|
|
||||||
def run(options)
|
def run(options)
|
||||||
@vars["_TARGET"] = @target
|
if @command
|
||||||
@vars["_SOURCES"] = @sources
|
finalize_command
|
||||||
command = @env.build_command("${CMD}", @vars)
|
else
|
||||||
cmd_desc = @vars["CMD_DESC"] || "Command"
|
@vars["_TARGET"] = @target
|
||||||
options = {}
|
@vars["_SOURCES"] = @sources
|
||||||
if @vars["CMD_STDOUT"]
|
command = @env.build_command("${CMD}", @vars)
|
||||||
options[:stdout] = @env.expand_varref("${CMD_STDOUT}", @vars)
|
cmd_desc = @vars["CMD_DESC"] || "Command"
|
||||||
|
options = {}
|
||||||
|
if @vars["CMD_STDOUT"]
|
||||||
|
options[:stdout] = @env.expand_varref("${CMD_STDOUT}", @vars)
|
||||||
|
end
|
||||||
|
standard_command("#{cmd_desc} #{@target}", command, options)
|
||||||
end
|
end
|
||||||
standard_threaded_build("#{cmd_desc} #{@target}", @target, command, @sources, @env, @cache, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Finalize a build.
|
|
||||||
#
|
|
||||||
# @param options [Hash]
|
|
||||||
# Finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# The target name on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
standard_finalize(options)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -6,14 +6,14 @@ module Rscons
|
|||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
def run(options)
|
def run(options)
|
||||||
if File.directory?(@target)
|
if File.directory?(@target)
|
||||||
@target
|
true
|
||||||
elsif File.exists?(@target)
|
elsif File.exists?(@target)
|
||||||
Ansi.write($stderr, :red, "Error: `#{@target}' already exists and is not a directory", :reset, "\n")
|
Ansi.write($stderr, :red, "Error: `#{@target}' already exists and is not a directory", :reset, "\n")
|
||||||
false
|
false
|
||||||
else
|
else
|
||||||
@env.print_builder_run_message("Directory #{@target}", nil)
|
@env.print_builder_run_message("Directory #{@target}", nil)
|
||||||
@cache.mkdir_p(@target)
|
@cache.mkdir_p(@target)
|
||||||
@target
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -11,30 +11,15 @@ module Rscons
|
|||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
def run(options)
|
def run(options)
|
||||||
@vars["_SOURCES"] = sources
|
if @command
|
||||||
command = @env.build_command("${DISASM_CMD}", @vars)
|
finalize_command
|
||||||
if @cache.up_to_date?(@target, command, @sources, @env)
|
|
||||||
@target
|
|
||||||
else
|
else
|
||||||
@cache.mkdir_p(File.dirname(@target))
|
@vars["_SOURCES"] = @sources
|
||||||
ThreadedCommand.new(
|
command = @env.build_command("${DISASM_CMD}", @vars)
|
||||||
command,
|
standard_command("Disassemble #{target}", command, stdout: @target)
|
||||||
short_description: "Disassemble #{@target}",
|
|
||||||
system_options: {out: @target})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Finalize a build.
|
|
||||||
#
|
|
||||||
# @param options [Hash]
|
|
||||||
# Finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# The target name on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
standard_finalize(options)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -42,7 +42,7 @@ module Rscons
|
|||||||
end
|
end
|
||||||
@cache.register_build(dest, :Copy, [src], @env)
|
@cache.register_build(dest, :Copy, [src], @env)
|
||||||
end
|
end
|
||||||
@target if (target_is_dir ? Dir.exists?(@target) : File.exists?(@target))
|
(target_is_dir ? Dir.exists?(@target) : File.exists?(@target)) ? true : false
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -11,17 +11,6 @@ module Rscons
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Create an instance of the Builder to build a target.
|
# Create an instance of the Builder to build a target.
|
||||||
#
|
|
||||||
# @param options [Hash]
|
|
||||||
# Options.
|
|
||||||
# @option options [String] :target
|
|
||||||
# Target file name.
|
|
||||||
# @option options [Array<String>] :sources
|
|
||||||
# Source file name(s).
|
|
||||||
# @option options [Environment] :env
|
|
||||||
# The Environment executing the builder.
|
|
||||||
# @option options [Hash,VarSet] :vars
|
|
||||||
# Extra construction variables.
|
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
super(options)
|
super(options)
|
||||||
suffixes = @env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], @vars)
|
suffixes = @env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], @vars)
|
||||||
@ -30,29 +19,15 @@ module Rscons
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
#
|
|
||||||
# @param options [Hash] Builder run options.
|
|
||||||
#
|
|
||||||
# @return [String,false]
|
|
||||||
# Name of the target file on success or false on failure.
|
|
||||||
def run(options)
|
def run(options)
|
||||||
@vars["_TARGET"] = @target
|
if @command
|
||||||
@vars["_SOURCES"] = @objects
|
finalize_command(sources: @objects)
|
||||||
command = @env.build_command("${ARCMD}", @vars)
|
true
|
||||||
standard_threaded_build("AR #{@target}", @target, command, @objects, @env, @cache)
|
else
|
||||||
end
|
@vars["_TARGET"] = @target
|
||||||
|
@vars["_SOURCES"] = @objects
|
||||||
# Finalize a build.
|
command = @env.build_command("${ARCMD}", @vars)
|
||||||
#
|
standard_command("AR #{@target}", command, sources: @objects)
|
||||||
# @param options [Hash]
|
|
||||||
# Finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# The target name on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
if options[:command_status]
|
|
||||||
@cache.register_build(@target, options[:tc].command, @objects, @env)
|
|
||||||
@target
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -76,40 +76,26 @@ module Rscons
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
#
|
|
||||||
# @param options [Hash] Builder run options.
|
|
||||||
#
|
|
||||||
# @return [String, ThreadedCommand]
|
|
||||||
# Target file name if target is up to date or a {ThreadedCommand}
|
|
||||||
# to execute to build the target.
|
|
||||||
def run(options)
|
def run(options)
|
||||||
@vars["_TARGET"] = @target
|
if @command
|
||||||
@vars["_SOURCES"] = @sources
|
|
||||||
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
|
||||||
com_prefix = KNOWN_SUFFIXES.find do |compiler, suffix_var|
|
|
||||||
@sources.first.end_with?(*@env.expand_varref("${#{suffix_var}}", @vars))
|
|
||||||
end.tap do |v|
|
|
||||||
v.nil? and raise "Error: unknown input file type: #{@sources.first.inspect}"
|
|
||||||
end.first
|
|
||||||
command = @env.build_command("${#{com_prefix}CMD}", @vars)
|
|
||||||
@env.produces(@target, @vars["_DEPFILE"])
|
|
||||||
standard_threaded_build("#{com_prefix} #{@target}", @target, command, @sources, @env, @cache)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Finalize the build operation.
|
|
||||||
#
|
|
||||||
# @param options [Hash] Builder finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# Name of the target file on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
if options[:command_status]
|
|
||||||
deps = @sources
|
deps = @sources
|
||||||
if File.exists?(@vars['_DEPFILE'])
|
if File.exists?(@vars["_DEPFILE"])
|
||||||
deps += Util.parse_makefile_deps(@vars['_DEPFILE'])
|
deps += Util.parse_makefile_deps(@vars["_DEPFILE"])
|
||||||
end
|
end
|
||||||
@cache.register_build(@target, options[:tc].command, deps.uniq, @env)
|
@cache.register_build(@target, @command, deps.uniq, @env)
|
||||||
@target
|
true
|
||||||
|
else
|
||||||
|
@vars["_TARGET"] = @target
|
||||||
|
@vars["_SOURCES"] = @sources
|
||||||
|
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
||||||
|
com_prefix = KNOWN_SUFFIXES.find do |compiler, suffix_var|
|
||||||
|
@sources.first.end_with?(*@env.expand_varref("${#{suffix_var}}", @vars))
|
||||||
|
end.tap do |v|
|
||||||
|
v.nil? and raise "Error: unknown input file type: #{@sources.first.inspect}"
|
||||||
|
end.first
|
||||||
|
command = @env.build_command("${#{com_prefix}CMD}", @vars)
|
||||||
|
@env.produces(@target, @vars["_DEPFILE"])
|
||||||
|
standard_command("#{com_prefix} #{@target}", command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -12,44 +12,30 @@ module Rscons
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
#
|
|
||||||
# @param options [Hash] Builder run options.
|
|
||||||
#
|
|
||||||
# @return [String, ThreadedCommand]
|
|
||||||
# Target file name if target is up to date or a {ThreadedCommand}
|
|
||||||
# to execute to build the target.
|
|
||||||
def run(options)
|
def run(options)
|
||||||
if @sources.find {|s| s.end_with?(*@env.expand_varref("${CXXSUFFIX}", @vars))}
|
if @command
|
||||||
pp_cc = "${CXX}"
|
|
||||||
depgen = "${CXXDEPGEN}"
|
|
||||||
else
|
|
||||||
pp_cc = "${CC}"
|
|
||||||
depgen = "${CCDEPGEN}"
|
|
||||||
end
|
|
||||||
@vars["_PREPROCESS_CC"] = pp_cc
|
|
||||||
@vars["_PREPROCESS_DEPGEN"] = depgen
|
|
||||||
@vars["_TARGET"] = @target
|
|
||||||
@vars["_SOURCES"] = @sources
|
|
||||||
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
|
||||||
command = @env.build_command("${CPP_CMD}", @vars)
|
|
||||||
@env.produces(@target, @vars["_DEPFILE"])
|
|
||||||
standard_threaded_build("#{name} #{@target}", @target, command, @sources, @env, @cache)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Finalize the build operation.
|
|
||||||
#
|
|
||||||
# @param options [Hash] Builder finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# Name of the target file on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
if options[:command_status]
|
|
||||||
deps = @sources
|
deps = @sources
|
||||||
if File.exists?(@vars['_DEPFILE'])
|
if File.exists?(@vars["_DEPFILE"])
|
||||||
deps += Util.parse_makefile_deps(@vars['_DEPFILE'])
|
deps += Util.parse_makefile_deps(@vars["_DEPFILE"])
|
||||||
end
|
end
|
||||||
@cache.register_build(@target, options[:tc].command, deps.uniq, @env)
|
@cache.register_build(@target, @command, deps.uniq, @env)
|
||||||
@target
|
true
|
||||||
|
else
|
||||||
|
if @sources.find {|s| s.end_with?(*@env.expand_varref("${CXXSUFFIX}", @vars))}
|
||||||
|
pp_cc = "${CXX}"
|
||||||
|
depgen = "${CXXDEPGEN}"
|
||||||
|
else
|
||||||
|
pp_cc = "${CC}"
|
||||||
|
depgen = "${CCDEPGEN}"
|
||||||
|
end
|
||||||
|
@vars["_PREPROCESS_CC"] = pp_cc
|
||||||
|
@vars["_PREPROCESS_DEPGEN"] = depgen
|
||||||
|
@vars["_TARGET"] = @target
|
||||||
|
@vars["_SOURCES"] = @sources
|
||||||
|
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
||||||
|
command = @env.build_command("${CPP_CMD}", @vars)
|
||||||
|
@env.produces(@target, @vars["_DEPFILE"])
|
||||||
|
standard_command("#{name} #{@target}", command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -40,40 +40,26 @@ module Rscons
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
#
|
|
||||||
# @param options [Hash] Builder run options.
|
|
||||||
#
|
|
||||||
# @return [String,false]
|
|
||||||
# Name of the target file on success or false on failure.
|
|
||||||
def run(options)
|
def run(options)
|
||||||
ld = @env.expand_varref("${LD}", @vars)
|
if @command
|
||||||
ld = if ld != ""
|
finalize_command(sources: @objects)
|
||||||
ld
|
true
|
||||||
elsif @sources.find {|s| s.end_with?(*@env.expand_varref("${DSUFFIX}", @vars))}
|
else
|
||||||
"${DC}"
|
ld = @env.expand_varref("${LD}", @vars)
|
||||||
elsif @sources.find {|s| s.end_with?(*@env.expand_varref("${CXXSUFFIX}", @vars))}
|
ld = if ld != ""
|
||||||
"${CXX}"
|
ld
|
||||||
else
|
elsif @sources.find {|s| s.end_with?(*@env.expand_varref("${DSUFFIX}", @vars))}
|
||||||
"${CC}"
|
"${DC}"
|
||||||
end
|
elsif @sources.find {|s| s.end_with?(*@env.expand_varref("${CXXSUFFIX}", @vars))}
|
||||||
@vars["_TARGET"] = @target
|
"${CXX}"
|
||||||
@vars["_SOURCES"] = @objects
|
else
|
||||||
@vars["LD"] = ld
|
"${CC}"
|
||||||
command = @env.build_command("${LDCMD}", @vars)
|
end
|
||||||
standard_threaded_build("LD #{@target}", @target, command, @objects, @env, @cache)
|
@vars["_TARGET"] = @target
|
||||||
end
|
@vars["_SOURCES"] = @objects
|
||||||
|
@vars["LD"] = ld
|
||||||
# Finalize a build.
|
command = @env.build_command("${LDCMD}", @vars)
|
||||||
#
|
standard_command("LD #{@target}", command, sources: @objects)
|
||||||
# @param options [Hash]
|
|
||||||
# Finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# The target name on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
if options[:command_status]
|
|
||||||
@cache.register_build(@target, options[:tc].command, @objects, @env)
|
|
||||||
@target
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,17 +25,6 @@ module Rscons
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Create an instance of the Builder to build a target.
|
# Create an instance of the Builder to build a target.
|
||||||
#
|
|
||||||
# @param options [Hash]
|
|
||||||
# Options.
|
|
||||||
# @option options [String] :target
|
|
||||||
# Target file name.
|
|
||||||
# @option options [Array<String>] :sources
|
|
||||||
# Source file name(s).
|
|
||||||
# @option options [Environment] :env
|
|
||||||
# The Environment executing the builder.
|
|
||||||
# @option options [Hash,VarSet] :vars
|
|
||||||
# Extra construction variables.
|
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
super(options)
|
super(options)
|
||||||
libprefix = @env.expand_varref("${SHLIBPREFIX}", @vars)
|
libprefix = @env.expand_varref("${SHLIBPREFIX}", @vars)
|
||||||
@ -52,40 +41,26 @@ module Rscons
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
#
|
|
||||||
# @param options [Hash] Builder run options.
|
|
||||||
#
|
|
||||||
# @return [String,false]
|
|
||||||
# Name of the target file on success or false on failure.
|
|
||||||
def run(options)
|
def run(options)
|
||||||
ld = @env.expand_varref("${SHLD}", @vars)
|
if @command
|
||||||
ld = if ld != ""
|
finalize_command(sources: @objects)
|
||||||
ld
|
true
|
||||||
elsif @sources.find {|s| s.end_with?(*@env.expand_varref("${DSUFFIX}", @vars))}
|
else
|
||||||
"${SHDC}"
|
ld = @env.expand_varref("${SHLD}", @vars)
|
||||||
elsif @sources.find {|s| s.end_with?(*@env.expand_varref("${CXXSUFFIX}", @vars))}
|
ld = if ld != ""
|
||||||
"${SHCXX}"
|
ld
|
||||||
else
|
elsif @sources.find {|s| s.end_with?(*@env.expand_varref("${DSUFFIX}", @vars))}
|
||||||
"${SHCC}"
|
"${SHDC}"
|
||||||
end
|
elsif @sources.find {|s| s.end_with?(*@env.expand_varref("${CXXSUFFIX}", @vars))}
|
||||||
@vars["_TARGET"] = @target
|
"${SHCXX}"
|
||||||
@vars["_SOURCES"] = @objects
|
else
|
||||||
@vars["SHLD"] = ld
|
"${SHCC}"
|
||||||
command = @env.build_command("${SHLDCMD}", @vars)
|
end
|
||||||
standard_threaded_build("SHLD #{@target}", @target, command, @objects, @env, @cache)
|
@vars["_TARGET"] = @target
|
||||||
end
|
@vars["_SOURCES"] = @objects
|
||||||
|
@vars["SHLD"] = ld
|
||||||
# Finalize a build.
|
command = @env.build_command("${SHLDCMD}", @vars)
|
||||||
#
|
standard_command("SHLD #{@target}", command, sources: @objects)
|
||||||
# @param options [Hash]
|
|
||||||
# Finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# The target name on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
if options[:command_status]
|
|
||||||
@cache.register_build(@target, options[:tc].command, @objects, @env)
|
|
||||||
@target
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -61,40 +61,26 @@ module Rscons
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Run the builder to produce a build target.
|
# Run the builder to produce a build target.
|
||||||
#
|
|
||||||
# @param options [Hash] Builder run options.
|
|
||||||
#
|
|
||||||
# @return [String, ThreadedCommand]
|
|
||||||
# Target file name if target is up to date or a {ThreadedCommand}
|
|
||||||
# to execute to build the target.
|
|
||||||
def run(options)
|
def run(options)
|
||||||
@vars["_TARGET"] = @target
|
if @command
|
||||||
@vars["_SOURCES"] = @sources
|
|
||||||
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
|
||||||
com_prefix = KNOWN_SUFFIXES.find do |compiler, suffix_var|
|
|
||||||
@sources.first.end_with?(*@env.expand_varref("${#{suffix_var}}", @vars))
|
|
||||||
end.tap do |v|
|
|
||||||
v.nil? and raise "Error: unknown input file type: #{@sources.first.inspect}"
|
|
||||||
end.first
|
|
||||||
command = @env.build_command("${#{com_prefix}CMD}", @vars)
|
|
||||||
@env.produces(@target, @vars["_DEPFILE"])
|
|
||||||
standard_threaded_build("#{com_prefix} #{@target}", @target, command, @sources, @env, @cache)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Finalize the build operation.
|
|
||||||
#
|
|
||||||
# @param options [Hash] Builder finalize options.
|
|
||||||
#
|
|
||||||
# @return [String, nil]
|
|
||||||
# Name of the target file on success or nil on failure.
|
|
||||||
def finalize(options)
|
|
||||||
if options[:command_status]
|
|
||||||
deps = @sources
|
deps = @sources
|
||||||
if File.exists?(@vars['_DEPFILE'])
|
if File.exists?(@vars["_DEPFILE"])
|
||||||
deps += Util.parse_makefile_deps(@vars['_DEPFILE'])
|
deps += Util.parse_makefile_deps(@vars["_DEPFILE"])
|
||||||
end
|
end
|
||||||
@cache.register_build(@target, options[:tc].command, deps.uniq, @env)
|
@cache.register_build(@target, @command, deps.uniq, @env)
|
||||||
@target
|
true
|
||||||
|
else
|
||||||
|
@vars["_TARGET"] = @target
|
||||||
|
@vars["_SOURCES"] = @sources
|
||||||
|
@vars["_DEPFILE"] = Rscons.set_suffix(target, env.expand_varref("${DEPFILESUFFIX}", vars))
|
||||||
|
com_prefix = KNOWN_SUFFIXES.find do |compiler, suffix_var|
|
||||||
|
@sources.first.end_with?(*@env.expand_varref("${#{suffix_var}}", @vars))
|
||||||
|
end.tap do |v|
|
||||||
|
v.nil? and raise "Error: unknown input file type: #{@sources.first.inspect}"
|
||||||
|
end.first
|
||||||
|
command = @env.build_command("${#{com_prefix}CMD}", @vars)
|
||||||
|
@env.produces(@target, @vars["_DEPFILE"])
|
||||||
|
standard_command("#{com_prefix} #{@target}", command)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -5,8 +5,14 @@ module Rscons
|
|||||||
# @since 1.8.0
|
# @since 1.8.0
|
||||||
class SimpleBuilder < Builder
|
class SimpleBuilder < Builder
|
||||||
|
|
||||||
|
# @return [String]
|
||||||
|
# User-provided builder name.
|
||||||
|
attr_reader :name
|
||||||
|
|
||||||
# Create an instance of the Builder to build a target.
|
# Create an instance of the Builder to build a target.
|
||||||
#
|
#
|
||||||
|
# @param name [String]
|
||||||
|
# User-provided builder name.
|
||||||
# @param options [Hash]
|
# @param options [Hash]
|
||||||
# Options.
|
# Options.
|
||||||
# @option options [String] :target
|
# @option options [String] :target
|
||||||
@ -20,7 +26,8 @@ module Rscons
|
|||||||
# @param run_proc [Proc]
|
# @param run_proc [Proc]
|
||||||
# A Proc to execute when the builder runs. The provided block must
|
# A Proc to execute when the builder runs. The provided block must
|
||||||
# provide the have the same signature as {Builder#run}.
|
# provide the have the same signature as {Builder#run}.
|
||||||
def initialize(options, &run_proc)
|
def initialize(name, options, &run_proc)
|
||||||
|
@name = name
|
||||||
super(options)
|
super(options)
|
||||||
@run_proc = run_proc
|
@run_proc = run_proc
|
||||||
end
|
end
|
||||||
|
66
lib/rscons/command.rb
Normal file
66
lib/rscons/command.rb
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
module Rscons
|
||||||
|
# Class to keep track of system commands that builders need to execute.
|
||||||
|
# Rscons will manage scheduling these commands to be run in separate threads.
|
||||||
|
class Command
|
||||||
|
|
||||||
|
# @return [Builder]
|
||||||
|
# {Builder} executing this command.
|
||||||
|
attr_reader :builder
|
||||||
|
|
||||||
|
# @return [Array<String>]
|
||||||
|
# The command to execute.
|
||||||
|
attr_reader :command
|
||||||
|
|
||||||
|
# @return [nil, true, false]
|
||||||
|
# true if the command gives zero exit status.
|
||||||
|
# false if the command gives non-zero exit status.
|
||||||
|
# nil if command execution fails.
|
||||||
|
attr_accessor :status
|
||||||
|
|
||||||
|
# @return [Hash]
|
||||||
|
# Environment Hash to pass to Kernel#system.
|
||||||
|
attr_reader :system_env
|
||||||
|
|
||||||
|
# @return [Hash]
|
||||||
|
# Options Hash to pass to Kernel#system.
|
||||||
|
attr_reader :system_options
|
||||||
|
|
||||||
|
# @return [Thread]
|
||||||
|
# The thread waiting on this command to terminate.
|
||||||
|
attr_reader :thread
|
||||||
|
|
||||||
|
# Create a ThreadedCommand object.
|
||||||
|
#
|
||||||
|
# @param command [Array<String>]
|
||||||
|
# The command to execute.
|
||||||
|
# @param builder [Builder]
|
||||||
|
# The {Builder} executing this command.
|
||||||
|
# @param options [Hash]
|
||||||
|
# Optional parameters.
|
||||||
|
# @option options [Hash] :system_env
|
||||||
|
# Environment Hash to pass to Kernel#system.
|
||||||
|
# @option options [Hash] :system_options
|
||||||
|
# Options Hash to pass to Kernel#system.
|
||||||
|
def initialize(command, builder, options = {})
|
||||||
|
@command = command
|
||||||
|
@builder = builder
|
||||||
|
@system_env = options[:system_env]
|
||||||
|
@system_options = options[:system_options]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Start a thread to run the command.
|
||||||
|
#
|
||||||
|
# @return [Thread]
|
||||||
|
# The Thread created to run the command.
|
||||||
|
def run
|
||||||
|
env_args = @system_env ? [@system_env] : []
|
||||||
|
options_args = @system_options ? [@system_options] : []
|
||||||
|
system_args = [*env_args, *Rscons.command_executer, *@command, *options_args]
|
||||||
|
|
||||||
|
@thread = Thread.new do
|
||||||
|
system(*system_args)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
@ -48,10 +48,9 @@ module Rscons
|
|||||||
attr_reader :build_root
|
attr_reader :build_root
|
||||||
|
|
||||||
# @return [Integer]
|
# @return [Integer]
|
||||||
# The number of threads to use for this Environment. If nil (the
|
# The number of threads to use for this Environment. Defaults to the
|
||||||
# default), the global Rscons.application.n_threads default value will be
|
# global Rscons.application.n_threads value.
|
||||||
# used.
|
attr_accessor :n_threads
|
||||||
attr_writer :n_threads
|
|
||||||
|
|
||||||
# Create an Environment object.
|
# Create an Environment object.
|
||||||
#
|
#
|
||||||
@ -67,7 +66,8 @@ module Rscons
|
|||||||
super(options)
|
super(options)
|
||||||
@id = self.class.get_id
|
@id = self.class.get_id
|
||||||
self.class.register(self)
|
self.class.register(self)
|
||||||
@threaded_commands = Set.new
|
# Hash of Thread object => {Command} or {Builder}.
|
||||||
|
@threads = {}
|
||||||
@registered_build_dependencies = {}
|
@registered_build_dependencies = {}
|
||||||
@side_effects = {}
|
@side_effects = {}
|
||||||
@builder_set = BuilderSet.new(@registered_build_dependencies, @side_effects)
|
@builder_set = BuilderSet.new(@registered_build_dependencies, @side_effects)
|
||||||
@ -91,6 +91,7 @@ module Rscons
|
|||||||
:short
|
:short
|
||||||
end
|
end
|
||||||
@build_root = "#{Cache.instance.configuration_data["build_dir"]}/e.#{@id}"
|
@build_root = "#{Cache.instance.configuration_data["build_dir"]}/e.#{@id}"
|
||||||
|
@n_threads = Rscons.application.n_threads
|
||||||
|
|
||||||
if block_given?
|
if block_given?
|
||||||
yield self
|
yield self
|
||||||
@ -173,9 +174,12 @@ module Rscons
|
|||||||
# @return [void]
|
# @return [void]
|
||||||
def add_builder(builder_class, &action)
|
def add_builder(builder_class, &action)
|
||||||
if builder_class.is_a?(String) or builder_class.is_a?(Symbol)
|
if builder_class.is_a?(String) or builder_class.is_a?(Symbol)
|
||||||
builder_class = BuilderBuilder.new(builder_class.to_s, Rscons::Builders::SimpleBuilder, &action)
|
name = builder_class.to_s
|
||||||
|
builder_class = BuilderBuilder.new(Rscons::Builders::SimpleBuilder, name, &action)
|
||||||
|
else
|
||||||
|
name = builder_class.name
|
||||||
end
|
end
|
||||||
@builders[builder_class.name] = builder_class
|
@builders[name] = builder_class
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add a build hook to the Environment.
|
# Add a build hook to the Environment.
|
||||||
@ -254,73 +258,29 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def process
|
def process
|
||||||
cache = Cache.instance
|
unless Cache.instance.configuration_data["configured"]
|
||||||
unless cache.configuration_data["configured"]
|
|
||||||
raise "Project must be configured before processing an Environment"
|
raise "Project must be configured before processing an Environment"
|
||||||
end
|
end
|
||||||
failure = nil
|
@process_failure = nil
|
||||||
|
@process_blocking_wait = false
|
||||||
|
@process_commands_waiting_to_run = []
|
||||||
|
@process_builder_waits = {}
|
||||||
|
@process_builders_to_run = []
|
||||||
begin
|
begin
|
||||||
while @builder_set.size > 0 or @threaded_commands.size > 0
|
while @builder_set.size > 0 or @threads.size > 0 or @process_commands_waiting_to_run.size > 0
|
||||||
|
process_step
|
||||||
if failure
|
if @process_failure
|
||||||
|
# On a build failure, do not start any more builders or commands,
|
||||||
|
# but let the threads that have already been started complete.
|
||||||
@builder_set.clear
|
@builder_set.clear
|
||||||
builder = nil
|
@process_commands_waiting_to_run.clear
|
||||||
else
|
|
||||||
targets_still_building = @threaded_commands.map do |tc|
|
|
||||||
tc.builder.target
|
|
||||||
end
|
|
||||||
builder = @builder_set.get_next_builder_to_run(targets_still_building)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: have Cache determine when checksums may be invalid based on
|
|
||||||
# file size and/or timestamp.
|
|
||||||
cache.clear_checksum_cache!
|
|
||||||
|
|
||||||
if builder
|
|
||||||
result = run_builder(builder, cache)
|
|
||||||
unless result
|
|
||||||
failure = "Failed to build #{builder.target}"
|
|
||||||
Ansi.write($stderr, :red, failure, :reset, "\n")
|
|
||||||
next
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
completed_tcs = Set.new
|
|
||||||
# First do a non-blocking wait to pick up any threads that have
|
|
||||||
# completed since last time.
|
|
||||||
while tc = wait_for_threaded_commands(nonblock: true)
|
|
||||||
completed_tcs << tc
|
|
||||||
end
|
|
||||||
|
|
||||||
# If needed, do a blocking wait.
|
|
||||||
if (@threaded_commands.size > 0) and
|
|
||||||
((completed_tcs.empty? and builder.nil?) or (@threaded_commands.size >= n_threads))
|
|
||||||
completed_tcs << wait_for_threaded_commands
|
|
||||||
end
|
|
||||||
|
|
||||||
# Process all completed {ThreadedCommand} objects.
|
|
||||||
completed_tcs.each do |tc|
|
|
||||||
result = finalize_builder(tc)
|
|
||||||
if result
|
|
||||||
@build_hooks[:post].each do |build_hook_block|
|
|
||||||
build_hook_block.call(tc.builder)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
unless @echo == :command
|
|
||||||
print_failed_command(tc.command)
|
|
||||||
end
|
|
||||||
failure = "Failed to build #{tc.builder.target}"
|
|
||||||
Ansi.write($stderr, :red, failure, :reset, "\n")
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
cache.write
|
Cache.instance.write
|
||||||
end
|
end
|
||||||
if failure
|
if @process_failure
|
||||||
raise BuildError.new(failure)
|
raise BuildError.new(@process_failure)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -505,47 +465,6 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Invoke a builder to build the given target based on the given sources.
|
|
||||||
#
|
|
||||||
# @param builder [Builder] The Builder to use.
|
|
||||||
# @param cache [Cache] The Cache.
|
|
||||||
#
|
|
||||||
# @return [String,false] Return value from the {Builder}'s +run+ method.
|
|
||||||
def run_builder(builder, cache)
|
|
||||||
builder.vars = @varset.merge(builder.vars)
|
|
||||||
build_operation = {}
|
|
||||||
call_build_hooks = lambda do |sec|
|
|
||||||
@build_hooks[sec].each do |build_hook_block|
|
|
||||||
build_hook_block.call(builder)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Invoke pre-build hooks.
|
|
||||||
call_build_hooks[:pre]
|
|
||||||
|
|
||||||
# Call the builder's #run method.
|
|
||||||
rv = builder.run(build_operation)
|
|
||||||
|
|
||||||
(@side_effects[builder.target] || []).each do |side_effect_file|
|
|
||||||
# Register side-effect files as build targets so that a Cache clean
|
|
||||||
# operation will remove them.
|
|
||||||
cache.register_build(side_effect_file, nil, [], self)
|
|
||||||
end
|
|
||||||
|
|
||||||
if rv.is_a?(ThreadedCommand)
|
|
||||||
# Store the build operation so the post-build hooks can be called
|
|
||||||
# with it when the threaded command completes.
|
|
||||||
rv.builder = builder
|
|
||||||
# TODO: remove
|
|
||||||
rv.build_operation = build_operation
|
|
||||||
start_threaded_command(rv)
|
|
||||||
else
|
|
||||||
call_build_hooks[:post] if rv
|
|
||||||
end
|
|
||||||
|
|
||||||
rv
|
|
||||||
end
|
|
||||||
|
|
||||||
# Expand a path to be relative to the Environment's build root.
|
# Expand a path to be relative to the Environment's build root.
|
||||||
#
|
#
|
||||||
# Paths beginning with "^/" are expanded by replacing "^" with the
|
# Paths beginning with "^/" are expanded by replacing "^" with the
|
||||||
@ -591,15 +510,6 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the number of threads to use for parallelized builds in this
|
|
||||||
# Environment.
|
|
||||||
#
|
|
||||||
# @return [Integer]
|
|
||||||
# Number of threads to use for parallelized builds in this Environment.
|
|
||||||
def n_threads
|
|
||||||
@n_threads || Rscons.application.n_threads
|
|
||||||
end
|
|
||||||
|
|
||||||
# Print the builder run message, depending on the Environment's echo mode.
|
# Print the builder run message, depending on the Environment's echo mode.
|
||||||
#
|
#
|
||||||
# @param short_description [String]
|
# @param short_description [String]
|
||||||
@ -636,49 +546,146 @@ module Rscons
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Start a threaded command in a new thread.
|
# Signal a build failure to the {#process} method.
|
||||||
#
|
#
|
||||||
# @param tc [ThreadedCommand]
|
# @param target [String]
|
||||||
# The ThreadedCommand to start.
|
# Build target name.
|
||||||
#
|
#
|
||||||
# @return [void]
|
# @return [void]
|
||||||
def start_threaded_command(tc)
|
def process_failure(target)
|
||||||
print_builder_run_message(tc.short_description, tc.command)
|
@process_failure = "Failed to build #{target}"
|
||||||
|
Ansi.write($stderr, :red, @process_failure, :reset, "\n")
|
||||||
env_args = tc.system_env ? [tc.system_env] : []
|
|
||||||
options_args = tc.system_options ? [tc.system_options] : []
|
|
||||||
system_args = [*env_args, *Rscons.command_executer, *tc.command, *options_args]
|
|
||||||
|
|
||||||
tc.thread = Thread.new do
|
|
||||||
system(*system_args)
|
|
||||||
end
|
|
||||||
@threaded_commands << tc
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Wait for threaded commands to complete.
|
# Run a builder and process its return value.
|
||||||
#
|
#
|
||||||
# @param options [Hash]
|
# @param builder [Builder]
|
||||||
# Options.
|
# The builder.
|
||||||
# @option options [Boolean] :nonblock
|
|
||||||
# Set to true to not block.
|
|
||||||
#
|
#
|
||||||
# @return [ThreadedCommand, nil]
|
# @return [void]
|
||||||
# The {ThreadedCommand} object that is finished.
|
def run_builder(builder)
|
||||||
def wait_for_threaded_commands(options = {})
|
# TODO: have Cache determine when checksums may be invalid based on
|
||||||
threads = @threaded_commands.map(&:thread)
|
# file size and/or timestamp.
|
||||||
if finished_thread = find_finished_thread(threads, options[:nonblock])
|
Cache.instance.clear_checksum_cache!
|
||||||
threaded_command = @threaded_commands.find do |tc|
|
case result = builder.run({})
|
||||||
tc.thread == finished_thread
|
when Array
|
||||||
|
result.each do |waititem|
|
||||||
|
@process_builder_waits[builder] ||= Set.new
|
||||||
|
@process_builder_waits[builder] << waititem
|
||||||
|
case waititem
|
||||||
|
when Thread
|
||||||
|
@threads[waititem] = builder
|
||||||
|
when Command
|
||||||
|
@process_commands_waiting_to_run << waititem
|
||||||
|
when Builder
|
||||||
|
# No action needed.
|
||||||
|
else
|
||||||
|
raise "Unrecognized #{builder.name} builder return item: #{waititem.inspect}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
@threaded_commands.delete(threaded_command)
|
when false
|
||||||
threaded_command
|
process_failure(builder.target)
|
||||||
|
when true
|
||||||
|
# Register side-effect files as build targets so that a Cache
|
||||||
|
# clean operation will remove them.
|
||||||
|
(@side_effects[builder.target] || []).each do |side_effect_file|
|
||||||
|
Cache.instance.register_build(side_effect_file, nil, [], self)
|
||||||
|
end
|
||||||
|
@build_hooks[:post].each do |build_hook_block|
|
||||||
|
build_hook_block.call(builder)
|
||||||
|
end
|
||||||
|
process_remove_wait(builder)
|
||||||
|
else
|
||||||
|
raise "Unrecognized #{builder.name} builder return value: #{result.inspect}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Check if any of the requested threads are finished.
|
# Remove an item that a builder may have been waiting on.
|
||||||
|
#
|
||||||
|
# @param waititem [Object]
|
||||||
|
# Item that a builder may be waiting on.
|
||||||
|
#
|
||||||
|
# @return [void]
|
||||||
|
def process_remove_wait(waititem)
|
||||||
|
@process_builder_waits.to_a.each do |builder, waits|
|
||||||
|
if waits.include?(waititem)
|
||||||
|
waits.delete(waititem)
|
||||||
|
end
|
||||||
|
if waits.empty?
|
||||||
|
@process_builder_waits.delete(builder)
|
||||||
|
@process_builders_to_run << builder
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Broken out from {#process} to perform a single operation.
|
||||||
|
#
|
||||||
|
# @return [void]
|
||||||
|
def process_step
|
||||||
|
# Check if a thread has completed since last time.
|
||||||
|
thread = find_finished_thread(true)
|
||||||
|
|
||||||
|
# Check if we need to do a blocking wait for a thread to complete.
|
||||||
|
if thread.nil? and (@threads.size >= n_threads or @process_blocking_wait)
|
||||||
|
thread = find_finished_thread(false)
|
||||||
|
@process_blocking_wait = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if thread
|
||||||
|
# We found a completed thread.
|
||||||
|
process_remove_wait(thread)
|
||||||
|
builder = builder_for_thread(thread)
|
||||||
|
completed_command = @threads[thread]
|
||||||
|
@threads.delete(thread)
|
||||||
|
if completed_command.is_a?(Command)
|
||||||
|
process_remove_wait(completed_command)
|
||||||
|
completed_command.status = thread.value
|
||||||
|
unless completed_command.status
|
||||||
|
unless @echo == :command
|
||||||
|
print_failed_command(completed_command.command)
|
||||||
|
end
|
||||||
|
return process_failure(builder.target)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @threads.size < n_threads and @process_commands_waiting_to_run.size > 0
|
||||||
|
# There is a command waiting to run and a thread free to run it.
|
||||||
|
command = @process_commands_waiting_to_run.slice!(0)
|
||||||
|
@threads[command.run] = command
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
unless @process_builders_to_run.empty?
|
||||||
|
# There is a builder waiting to run that was unblocked by its wait
|
||||||
|
# items completing.
|
||||||
|
return run_builder(@process_builders_to_run.slice!(0))
|
||||||
|
end
|
||||||
|
|
||||||
|
# If no builder was found to run yet and there are threads available, try
|
||||||
|
# to get a runnable builder from the builder set.
|
||||||
|
targets_still_building = @threads.reduce([]) do |result, (thread, obj)|
|
||||||
|
result << builder_for_thread(thread).target
|
||||||
|
end
|
||||||
|
builder = @builder_set.get_next_builder_to_run(targets_still_building)
|
||||||
|
|
||||||
|
if builder
|
||||||
|
builder.vars = @varset.merge(builder.vars)
|
||||||
|
@build_hooks[:pre].each do |build_hook_block|
|
||||||
|
build_hook_block.call(builder)
|
||||||
|
end
|
||||||
|
return run_builder(builder)
|
||||||
|
end
|
||||||
|
|
||||||
|
if @threads.size > 0
|
||||||
|
# A runnable builder was not found but there is a thread running,
|
||||||
|
# so next time do a blocking wait for a thread to complete.
|
||||||
|
@process_blocking_wait = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Find a finished thread.
|
||||||
#
|
#
|
||||||
# @param threads [Array<Thread>]
|
|
||||||
# The threads to check.
|
|
||||||
# @param nonblock [Boolean]
|
# @param nonblock [Boolean]
|
||||||
# Whether to be non-blocking. If true, nil will be returned if no thread
|
# Whether to be non-blocking. If true, nil will be returned if no thread
|
||||||
# is finished. If false, the method will wait until one of the threads
|
# is finished. If false, the method will wait until one of the threads
|
||||||
@ -686,31 +693,32 @@ module Rscons
|
|||||||
#
|
#
|
||||||
# @return [Thread, nil]
|
# @return [Thread, nil]
|
||||||
# The finished thread, if any.
|
# The finished thread, if any.
|
||||||
def find_finished_thread(threads, nonblock)
|
def find_finished_thread(nonblock)
|
||||||
if nonblock
|
if nonblock
|
||||||
threads.find do |thread|
|
@threads.keys.find do |thread|
|
||||||
!thread.alive?
|
!thread.alive?
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if threads.empty?
|
if @threads.empty?
|
||||||
raise "No threads to wait for"
|
raise "No threads to wait for"
|
||||||
end
|
end
|
||||||
ThreadsWait.new(*threads).next_wait
|
ThreadsWait.new(*@threads.keys).next_wait
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Call a builder's #finalize method after a ThreadedCommand terminates.
|
# Get the {Builder} waiting on the given Thread.
|
||||||
#
|
#
|
||||||
# @param tc [ThreadedCommand]
|
# @param thread [Thread]
|
||||||
# The ThreadedCommand returned from the builder's #run method.
|
# The thread.
|
||||||
#
|
#
|
||||||
# @return [String, false]
|
# @return [Builder]
|
||||||
# Result of Builder#finalize.
|
# The {Builder} waiting on the given thread.
|
||||||
def finalize_builder(tc)
|
def builder_for_thread(thread)
|
||||||
tc.builder.finalize(
|
if @threads[thread].is_a?(Command)
|
||||||
tc.build_operation.merge(
|
@threads[thread].builder
|
||||||
command_status: tc.thread.value,
|
else
|
||||||
tc: tc))
|
@threads[thread]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Find a builder that meets the requested features and produces a target
|
# Find a builder that meets the requested features and produces a target
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
module Rscons
|
|
||||||
# If a builder returns an instance of this class from its #run method, then
|
|
||||||
# Rscons will execute the command specified in a thread and allow other
|
|
||||||
# builders to continue executing in parallel.
|
|
||||||
class ThreadedCommand
|
|
||||||
|
|
||||||
# @return [Array<String>]
|
|
||||||
# The command to execute.
|
|
||||||
attr_reader :command
|
|
||||||
|
|
||||||
# @return [String]
|
|
||||||
# Short description of the command. This will be printed to standard
|
|
||||||
# output if the Environment's echo mode is :short.
|
|
||||||
attr_reader :short_description
|
|
||||||
|
|
||||||
# @return [Hash]
|
|
||||||
# Environment Hash to pass to Kernel#system.
|
|
||||||
attr_reader :system_env
|
|
||||||
|
|
||||||
# @return [Hash]
|
|
||||||
# Options Hash to pass to Kernel#system.
|
|
||||||
attr_reader :system_options
|
|
||||||
|
|
||||||
# @return [Hash]
|
|
||||||
# Field for Rscons to store the build operation while this threaded
|
|
||||||
# command is executing.
|
|
||||||
attr_accessor :build_operation
|
|
||||||
|
|
||||||
# @return [Builder]
|
|
||||||
# {Builder} executing this command.
|
|
||||||
attr_accessor :builder
|
|
||||||
|
|
||||||
# @return [Thread]
|
|
||||||
# The thread waiting on this command to terminate.
|
|
||||||
attr_accessor :thread
|
|
||||||
|
|
||||||
# Create a ThreadedCommand object.
|
|
||||||
#
|
|
||||||
# @param command [Array<String>]
|
|
||||||
# The command to execute.
|
|
||||||
# @param options [Hash]
|
|
||||||
# Optional parameters.
|
|
||||||
# @option options [Object] :builder_info
|
|
||||||
# Arbitrary object to store builder-specific info. This object value will
|
|
||||||
# be passed back into the builder's #finalize method.
|
|
||||||
# @option options [String] :short_description
|
|
||||||
# Short description of the command. This will be printed to standard
|
|
||||||
# output if the Environment's echo mode is :short.
|
|
||||||
# @option options [Hash] :system_env
|
|
||||||
# Environment Hash to pass to Kernel#system.
|
|
||||||
# @option options [Hash] :system_options
|
|
||||||
# Options Hash to pass to Kernel#system.
|
|
||||||
def initialize(command, options = {})
|
|
||||||
@command = command
|
|
||||||
@short_description = options[:short_description]
|
|
||||||
@system_env = options[:system_env]
|
|
||||||
@system_options = options[:system_options]
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
@ -327,6 +327,29 @@ EOF
|
|||||||
expect(`./program.exe`).to eq "The value is 42\n"
|
expect(`./program.exe`).to eq "The value is 42\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'raises an error when a custom builder returns an invalid value from #run' do
|
||||||
|
test_dir("custom_builder")
|
||||||
|
result = run_rscons(rsconscript: "error_run_return_value.rb")
|
||||||
|
expect(result.stderr).to match /Unrecognized MyBuilder builder return value: "hi"/
|
||||||
|
expect(result.status).to_not eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises an error when a custom builder returns an invalid value using Builder#wait_for' do
|
||||||
|
test_dir("custom_builder")
|
||||||
|
result = run_rscons(rsconscript: "error_wait_for.rb")
|
||||||
|
expect(result.stderr).to match /Unrecognized MyBuilder builder return item: 1/
|
||||||
|
expect(result.status).to_not eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'supports a Builder waiting for a custom Thread object' do
|
||||||
|
test_dir "custom_builder"
|
||||||
|
result = run_rscons(rsconscript: "wait_for_thread.rb")
|
||||||
|
expect(result.stderr).to eq ""
|
||||||
|
expect(result.status).to eq 0
|
||||||
|
expect(lines(result.stdout)).to include "MyBuilder foo"
|
||||||
|
expect(File.exists?("foo")).to be_truthy
|
||||||
|
end
|
||||||
|
|
||||||
it 'allows cloning Environment objects' do
|
it 'allows cloning Environment objects' do
|
||||||
test_dir('clone_env')
|
test_dir('clone_env')
|
||||||
result = run_rscons
|
result = run_rscons
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
module Rscons
|
|
||||||
module Builders
|
|
||||||
describe SimpleBuilder do
|
|
||||||
let(:env) {Environment.new}
|
|
||||||
|
|
||||||
it "should create a new builder with the given action" do
|
|
||||||
builder = Rscons::Builders::SimpleBuilder.new({}) { 0x1234 }
|
|
||||||
expect(builder.run(1,2,3,4,5)).to eq(0x1234)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -230,7 +230,7 @@ module Rscons
|
|||||||
describe "#find_finished_thread" do
|
describe "#find_finished_thread" do
|
||||||
it "raises an error if called with nonblock=false and no threads to wait for" do
|
it "raises an error if called with nonblock=false and no threads to wait for" do
|
||||||
env = Environment.new
|
env = Environment.new
|
||||||
expect {env.__send__(:find_finished_thread, [], false)}.to raise_error /No threads to wait for/
|
expect {env.__send__(:find_finished_thread, false)}.to raise_error /No threads to wait for/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user