added more documentation to get to 100% YARD coverage; fix YARD warnings

This commit is contained in:
Josh Holtrop 2014-06-16 15:33:22 -04:00
parent d87c4990b1
commit 912615535a
13 changed files with 309 additions and 39 deletions

View File

@ -268,8 +268,8 @@ env.Preprocess(target, source)
env.Preprocess("module-preprocessed.cc", "module.cc")
```
The Preprocess builder invokes either ${CC} or ${CXX} (depending on if the
source contains an extension in ${CXXSUFFIX} or not) and writes the
The Preprocess builder invokes either `${CC}` or `${CXX}` (depending on if the
source contains an extension in `${CXXSUFFIX}` or not) and writes the
preprocessed output to the target file.
#### Program

View File

@ -15,6 +15,8 @@ require_relative "rscons/builders/program"
# Namespace module for rscons classes
module Rscons
# Names of the default builders which will be added to all newly created
# {Environment} objects.
DEFAULT_BUILDERS = [
:CFile,
:Disassemble,
@ -24,9 +26,10 @@ module Rscons
:Program,
]
# Class to represent a fatal error while building a target.
class BuildError < RuntimeError; end
# Remove all generated files
# Remove all generated files.
def self.clean
cache = Cache.instance
# remove all built files
@ -43,20 +46,27 @@ module Rscons
cache.clear
end
# Return whether the given path is an absolute filesystem path or not
# @param path [String] the path to examine
# Return whether the given path is an absolute filesystem path.
#
# @param path [String] the path to examine.
#
# @return [Boolean] Whether the given path is an absolute filesystem path.
def self.absolute_path?(path)
path =~ %r{^(/|\w:[\\/])}
end
# Return a new path by changing the suffix in path to suffix.
# @param path [String] the path to alter
# @param suffix [String] the new filename suffix
#
# @param path [String] The path to alter.
# @param suffix [String] The new filename suffix, e.g. ".exe".
#
# @return [String] New path.
def self.set_suffix(path, suffix)
path.sub(/\.[^.]*$/, suffix)
end
# Return the system shell and arguments for executing a shell command.
#
# @return [Array<String>] The shell and flag.
def self.get_system_shell
@@shell ||=

View File

@ -18,6 +18,8 @@ module Rscons
# Manually record a given 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

View File

@ -7,14 +7,17 @@ module Rscons
# Class to hold an object that knows how to build a certain type of file.
class Builder
# Return the name of the builder.
#
# If not overridden this defaults to the last component of the class name.
def name
self.class.name.split(":").last
end
# Return a set of default variable values for the Environment to use
# unless the user overrides any.
# Return a set of default construction variables for the builder.
#
# @param env [Environment] The Environment.
#
# @return [Hash] Default construction variables.
def default_variables(env)
{}
end
@ -39,16 +42,33 @@ module Rscons
# Return whether this builder object is capable of producing a given target
# file name from a given source file name.
#
# @param target [String] The target file name.
# @param source [String, Array] The source file name(s).
# @param env [Environment] The Environment.
#
# @return [Boolean]
# Whether this builder object is capable of producing a given target
# file name from a given source file name.
def produces?(target, source, env)
false
end
# Check if the cache is up to date for the target and if not execute the
# build command.
# Return the name of the target or false on failure.
#
# @param short_cmd_string [String]
# Short description of build action to be printed when env.echo ==
# :short.
# @param target [String] Name of the target file.
# @param command [Array<String>]
# The command to execute to build the target.
# @param sources [Array<String>] Source file name(s).
# @param env [Environment] The Environment executing the builder.
# @param cache [Cache] The Cache object.
#
# @return [String,false]
# The name of the target on success or false on failure.
def standard_build(short_cmd_string, target, command, sources, env, cache)
unless cache.up_to_date?(target, command, sources, env)
cache.mkdir_p(File.dirname(target))

View File

@ -7,6 +7,11 @@ module Rscons
# env.CFile("parser.tab.cc", "parser.yy")
# env.CFile("lex.yy.cc", "parser.ll")
class CFile < Builder
# Return default construction variables for the builder.
#
# @param env [Environment] The Environment using the builder.
#
# @return [Hash] Default construction variables for the builder.
def default_variables(env)
{
"YACC" => "bison",
@ -18,6 +23,16 @@ module Rscons
}
end
# Run the builder to produce a build target.
#
# @param target [String] Target file name.
# @param sources [Array<String>] Source file name(s).
# @param cache [Cache] The Cache object.
# @param env [Environment] The Environment executing the builder.
# @param vars [Hash,VarSet] Extra construction variables.
#
# @return [String,false]
# Name of the target file on success or false on failure.
def run(target, sources, cache, env, vars)
vars = vars.merge({
"_TARGET" => target,

View File

@ -2,6 +2,11 @@ module Rscons
module Builders
# The Disassemble builder produces a disassembly listing of a source file.
class Disassemble < Builder
# Return default construction variables for the builder.
#
# @param env [Environment] The Environment using the builder.
#
# @return [Hash] Default construction variables for the builder.
def default_variables(env)
{
"OBJDUMP" => "objdump",
@ -10,6 +15,16 @@ module Rscons
}
end
# Run the builder to produce a build target.
#
# @param target [String] Target file name.
# @param sources [Array<String>] Source file name(s).
# @param cache [Cache] The Cache object.
# @param env [Environment] The Environment executing the builder.
# @param vars [Hash,VarSet] Extra construction variables.
#
# @return [String,false]
# Name of the target file on success or false on failure.
def run(target, sources, cache, env, vars)
vars = vars.merge("_SOURCES" => sources)
command = env.build_command("${DISASM_CMD}", vars)

View File

@ -2,6 +2,11 @@ module Rscons
module Builders
# A default Rscons builder that produces a static library archive.
class Library < Builder
# Return default construction variables for the builder.
#
# @param env [Environment] The Environment using the builder.
#
# @return [Hash] Default construction variables for the builder.
def default_variables(env)
{
'AR' => 'ar',
@ -11,6 +16,16 @@ module Rscons
}
end
# Run the builder to produce a build target.
#
# @param target [String] Target file name.
# @param sources [Array<String>] Source file name(s).
# @param cache [Cache] The Cache object.
# @param env [Environment] The Environment executing the builder.
# @param vars [Hash,VarSet] Extra construction variables.
#
# @return [String,false]
# Name of the target file on success or false on failure.
def run(target, sources, cache, env, vars)
# build sources to linkable objects
objects = env.build_sources(sources, env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], vars).flatten, cache, vars)

View File

@ -3,6 +3,7 @@ module Rscons
# A default Rscons builder which knows how to produce an object file from
# various types of source files.
class Object < Builder
# Mapping of known sources from which to build object files.
KNOWN_SUFFIXES = {
"AS" => "ASSUFFIX",
"CC" => "CSUFFIX",
@ -10,6 +11,11 @@ module Rscons
"DC" => "DSUFFIX",
}
# Return default construction variables for the builder.
#
# @param env [Environment] The Environment using the builder.
#
# @return [Hash] Default construction variables for the builder.
def default_variables(env)
{
'OBJSUFFIX' => '.o',
@ -51,12 +57,32 @@ module Rscons
}
end
# Return whether this builder object is capable of producing a given target
# file name from a given source file name.
#
# @param target [String] The target file name.
# @param source [String, Array] The source file name(s).
# @param env [Environment] The Environment.
#
# @return [Boolean]
# Whether this builder object is capable of producing a given target
# file name from a given source file name.
def produces?(target, source, env)
target.end_with?(*env['OBJSUFFIX']) and KNOWN_SUFFIXES.find do |compiler, suffix_var|
source.end_with?(*env[suffix_var])
end
end
# Run the builder to produce a build target.
#
# @param target [String] Target file name.
# @param sources [Array<String>] Source file name(s).
# @param cache [Cache] The Cache object.
# @param env [Environment] The Environment executing the builder.
# @param vars [Hash,VarSet] Extra construction variables.
#
# @return [String,false]
# Name of the target file on success or false on failure.
def run(target, sources, cache, env, vars)
vars = vars.merge({
'_TARGET' => target,

View File

@ -2,12 +2,27 @@ module Rscons
module Builders
# The Preprocess builder invokes the C preprocessor
class Preprocess < Builder
# Return default construction variables for the builder.
#
# @param env [Environment] The Environment using the builder.
#
# @return [Hash] Default construction variables for the builder.
def default_variables(env)
{
"CPP_CMD" => ["${_PREPROCESS_CC}", "-E", "-o", "${_TARGET}", "-I${CPPPATH}", "${CPPFLAGS}", "${CFLAGS}", "${_SOURCES}"],
}
end
# Run the builder to produce a build target.
#
# @param target [String] Target file name.
# @param sources [Array<String>] Source file name(s).
# @param cache [Cache] The Cache object.
# @param env [Environment] The Environment executing the builder.
# @param vars [Hash,VarSet] Extra construction variables.
#
# @return [String,false]
# Name of the target file on success or false on failure.
def run(target, sources, cache, env, vars)
pp_cc = if sources.find {|s| s.end_with?(*env.expand_varref("${CXXSUFFIX}", vars))}
"${CXX}"

View File

@ -3,6 +3,11 @@ module Rscons
# A default Rscons builder that knows how to link object files into an
# executable program.
class Program < Builder
# Return default construction variables for the builder.
#
# @param env [Environment] The Environment using the builder.
#
# @return [Hash] Default construction variables for the builder.
def default_variables(env)
{
'OBJSUFFIX' => '.o',
@ -18,6 +23,20 @@ module Rscons
}
end
# Create a BuildTarget object for this build target.
#
# The build target filename is given a ".exe" suffix if Rscons is
# executing on a Windows platform and no other suffix is given.
#
# @param options [Hash] Options to create the BuildTarget with.
# @option options [Environment] :env
# The Environment.
# @option options [String] :target
# The user-supplied target name.
# @option options [Array<String>] :sources
# The user-supplied source file name(s).
#
# @return [BuildTarget]
def create_build_target(options)
my_options = options.dup
unless my_options[:target] =~ /\./
@ -26,6 +45,16 @@ module Rscons
super(my_options)
end
# Run the builder to produce a build target.
#
# @param target [String] Target file name.
# @param sources [Array<String>] Source file name(s).
# @param cache [Cache] The Cache object.
# @param env [Environment] The Environment executing the builder.
# @param vars [Hash,VarSet] Extra construction variables.
#
# @return [String,false]
# Name of the target file on success or false on failure.
def run(target, sources, cache, env, vars)
# build sources to linkable objects
objects = env.build_sources(sources, env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], vars).flatten, cache, vars)

View File

@ -84,7 +84,8 @@ module Rscons
@dirty = false
end
# Check if target(s) are up to date
# Check if target(s) are up to date.
#
# @param targets [String, Array] The name(s) of the target file(s).
# @param command [String, Array] The command used to build the target.
# @param deps [Array] List of the target's dependency files.
@ -93,6 +94,7 @@ module Rscons
# @option options [Boolean] :strict_deps
# Only consider a target up to date if its list of dependencies is
# exactly equal (including order) to the cached list of dependencies
#
# @return [Boolean]
# True value if the targets are all up to date, meaning that,
# for each target:
@ -144,11 +146,14 @@ module Rscons
true
end
# Store cache information about target(s) built by a builder
# Store cache information about target(s) built by a builder.
#
# @param targets [String, Array] The name of the target(s) built.
# @param command [String, Array] The command used to build the target.
# @param deps [Array] List of dependencies for the target.
# @param env [Environment] The {Rscons::Environment}.
#
# @return [void]
def register_build(targets, command, deps, env)
Array(targets).each do |target|
@cache["targets"][target] = {
@ -171,13 +176,19 @@ module Rscons
end
end
# Return a list of targets that have been built
# Return a list of targets that have been built.
#
# @return [Array<String>] List of targets that have been built.
def targets
@cache["targets"].keys
end
# Make any needed directories and record the ones that are created for
# removal upon a "clean" operation.
#
# @param path [String] Directory to create.
#
# @return [void]
def mkdir_p(path)
parts = path.split(/[\\\/]/)
parts.each_index do |i|
@ -191,7 +202,10 @@ module Rscons
end
end
# Return a list of directories which were created as a part of the build
# Return a list of directories which were created as a part of the build.
#
# @return [Array<String>]
# List of directories which were created as a part of the build.
def directories
@cache["directories"].keys
end
@ -213,14 +227,20 @@ module Rscons
end
# Return a file's checksum, or the previously calculated checksum for
# the same file
# the same file.
#
# @param file [String] The file name.
#
# @return [String] The file's checksum.
def lookup_checksum(file)
@lookup_checksums[file] || calculate_checksum(file)
end
# Calculate and return a file's checksum
# Calculate and return a file's checksum.
#
# @param file [String] The file name.
#
# @return [String] The file's checksum.
def calculate_checksum(file)
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode: "rb")) rescue ""
end

View File

@ -7,25 +7,33 @@ module Rscons
# contains a collection of construction variables, options, builders, and
# rules for building targets.
class Environment
# Hash of +{"builder_name" => builder_object}+ pairs.
# @return [Hash] Set of \{"builder_name" => builder_object} pairs.
attr_reader :builders
# :command, :short, or :off
attr_accessor :echo
# String or +nil+
# @return [String, nil] The build root.
attr_reader :build_root
# Set the build root.
#
# @param build_root [String] The build root.
def build_root=(build_root)
@build_root = build_root
@build_root.gsub!('\\', '/') if @build_root
end
# Create an Environment object.
#
# @param options [Hash]
# Possible options keys:
# :echo => :command, :short, or :off (default :short)
# :build_root => String specifying build root directory (default nil)
# :exclude_builders => true to omit adding default builders (default false)
# @option options [Symbol] :echo
# :command, :short, or :off (default :short)
# @option options [String] :build_root
# Build root directory (default nil)
# @option options [Boolean] :exclude_builders
# Whether to omit adding default builders (default false)
#
# If a block is given, the Environment object is yielded to the block and
# when the block returns, the {#process} method is automatically called.
def initialize(options = {})
@ -108,6 +116,10 @@ module Rscons
end
# Add a {Builder} object to the Environment.
#
# @param builder [Builder] The {Builder} object to add.
#
# @return [void]
def add_builder(builder)
@builders[builder.name] = builder
var_defs = builder.default_variables(self)
@ -119,19 +131,45 @@ module Rscons
end
# Add a build hook to the Environment.
#
# @yield [build_op]
# Invoke the given block with the current build operation.
# @yieldparam build_op [Hash]
# Hash with keys:
# - :builder - The builder object in use.
# - :target - Target file name.
# - :sources - List of source file(s).
# - :vars - Set of construction variable values in use.
# - :env - The Environment invoking the builder.
#
# @return [void]
def add_build_hook(&block)
@build_hooks << block
end
# Specify a build directory for this Environment.
#
# Source files from src_dir will produce object files under obj_dir.
#
# @param src_dir [String] Path to the source directory.
# @param obj_dir [String] Path to the object directory.
#
# @return [void]
def build_dir(src_dir, obj_dir)
src_dir = src_dir.gsub('\\', '/') if src_dir.is_a?(String)
@build_dirs << [src_dir, obj_dir]
end
# Return the file name to be built from source_fname with suffix suffix.
# Return the file name to be built from +source_fname+ with suffix
# +suffix+.
#
# This method takes into account the Environment's build directories.
#
# @param source_fname [String] Source file name.
# @param suffix [String] Suffix, including "." if desired.
#
# @return [String]
# The file name to be built from +source_fname+ with suffix +suffix+.
def get_build_fname(source_fname, suffix)
build_fname = Rscons.set_suffix(source_fname, suffix).gsub('\\', '/')
found_match = @build_dirs.find do |src_dir, obj_dir|
@ -151,26 +189,32 @@ module Rscons
end
# Access a construction variable or environment option.
#
# @see VarSet#[]
def [](*args)
@varset.send(:[], *args)
end
# Set a construction variable or environment option.
#
# @see VarSet#[]=
def []=(*args)
@varset.send(:[]=, *args)
end
# Add a set of construction variables or environment options.
#
# @see VarSet#append
def append(*args)
@varset.append(*args)
end
# Build all target specified in the Environment.
# Build all build targets specified in the Environment.
#
# When a block is passed to Environment.new, this method is automatically
# called after the block returns.
#
# @return [void]
def process
unless @targets.empty?
expand_paths!
@ -227,13 +271,16 @@ module Rscons
end
alias_method :build_command, :expand_varref
# Execute a builder command
# Execute a builder command.
#
# @param short_desc [String] Message to print if the Environment's echo
# mode is set to :short
# @param command [Array] The command to execute.
# @param options [Hash] Optional options, possible keys:
# - :env - environment Hash to pass to Kernel#system.
# - :options - options Hash to pass to Kernel#system.
#
# @return [true,false,nil] Return value from Kernel.system().
def execute(short_desc, command, options = {})
print_command = proc do
puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
@ -253,6 +300,14 @@ module Rscons
end
end
# Define a build target.
#
# @param method [Symbol] Method name.
# @param args [Array] Method arguments.
#
# @return [BuildTarget]
# The {BuildTarget} object registered, if the method called is a
# {Builder}.
def method_missing(method, *args)
if @builders.has_key?(method.to_s)
target, sources, vars, *rest = args
@ -269,6 +324,15 @@ module Rscons
end
end
# Add a build target.
#
# @param target [String] Build target file name.
# @param builder [Builder] The {Builder} to use to build the target.
# @param sources [Array<String>] Source file name(s).
# @param vars [Hash] Construction variable overrides.
# @param args [Object] Any extra arguments passed to the {Builder}.
#
# @return [void]
def add_target(target, builder, sources, vars, args)
@targets[target] = {
builder: builder,
@ -290,20 +354,28 @@ module Rscons
@user_deps[target] = (@user_deps[target] + user_deps).uniq
end
# Return the list of user dependencies for a given target, or +nil+ for
# none.
# Return the list of user dependencies for a given target.
#
# @param target [String] Target file name.
#
# @return [Array<String>,nil]
# List of user-specified dependencies for the target, or nil if none were
# specified.
def get_user_deps(target)
@user_deps[target]
end
# Build a list of source files into files containing one of the suffixes
# given by suffixes.
#
# This method is used internally by Rscons builders.
#
# @param sources [Array] List of source files to build.
# @param suffixes [Array] List of suffixes to try to convert source files into.
# @param cache [Cache] The Cache.
# @param vars [Hash] Extra variables to pass to the builder.
# Return a list of the converted file names.
#
# @return [Array<String>] List of the converted file name(s).
def build_sources(sources, suffixes, cache, vars)
sources.map do |source|
if source.end_with?(*suffixes)
@ -325,12 +397,14 @@ module Rscons
end
# Invoke a builder to build the given target based on the given sources.
#
# @param builder [Builder] The Builder to use.
# @param target [String] The target output file.
# @param sources [Array] List of source files.
# @param cache [Cache] The Cache.
# @param vars [Hash] Extra variables to pass to the builder.
# Return the result of the builder's run() method.
#
# @return [String,false] Return value from the {Builder}'s +run+ method.
def run_builder(builder, target, sources, cache, vars)
vars = @varset.merge(vars)
@build_hooks.each do |build_hook_block|
@ -516,6 +590,8 @@ module Rscons
# This method expand construction variable references in the target and
# source file names before passing them to the builder. It also expands
# "^/" prefixes to the Environment's build root if a build root is defined.
#
# @return [void]
def expand_paths!
@targets = @targets.reduce({}) do |result, (target, target_params)|
sources = target_params[:sources].map do |source|
@ -530,9 +606,13 @@ module Rscons
end
# Parse dependencies for a given target from a Makefile.
#
# This method is used internally by Rscons builders.
#
# @param mf_fname [String] File name of the Makefile to read.
# @param target [String] Name of the target to gather dependencies for.
#
# @return [Array<String>] Paths of dependency files.
def self.parse_makefile_deps(mf_fname, target)
deps = []
buildup = ''

View File

@ -1,9 +1,9 @@
module Rscons
# This class represents a collection of variables which can be accessed
# as certain types.
# Only nil, strings, arrays, and hashes should be stored in a VarSet.
# This class represents a collection of variables which supports efficient
# deep cloning.
class VarSet
# Create a VarSet.
#
# @param vars [Hash] Optional initial variables.
def initialize(vars = {})
@my_vars = {}
@ -11,8 +11,10 @@ module Rscons
append(vars)
end
# Access the value of variable as a particular type
# Access the value of variable.
#
# @param key [String, Symbol] The variable name.
#
# @return [Object] The variable's value.
def [](key)
if @my_vars.include?(key)
@ -29,15 +31,19 @@ module Rscons
end
# Assign a value to a variable.
#
# @param key [String, Symbol] The variable name.
#
# @param val [Object] The value to set.
def []=(key, val)
@my_vars[key] = val
end
# Check if the VarSet contains a variable.
#
# @param key [String, Symbol] The variable name.
# @return [true, false] Whether the VarSet contains a variable.
#
# @return [Boolean] Whether the VarSet contains the variable.
def include?(key)
if @my_vars.include?(key)
true
@ -48,8 +54,11 @@ module Rscons
end
end
# Add or overwrite a set of variables
# Add or overwrite a set of variables.
#
# @param values [VarSet, Hash] New set of variables.
#
# @return [self]
def append(values)
coa!
if values.is_a?(VarSet)
@ -62,7 +71,10 @@ module Rscons
end
# Create a new VarSet object based on the first merged with other.
#
# @param other [VarSet, Hash] Other variables to add or overwrite.
#
# @return [VarSet] The newly created VarSet.
def merge(other = {})
coa!
varset = self.class.new
@ -71,9 +83,13 @@ module Rscons
end
alias_method :clone, :merge
# Replace "$" variable references in varref with the variables values,
# recursively.
# Replace "$\{var}" variable references in varref with the expanded
# variables' values, recursively.
#
# @param varref [String, Array] Value containing references to variables.
#
# @return [String, Array]
# Expanded value with "$\{var}" variable references replaced.
def expand_varref(varref)
if varref.is_a?(Array)
varref.map do |ent|
@ -99,6 +115,8 @@ module Rscons
private
# Move all VarSet variables into the copy-on-access list.
#
# @return [void]
def coa!
unless @my_vars.empty?
@coa_vars.unshift(@my_vars)
@ -107,8 +125,13 @@ module Rscons
end
# Create a deep copy of an object.
# @param obj [nil, String, Array, Hash] Object to deep copy.
# @return [nil, String, Array, Hash] Deep copied value.
#
# Only objects which are of type String, Array, or Hash are deep copied.
# Any other object just has its referenced copied.
#
# @param obj [Object] Object to deep copy.
#
# @return [Object] Deep copied value.
def deep_dup(obj)
obj_class = obj.class
if obj_class == Hash