222 lines
6.7 KiB
Ruby
222 lines
6.7 KiB
Ruby
require "fileutils"
|
|
|
|
module Rscons
|
|
# Namespace module in which to store builders for convenient grouping
|
|
module Builders; end
|
|
|
|
# Class to hold an object that knows how to build a certain type of file.
|
|
class Builder
|
|
|
|
class << self
|
|
# Return a String specifying an extra path component used to
|
|
# differentiate build targets built by this builder from others.
|
|
#
|
|
# @return [String, nil]
|
|
# Extra path component used to differentiate build targets built by
|
|
# this builder from others.
|
|
def extra_path
|
|
end
|
|
|
|
# Return the name of the builder.
|
|
#
|
|
# If not overridden this defaults to the last component of the class name.
|
|
#
|
|
# @return [String] The name of the builder.
|
|
def name
|
|
super.split(":").last
|
|
end
|
|
end
|
|
|
|
# @return [String, Symbol]
|
|
# Target file name.
|
|
attr_accessor :target
|
|
|
|
# @return [Array<String>]
|
|
# Source file name(s).
|
|
attr_accessor :sources
|
|
|
|
# @return [Cache]
|
|
# Cache instance.
|
|
attr_accessor :cache
|
|
|
|
# @return [Environment]
|
|
# The {Environment} performing the build operation.
|
|
attr_accessor :env
|
|
|
|
# @return [Hash, VarSet]
|
|
# Construction variables used to perform the build operation.
|
|
attr_accessor :vars
|
|
|
|
# @return [Set<String>]
|
|
# Side effect file(s) produced when this builder runs.
|
|
attr_accessor :side_effects
|
|
|
|
# @return [Integer]
|
|
# Build step.
|
|
attr_accessor :build_step
|
|
|
|
# Create an instance of the Builder to build a target.
|
|
#
|
|
# @param options [Hash]
|
|
# Options.
|
|
# @option options [String, Symbol] :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.
|
|
def initialize(options)
|
|
@target = options[:target]
|
|
@sources = options[:sources]
|
|
@cache = options[:cache]
|
|
@env = options[:env]
|
|
@vars = options[:vars]
|
|
@side_effects = Set.new
|
|
end
|
|
|
|
# Return the name of the builder.
|
|
#
|
|
# If not overridden this defaults to the last component of the class name.
|
|
#
|
|
# @return [String] The name of the builder.
|
|
def name
|
|
self.class.name
|
|
end
|
|
|
|
# Manually record a given build target as depending on the specified files.
|
|
#
|
|
# @param user_deps [Array<String>]
|
|
# Dependency files.
|
|
#
|
|
# @return [void]
|
|
def depends(*user_deps)
|
|
@env.depends(@target, *user_deps)
|
|
end
|
|
|
|
# Manually record the given side effect file(s) as being produced when the
|
|
# named target is produced.
|
|
#
|
|
# @return [void]
|
|
def produces(*side_effects)
|
|
side_effects.each do |side_effect|
|
|
side_effect_expanded = @env.expand_path(@env.expand_varref(side_effect))
|
|
@env.register_side_effect(side_effect_expanded)
|
|
@side_effects << side_effect_expanded
|
|
end
|
|
end
|
|
|
|
# Run the builder to produce a build target.
|
|
#
|
|
# @param options [Hash]
|
|
# Run options.
|
|
#
|
|
# @return [Object]
|
|
# If the build operation fails, this method should return +false+.
|
|
# If the build operation succeeds, this method should return +true+.
|
|
# If the build operation is not yet complete and is waiting on other
|
|
# operations, this method should return the return value from the
|
|
# {#wait_for} method.
|
|
def run(options)
|
|
raise "This method must be overridden in a subclass"
|
|
end
|
|
|
|
# Print the builder run message, depending on the Environment's echo mode.
|
|
#
|
|
# @param short_description [String]
|
|
# Builder short description, printed if the echo mode is :short, or if
|
|
# there is no command.
|
|
# @param command [Array<String>]
|
|
# Builder command, printed if the echo mode is :command.
|
|
#
|
|
# @return [void]
|
|
def print_run_message(short_description, command)
|
|
@env.print_builder_run_message(self, short_description, command)
|
|
end
|
|
|
|
# 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 [String] :stdout
|
|
# File name to redirect standard output to.
|
|
#
|
|
# @return [Object]
|
|
# Return value for {#run} method.
|
|
def register_command(short_description, command, options = {})
|
|
command_options = {}
|
|
if options[:stdout]
|
|
command_options[:system_options] = {out: options[:stdout]}
|
|
end
|
|
print_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
|
|
unless Rscons.phony_target?(@target)
|
|
@cache.mkdir_p(File.dirname(@target))
|
|
FileUtils.rm_f(@target)
|
|
end
|
|
register_command(short_description, @command, options)
|
|
end
|
|
end
|
|
|
|
# Register build results from a {Command} with the cache.
|
|
#
|
|
# @param options [Hash]
|
|
# Builder finalize options.
|
|
# @option options [String] :stdout
|
|
# File name to redirect standard output to.
|
|
#
|
|
# @return [true]
|
|
# Return value for {#run} method.
|
|
def finalize_command(options = {})
|
|
sources = options[:sources] || @sources
|
|
@cache.register_build(@target, @command, sources, @env)
|
|
true
|
|
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
|