add/update YARD documentation

This commit is contained in:
Josh Holtrop 2013-08-04 15:39:01 -04:00
parent c0a69a5055
commit 8d4be1b51a
10 changed files with 160 additions and 35 deletions

View File

@ -11,6 +11,7 @@ require "rscons/monkey/string"
require "rscons/builders/object" require "rscons/builders/object"
require "rscons/builders/program" require "rscons/builders/program"
# Namespace module for rscons classes
module Rscons module Rscons
DEFAULT_BUILDERS = [ DEFAULT_BUILDERS = [
Object, Object,

View File

@ -1,8 +1,18 @@
module Rscons module Rscons
# Class to hold an object that knows how to build a certain type of file.
class Builder class Builder
# Return a set of default variable values for the Environment to use
# unless the user overrides any.
# @param env [Environment] The Environment.
def default_variables(env) def default_variables(env)
{} {}
end 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.
def produces?(target, source, env) def produces?(target, source, env)
false false
end end

View File

@ -1,4 +1,6 @@
module Rscons module Rscons
# A default RScons builder which knows how to produce an object file from
# various types of source files.
class Object < Builder class Object < Builder
def default_variables(env) def default_variables(env)
{ {

View File

@ -1,4 +1,6 @@
module Rscons module Rscons
# A default RScons builder that knows how to link object files into an
# executable program.
class Program < Builder class Program < Builder
def default_variables(env) def default_variables(env)
{ {

View File

@ -5,46 +5,55 @@ require 'set'
require 'rscons/version' require 'rscons/version'
module Rscons module Rscons
# The Cache class keeps track of file checksums, build target commands and
# dependencies in a YAML file which persists from one invocation to the next.
# Example cache: # Example cache:
# { # {
# version: '1.2.3', # version: '1.2.3',
# targets: { # targets: {
# 'program' => { # 'program' => {
# 'checksum' => 'A1B2C3D4', # 'checksum' => 'A1B2C3D4',
# 'command' => ['gcc', '-o', 'program', 'program.o'], # 'command' => ['gcc', '-o', 'program', 'program.o'],
# 'deps' => [ # 'deps' => [
# { # {
# 'fname' => 'program.o', # 'fname' => 'program.o',
# 'checksum' => '87654321', # 'checksum' => '87654321',
# } # }
# ], # ],
# } # }
# 'program.o' => { # 'program.o' => {
# 'checksum' => '87654321', # 'checksum' => '87654321',
# 'command' => ['gcc', '-c', '-o', 'program.o', 'program.c'], # 'command' => ['gcc', '-c', '-o', 'program.o', 'program.c'],
# 'deps' => [ # 'deps' => [
# { # {
# 'fname' => 'program.c', # 'fname' => 'program.c',
# 'checksum' => '456789ABC', # 'checksum' => '456789ABC',
# }, # },
# { # {
# 'fname' => 'program.h', # 'fname' => 'program.h',
# 'checksum' => '7979764643', # 'checksum' => '7979764643',
# } # }
# ] # ]
# }
# } # }
# } # }
# }
class Cache class Cache
# Constants #### Constants
# Name of the file to store cache information in
CACHE_FILE = '.rsconscache' CACHE_FILE = '.rsconscache'
# Class Methods #### Class Methods
# Remove the cache file
def self.clear def self.clear
FileUtils.rm_f(CACHE_FILE) FileUtils.rm_f(CACHE_FILE)
end end
# Instance Methods #### Instance Methods
# Create a Cache object and load in the previous contents from the cache
# file.
def initialize def initialize
@cache = YAML.load(File.read(CACHE_FILE)) rescue { @cache = YAML.load(File.read(CACHE_FILE)) rescue {
targets: {}, targets: {},
@ -53,12 +62,30 @@ module Rscons
@lookup_checksums = {} @lookup_checksums = {}
end end
# Write the cache to disk to be loaded next time.
def write def write
File.open(CACHE_FILE, 'w') do |fh| File.open(CACHE_FILE, 'w') do |fh|
fh.puts(YAML.dump(@cache)) fh.puts(YAML.dump(@cache))
end end
end end
# Check if a target is up to date
# @param target [String] The name of the target file.
# @param command [Array] The command used to build the target.
# @param deps [Array] List of the target's dependency files.
# @param options [Hash] Optional options. Can contain the following keys:
# :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 true value if the target is up to date, meaning that:
# - the target exists on disk
# - the cache has information for the target
# - the command used to build the target is the same as last time
# - all dependencies listed are also listed in the cache, or, if
# :strict_deps was given in options, the list of dependencies is
# exactly equal to those cached
# - each cached dependency file's current checksum matches the checksum
# stored in the cache file
def up_to_date?(target, command, deps, options = {}) def up_to_date?(target, command, deps, options = {})
# target file must exist on disk # target file must exist on disk
return false unless File.exists?(target) return false unless File.exists?(target)
@ -84,6 +111,10 @@ module Rscons
end.all? end.all?
end end
# Store cache information about a target built by a builder
# @param target [String] The name of the target.
# @param command [Array] The command used to build the target.
# @param deps [Array] List of dependencies for the target.
def register_build(target, command, deps) def register_build(target, command, deps)
@cache[:targets][target] = { @cache[:targets][target] = {
command: command, command: command,
@ -100,10 +131,15 @@ module Rscons
# Private Instance Methods # Private Instance Methods
private private
# Return a file's checksum, or the previously calculated checksum for
# the same file
# @param file [String] The file name.
def lookup_checksum(file) def lookup_checksum(file)
@lookup_checksums[file] || calculate_checksum(file) @lookup_checksums[file] || calculate_checksum(file)
end end
# Calculate and return a file's checksum
# @param file [String] The file name.
def calculate_checksum(file) def calculate_checksum(file)
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file)).encode(__ENCODING__) rescue '' @lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file)).encode(__ENCODING__) rescue ''
end end

View File

@ -2,14 +2,17 @@ require 'set'
require 'fileutils' require 'fileutils'
module Rscons module Rscons
# The Environment class is the main programmatic interface to RScons. It
# contains a collection of construction variables, options, builders, and
# rules for building targets.
class Environment class Environment
# [Array] of {Builder} objects.
attr_reader :builders attr_reader :builders
# Initialize a newly constructed Environment object # Create an Environment object.
# === Arguments # @param variables [Hash]
# +variables+ _Hash_ :: # The variables hash can contain both construction variables, which are
# the variables hash can contain both construction variables, which are # uppercase strings (such as "CC" or "LDFLAGS"), and RScons options,
# uppercase strings (such as "CC" or "LDFLAGS"), and rscons options,
# which are lowercase symbols (such as :echo). # which are lowercase symbols (such as :echo).
def initialize(variables = {}) def initialize(variables = {})
@varset = VarSet.new(variables) @varset = VarSet.new(variables)
@ -36,6 +39,10 @@ module Rscons
end end
end end
# Make a copy of the Environment object.
# The cloned environment will contain a copy of all environment options,
# construction variables, builders, and build directories. It will not
# contain a copy of the targets.
def clone(variables = {}) def clone(variables = {})
env = Environment.new() env = Environment.new()
@builders.each do |builder_name, builder| @builders.each do |builder_name, builder|
@ -54,6 +61,7 @@ module Rscons
env env
end end
# Add a {Builder} object to the Environment.
def add_builder(builder) def add_builder(builder)
@builders[builder.class.short_name] = builder @builders[builder.class.short_name] = builder
var_defs = builder.default_variables(self) var_defs = builder.default_variables(self)
@ -64,10 +72,16 @@ module Rscons
end end
end end
# Specify a build directory for this Environment.
# Source files from src_dir will produce object files under obj_dir.
def build_dir(src_dir, obj_dir) def build_dir(src_dir, obj_dir)
@build_dirs[src_dir.gsub('\\', '/')] = obj_dir.gsub('\\', '/') @build_dirs[src_dir.gsub('\\', '/')] = obj_dir.gsub('\\', '/')
end end
# Return the file name to be built from source_fname with suffix suffix.
# This method takes into account the Environment's build directories.
# It also creates any parent directories needed to be able to open and
# write to the output file.
def get_build_fname(source_fname, suffix) def get_build_fname(source_fname, suffix)
build_fname = source_fname.set_suffix(suffix).gsub('\\', '/') build_fname = source_fname.set_suffix(suffix).gsub('\\', '/')
@build_dirs.each do |src_dir, obj_dir| @build_dirs.each do |src_dir, obj_dir|
@ -77,26 +91,37 @@ module Rscons
build_fname build_fname
end end
# Access a construction variable or environment option.
# @see VarSet#[]
def [](*args) def [](*args)
@varset.send(:[], *args) @varset.send(:[], *args)
end end
# Set a construction variable or environment option.
# @see VarSet#[]=
def []=(*args) def []=(*args)
@varset.send(:[]=, *args) @varset.send(:[]=, *args)
end end
# Add a set of construction variables or environment options.
# @see VarSet#append
def append(*args) def append(*args)
@varset.send(:append, *args) @varset.send(:append, *args)
end end
# Return a list of target file names
def targets def targets
@targets.keys @targets.keys
end end
# Return a list of sources needed to build target target.
def target_sources(target) def target_sources(target)
@targets[target][:source] rescue nil @targets[target][:source] rescue nil
end end
# Build all target specified in the Environment.
# When a block is passed to Environment.new, this method is automatically
# called after the block returns.
def process def process
cache = Cache.new cache = Cache.new
targets_processed = Set.new targets_processed = Set.new
@ -123,10 +148,23 @@ module Rscons
cache.write cache.write
end end
# Build a command line from the given template, resolving references to
# variables using the Environment's construction variables and any extra
# variables specified.
# @param command_template [Array] template for the command with variable
# references
# @param extra_vars [Hash, VarSet] extra variables to use in addition to
# (or replace) the Environment's construction variables when building
# the command
def build_command(command_template, extra_vars) def build_command(command_template, extra_vars)
@varset.merge(extra_vars).expand_varref(command_template) @varset.merge(extra_vars).expand_varref(command_template)
end end
# 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 to pass to {Kernel#system}.
def execute(short_desc, command, options = {}) def execute(short_desc, command, options = {})
print_command = proc do print_command = proc do
puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ') puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
@ -159,6 +197,10 @@ module Rscons
end end
end 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.
def parse_makefile_deps(mf_fname, target) def parse_makefile_deps(mf_fname, target)
deps = [] deps = []
buildup = '' buildup = ''

View File

@ -1,4 +1,6 @@
# Standard Ruby Module class.
class Module class Module
# @return the base module name (not the fully qualified name)
def short_name def short_name
name.split(':').last name.split(':').last
end end

View File

@ -1,4 +1,8 @@
# Standard Ruby String class.
class String class String
# Check if the given string ends with any of the supplied suffixes
# @param suffix [String, Array] The suffix to look for.
# @return a true value if the string ends with one of the suffixes given.
def has_suffix?(suffix) def has_suffix?(suffix)
if suffix if suffix
suffix = [suffix] if suffix.is_a?(String) suffix = [suffix] if suffix.is_a?(String)
@ -6,6 +10,9 @@ class String
end end
end end
# Return a new string with the suffix (dot character and extension) changed
# to the given suffix.
# @param suffix [String] The new suffix.
def set_suffix(suffix = '') def set_suffix(suffix = '')
sub(/\.[^.]*$/, suffix) sub(/\.[^.]*$/, suffix)
end end

View File

@ -1,11 +1,23 @@
module Rscons module Rscons
# This class represents a collection of variables which can be accessed
# as certain types
class VarSet class VarSet
# The underlying hash
attr_reader :vars attr_reader :vars
# Create a VarSet
# @param vars [Hash] Optional initial variables.
def initialize(vars = {}) def initialize(vars = {})
@vars = vars @vars = vars
end end
# Access the value of variable as a particular type
# @param key [String, Symbol] The variable name.
# @param type [Symbol, nil] Optional specification of the type desired.
# If the variable is a String and type is :array, a 1-element array with
# the variable value will be returned. If the variable is an Array and
# type is :string, the first element from the variable value will be
# returned.
def [](key, type = nil) def [](key, type = nil)
val = @vars[key] val = @vars[key]
if type == :array and val.is_a?(String) if type == :array and val.is_a?(String)
@ -17,21 +29,31 @@ module Rscons
end end
end end
# Assign a value to a variable.
# @param key [String, Symbol] The variable name.
# @param val [Object] The value.
def []=(key, val) def []=(key, val)
@vars[key] = val @vars[key] = val
end end
# Add or overwrite a set of variables
# @param values [VarSet, Hash] New set of variables.
def append(values) def append(values)
values = values.vars if values.is_a?(VarSet) values = values.vars if values.is_a?(VarSet)
@vars.merge!(values) @vars.merge!(values)
self self
end end
# Create a new VarSet object based on the first merged with other.
# @param other [VarSet, Hash] Other variables to add or overwrite.
def merge(other = {}) def merge(other = {})
VarSet.new(Marshal.load(Marshal.dump(@vars))).append(other) VarSet.new(Marshal.load(Marshal.dump(@vars))).append(other)
end end
alias_method :clone, :merge alias_method :clone, :merge
# Replace "$" variable references in varref with the variables values,
# recursively.
# @param varref [String, Array] Value containing references to variables.
def expand_varref(varref) def expand_varref(varref)
if varref.is_a?(Array) if varref.is_a?(Array)
varref.map do |ent| varref.map do |ent|

View File

@ -1,3 +1,4 @@
module Rscons module Rscons
# gem version
VERSION = "0.0.1" VERSION = "0.0.1"
end end