Compare commits

..
29 Commits
Author SHA1 Message Date
josh e041ea6612 v0.0.11 2013-09-19 17:06:37 -04:00
josh ab51ddcc1b do not try to clean directories that have already been removed 2013-09-19 17:06:20 -04:00
josh 3e4e9cce1c v0.0.10 2013-09-19 16:48:15 -04:00
josh 32d19489cb Cache: encode directory names in __ENCODING__ - close #3 2013-09-19 16:45:35 -04:00
josh 45a0d56c54 recover from, and warn when, .rsconscache loads something other than a Hash 2013-09-19 16:18:07 -04:00
josh 9b954d9d98 v0.0.9 2013-09-19 09:43:17 -04:00
josh e63b4c932f Cache: create missing hash entries from previous versions of the cache file 2013-09-19 09:43:00 -04:00
josh 97e11f45e5 v0.0.8 2013-09-18 21:18:00 -04:00
josh 5c6239ea6d Rscons.clean() removes any directories it created if they are empty 2013-09-18 21:17:42 -04:00
josh 770a22250a add Rscons.clear() class method 2013-09-17 21:48:50 -04:00
josh 983cb7cf21 v0.0.7 2013-09-16 23:03:14 -04:00
josh 986b8f08cc prepend builder-temporary construction variables with "_"; reserve lowercase string variables for user 2013-09-16 22:30:16 -04:00
josh f13664331f create requisite output directories for build targets; refactor common buile functionality into Builder#standard_build() 2013-09-15 15:27:16 -04:00
josh 17c7bf1d31 v0.0.6 2013-09-12 23:37:37 -04:00
josh 64d15602cc add Library default builder 2013-09-12 23:35:34 -04:00
josh e04e67698a add rspec test for overridding construction variables for an individual builer 2013-09-12 23:05:04 -04:00
josh 837dff9374 pass extra construction variables to Builder#run() 2013-09-12 22:57:22 -04:00
josh 75f2418570 refactor some Program functionality into Environment#build_sources() 2013-09-12 22:38:52 -04:00
josh 711e96cec8 write out cache file when raising a build error exception 2013-08-12 14:40:46 -04:00
josh 289d27d41d raise Rscons::BuildError on a build failure 2013-08-12 13:13:22 -04:00
josh 052b1afe19 v0.0.3 2013-08-05 17:19:22 -04:00
josh 72976be765 fix verifying a target's checksum 2013-08-05 17:19:08 -04:00
josh ad2424007f v0.0.2 2013-08-05 14:56:20 -04:00
josh c3c6385068 String#has_suffix?(): allow nested arrays of suffixes 2013-08-05 14:51:07 -04:00
josh 13b9499fbf Environment#build_dir(): allow src_dir to be a regex 2013-08-05 14:48:47 -04:00
josh 4286925f95 Environment#clone(): do not clone build directories 2013-08-05 14:48:31 -04:00
josh 0db5614555 rename LIBPATHS default construction variable to LIBPATH 2013-08-05 14:34:59 -04:00
josh 5d0bbf73ab specify gem homepage and license - close #1 2013-08-05 14:31:48 -04:00
josh 75977981c0 fix parsing Makefile dependencies when they spanned multiple lines 2013-08-05 14:27:57 -04:00
21 changed files with 302 additions and 65 deletions

No files matched your search

+1 -1
View File
@@ -1,5 +1,5 @@
class MySource < Rscons::Builder class MySource < Rscons::Builder
def run(target, sources, cache, env) def run(target, sources, cache, env, vars = {})
File.open(target, 'w') do |fh| File.open(target, 'w') do |fh|
fh.puts <<EOF fh.puts <<EOF
#define THE_VALUE 5678 #define THE_VALUE 5678
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new(echo: :command) do |env|
env.Program('library', ['lib.a', 'three.c'])
env.Library("lib.a", ['one.c', 'two.c'], 'CPPFLAGS' => ['-Dmake_lib'])
end
+8
View File
@@ -0,0 +1,8 @@
#include <stdio.h>
#ifdef make_lib
int main(int argc, char *argv[])
{
printf("Library\n");
}
#endif
View File
Whitespace-only changes.
View File
Whitespace-only changes.
+4
View File
@@ -0,0 +1,4 @@
Rscons::Environment.new(echo: :command) do |env|
env.Object("one.o", "one.c", 'CPPFLAGS' => ['-DONE'])
env.Program('two_sources', ['one.o', 'two.c'])
end
+8
View File
@@ -0,0 +1,8 @@
#include <stdio.h>
#ifdef ONE
int main(int argc, char *argv[])
{
printf("This is a C program with two sources.\n");
}
#endif
+3
View File
@@ -0,0 +1,3 @@
#ifdef ONE
#error ONE should not be defined
#endif
+22
View File
@@ -8,13 +8,35 @@ require "rscons/monkey/module"
require "rscons/monkey/string" require "rscons/monkey/string"
# default builders # default builders
require "rscons/builders/library"
require "rscons/builders/object" require "rscons/builders/object"
require "rscons/builders/program" require "rscons/builders/program"
# Namespace module for rscons classes # Namespace module for rscons classes
module Rscons module Rscons
DEFAULT_BUILDERS = [ DEFAULT_BUILDERS = [
Library,
Object, Object,
Program, Program,
] ]
class BuildError < Exception
end
# Remove all generated files
def self.clean
cache = Cache.new
# remove all built files
cache.targets.each do |target|
FileUtils.rm_f(target)
end
# remove all created directories if they are empty
cache.directories.sort {|a, b| b.size <=> a.size}.each do |directory|
next unless File.directory?(directory)
if (Dir.entries(directory) - ['.', '..']).empty?
Dir.rmdir(directory) rescue nil
end
end
Cache.clear
end
end end
+15
View File
@@ -1,3 +1,5 @@
require "fileutils"
module Rscons 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
@@ -16,5 +18,18 @@ module Rscons
def produces?(target, source, env) def produces?(target, source, env)
false false
end 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.
def standard_build(short_cmd_string, target, command, sources, env, cache)
unless cache.up_to_date?(target, command, sources)
cache.mkdir_p(File.dirname(target))
FileUtils.rm_f(target)
return false unless env.execute(short_cmd_string, command)
cache.register_build(target, command, sources)
end
target
end
end end
end end
+28
View File
@@ -0,0 +1,28 @@
require 'fileutils'
module Rscons
# A default RScons builder that produces a static library archive.
class Library < Builder
def default_variables(env)
{
'AR' => 'ar',
'LIBSUFFIX' => '.a',
'ARFLAGS' => [],
'ARCOM' => ['$AR', 'rcs', '$ARFLAGS', '$_TARGET', '$_SOURCES']
}
end
def run(target, sources, cache, env, vars = {})
# build sources to linkable objects
objects = env.build_sources(sources, [env['OBJSUFFIX'], env['LIBSUFFIX']].flatten, cache, vars)
if objects
vars = vars.merge({
'_TARGET' => target,
'_SOURCES' => objects,
})
command = env.build_command(env['ARCOM'], vars)
standard_build("AR #{target}", target, command, objects, env, cache)
end
end
end
end
+17 -15
View File
@@ -11,8 +11,8 @@ module Rscons
'ASSUFFIX' => '.S', 'ASSUFFIX' => '.S',
'ASPPPATH' => '$CPPPATH', 'ASPPPATH' => '$CPPPATH',
'ASPPFLAGS' => '$CPPFLAGS', 'ASPPFLAGS' => '$CPPFLAGS',
'ASDEPGEN' => ['-MMD', '-MF', '$DEPFILE'], 'ASDEPGEN' => ['-MMD', '-MF', '$_DEPFILE'],
'ASCOM' => ['$AS', '-c', '-o', '$TARGET', '$ASDEPGEN', '-I$[ASPPPATH]', '$ASPPFLAGS', '$ASFLAGS', '$SOURCES'], 'ASCOM' => ['$AS', '-c', '-o', '$_TARGET', '$ASDEPGEN', '-I$[ASPPPATH]', '$ASPPFLAGS', '$ASFLAGS', '$_SOURCES'],
'CPPFLAGS' => [], 'CPPFLAGS' => [],
'CPPPATH' => [], 'CPPPATH' => [],
@@ -20,14 +20,14 @@ module Rscons
'CC' => 'gcc', 'CC' => 'gcc',
'CFLAGS' => [], 'CFLAGS' => [],
'CSUFFIX' => '.c', 'CSUFFIX' => '.c',
'CCDEPGEN' => ['-MMD', '-MF', '$DEPFILE'], 'CCDEPGEN' => ['-MMD', '-MF', '$_DEPFILE'],
'CCCOM' => ['$CC', '-c', '-o', '$TARGET', '$CCDEPGEN', '-I$[CPPPATH]', '$CPPFLAGS', '$CFLAGS', '$SOURCES'], 'CCCOM' => ['$CC', '-c', '-o', '$_TARGET', '$CCDEPGEN', '-I$[CPPPATH]', '$CPPFLAGS', '$CFLAGS', '$_SOURCES'],
'CXX' => 'g++', 'CXX' => 'g++',
'CXXFLAGS' => [], 'CXXFLAGS' => [],
'CXXSUFFIX' => '.cc', 'CXXSUFFIX' => '.cc',
'CXXDEPGEN' => ['-MMD', '-MF', '$DEPFILE'], 'CXXDEPGEN' => ['-MMD', '-MF', '$_DEPFILE'],
'CXXCOM' =>['$CXX', '-c', '-o', '$TARGET', '$CXXDEPGEN', '-I$[CPPPATH]', '$CPPFLAGS', '$CXXFLAGS', '$SOURCES'], 'CXXCOM' =>['$CXX', '-c', '-o', '$_TARGET', '$CXXDEPGEN', '-I$[CPPPATH]', '$CPPFLAGS', '$CXXFLAGS', '$_SOURCES'],
} }
end end
@@ -38,12 +38,12 @@ module Rscons
source.has_suffix?(env['CXXSUFFIX'])) source.has_suffix?(env['CXXSUFFIX']))
end end
def run(target, sources, cache, env) def run(target, sources, cache, env, vars = {})
vars = { vars = vars.merge({
'TARGET' => target, '_TARGET' => target,
'SOURCES' => sources, '_SOURCES' => sources,
'DEPFILE' => target.set_suffix('.mf'), '_DEPFILE' => target.set_suffix('.mf'),
} })
com_prefix = if sources.first.has_suffix?(env['ASSUFFIX']) com_prefix = if sources.first.has_suffix?(env['ASSUFFIX'])
'AS' 'AS'
elsif sources.first.has_suffix?(env['CSUFFIX']) elsif sources.first.has_suffix?(env['CSUFFIX'])
@@ -55,11 +55,13 @@ module Rscons
end end
command = env.build_command(env["#{com_prefix}COM"], vars) command = env.build_command(env["#{com_prefix}COM"], vars)
unless cache.up_to_date?(target, command, sources) unless cache.up_to_date?(target, command, sources)
cache.mkdir_p(File.dirname(target))
FileUtils.rm_f(target)
return false unless env.execute("#{com_prefix} #{target}", command) return false unless env.execute("#{com_prefix} #{target}", command)
deps = sources deps = sources
if File.exists?(vars['DEPFILE']) if File.exists?(vars['_DEPFILE'])
deps += env.parse_makefile_deps(vars['DEPFILE'], target) deps += env.parse_makefile_deps(vars['_DEPFILE'], target)
FileUtils.rm_f(vars['DEPFILE']) FileUtils.rm_f(vars['_DEPFILE'])
end end
cache.register_build(target, command, deps.uniq) cache.register_build(target, command, deps.uniq)
end end
+10 -23
View File
@@ -8,40 +8,27 @@ module Rscons
'OBJSUFFIX' => '.o', 'OBJSUFFIX' => '.o',
'LIBSUFFIX' => '.a', 'LIBSUFFIX' => '.a',
'LDFLAGS' => [], 'LDFLAGS' => [],
'LIBPATHS' => [], 'LIBPATH' => [],
'LIBS' => [], 'LIBS' => [],
'LDCOM' => ['$LD', '-o', '$TARGET', '$LDFLAGS', '$SOURCES', '-L$[LIBPATHS]', '-l$[LIBS]'] 'LDCOM' => ['$LD', '-o', '$_TARGET', '$LDFLAGS', '$_SOURCES', '-L$[LIBPATH]', '-l$[LIBS]']
} }
end end
def run(target, sources, cache, env) def run(target, sources, cache, env, vars = {})
# convert sources to object file names # build sources to linkable objects
objects = sources.map do |source| objects = env.build_sources(sources, [env['OBJSUFFIX'], env['LIBSUFFIX']].flatten, cache, vars)
if source.has_suffix?([env['OBJSUFFIX'], env['LIBSUFFIX']])
source
else
o_file = env.get_build_fname(source, env['OBJSUFFIX', :string])
builder = env.builders.values.find { |b| b.produces?(o_file, source, env) }
builder or raise "No builder found to convert input source #{source.inspect} to an object file."
builder.run(o_file, [source], cache, env) or break
end
end
if objects if objects
use_cxx = sources.map do |s| use_cxx = sources.map do |s|
s.has_suffix?(env['CXXSUFFIX']) s.has_suffix?(env['CXXSUFFIX'])
end.any? end.any?
ld_alt = use_cxx ? env['CXX'] : env['CC'] ld_alt = use_cxx ? env['CXX'] : env['CC']
vars = { vars = vars.merge({
'TARGET' => target, '_TARGET' => target,
'SOURCES' => objects, '_SOURCES' => objects,
'LD' => env['LD'] || ld_alt, 'LD' => env['LD'] || ld_alt,
} })
command = env.build_command(env['LDCOM'], vars) command = env.build_command(env['LDCOM'], vars)
unless cache.up_to_date?(target, command, objects) standard_build("LD #{target}", target, command, objects, env, cache)
return false unless env.execute("LD #{target}", command)
cache.register_build(target, command, objects)
end
target
end end
end end
end end
+43 -5
View File
@@ -36,6 +36,11 @@ module Rscons
# ] # ]
# } # }
# } # }
# directories: {
# 'build' => true,
# 'build/one' => true,
# 'build/two' => true,
# }
# } # }
class Cache class Cache
#### Constants #### Constants
@@ -55,10 +60,14 @@ module Rscons
# Create a Cache object and load in the previous contents from the cache # Create a Cache object and load in the previous contents from the cache
# file. # file.
def initialize def initialize
@cache = YAML.load(File.read(CACHE_FILE)) rescue { @cache = YAML.load(File.read(CACHE_FILE)) rescue {}
targets: {}, unless @cache.is_a?(Hash)
version: VERSION, $stderr.puts "Warning: #{CACHE_FILE} was corrupt. Contents:\n#{@cache.inspect}"
} @cache = {}
end
@cache[:targets] ||= {}
@cache[:directories] ||= {}
@cache[:version] ||= VERSION
@lookup_checksums = {} @lookup_checksums = {}
end end
@@ -80,6 +89,7 @@ module Rscons
# @return true value if the target is up to date, meaning that: # @return true value if the target is up to date, meaning that:
# - the target exists on disk # - the target exists on disk
# - the cache has information for the target # - the cache has information for the target
# - the target's checksum matches its checksum when it was last built
# - the command used to build the target is the same as last time # - the command used to build the target is the same as last time
# - all dependencies listed are also listed in the cache, or, if # - all dependencies listed are also listed in the cache, or, if
# :strict_deps was given in options, the list of dependencies is # :strict_deps was given in options, the list of dependencies is
@@ -93,6 +103,9 @@ module Rscons
# target must be registered in the cache # target must be registered in the cache
return false unless @cache[:targets].has_key?(target) return false unless @cache[:targets].has_key?(target)
# target must have the same checksum as when it was built last
return false unless @cache[:targets][target][:checksum] == lookup_checksum(target)
# command used to build target must be identical # command used to build target must be identical
return false unless @cache[:targets][target][:command] == command return false unless @cache[:targets][target][:command] == command
@@ -128,6 +141,31 @@ module Rscons
} }
end end
# Return a 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.
def mkdir_p(path)
parts = path.split(/[\\\/]/)
(0..parts.size).each do |i|
subpath = File.join(*parts[0, i + 1]).encode(__ENCODING__)
unless File.exists?(subpath)
FileUtils.mkdir(subpath)
unless @cache[:directories].include?(subpath)
@cache[:directories][subpath] = true
end
end
end
end
# Return a list of directories which were created as a part of the build
def directories
@cache[:directories].keys
end
# Private Instance Methods # Private Instance Methods
private private
@@ -141,7 +179,7 @@ module Rscons
# Calculate and return a file's checksum # Calculate and return a file's checksum
# @param file [String] The file name. # @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, {mode: 'rb'})).encode(__ENCODING__) rescue ''
end end
end end
end end
+54 -18
View File
@@ -11,16 +11,17 @@ module Rscons
# Create an Environment object. # Create an Environment object.
# @param variables [Hash] # @param variables [Hash]
# The variables hash can contain both construction variables, which are # The variables hash can contain construction variables, which are
# uppercase strings (such as "CC" or "LDFLAGS"), and RScons options, # uppercase strings (such as "CC" or "LDFLAGS"), user variables, which
# which are lowercase symbols (such as :echo). # are lowercase strings (such as "sources"), and RScons options, which
# are lowercase symbols (such as :echo).
# If a block is given, the Environment object is yielded to the block and # If a block is given, the Environment object is yielded to the block and
# when the block returns, the {#process} method is automatically called. # when the block returns, the {#process} method is automatically called.
def initialize(variables = {}) def initialize(variables = {})
@varset = VarSet.new(variables) @varset = VarSet.new(variables)
@targets = {} @targets = {}
@builders = {} @builders = {}
@build_dirs = {} @build_dirs = []
@varset[:exclude_builders] ||= [] @varset[:exclude_builders] ||= []
unless @varset[:exclude_builders] == :all unless @varset[:exclude_builders] == :all
exclude_builders = Set.new(@varset[:exclude_builders] || []) exclude_builders = Set.new(@varset[:exclude_builders] || [])
@@ -52,9 +53,6 @@ module Rscons
@builders.each do |builder_name, builder| @builders.each do |builder_name, builder|
env.add_builder(builder) env.add_builder(builder)
end end
@build_dirs.each do |src_dir, obj_dir|
env.build_dir(src_dir, obj_dir)
end
env.append(@varset) env.append(@varset)
env.append(variables) env.append(variables)
@@ -79,7 +77,9 @@ module Rscons
# Specify a build directory for this Environment. # Specify a build directory for this Environment.
# Source files from src_dir will produce object files under obj_dir. # 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('\\', '/') src_dir = src_dir.gsub('\\', '/') if src_dir.is_a?(String)
obj_dir = obj_dir.gsub('\\', '/')
@build_dirs << [src_dir, obj_dir]
end 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.
@@ -89,9 +89,13 @@ module Rscons
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|
build_fname.sub!(/^#{src_dir}\//, "#{obj_dir}/") if src_dir.is_a?(Regexp)
build_fname.sub!(src_dir, obj_dir)
else
build_fname.sub!(/^#{src_dir}\//, "#{obj_dir}/")
end
build_fname.gsub!('\\', '/')
end end
FileUtils.mkdir_p(File.dirname(build_fname))
build_fname build_fname
end end
@@ -137,7 +141,7 @@ module Rscons
@targets[target][:source], @targets[target][:source],
cache, cache,
self, self,
*@targets[target][:args]) @targets[target][:vars] || {})
else else
false false
end end
@@ -145,8 +149,8 @@ module Rscons
@targets.each do |target, info| @targets.each do |target, info|
next if targets_processed.include?(target) next if targets_processed.include?(target)
unless process_target.call(target) unless process_target.call(target)
$stderr.puts "Error: failed to build #{target}" cache.write
break raise BuildError.new("Failed to build #{target}")
end end
end end
cache.write cache.write
@@ -189,11 +193,15 @@ module Rscons
alias_method :orig_method_missing, :method_missing alias_method :orig_method_missing, :method_missing
def method_missing(method, *args) def method_missing(method, *args)
if @builders.has_key?(method.to_s) if @builders.has_key?(method.to_s)
target, source, *rest = args target, source, vars, *rest = args
unless vars.nil? or vars.is_a?(Hash) or vars.is_a?(VarSet)
raise "Unexpected construction variable set: #{vars.inspect}"
end
source = [source] unless source.is_a?(Array) source = [source] unless source.is_a?(Array)
@targets[target] = { @targets[target] = {
builder: @builders[method.to_s], builder: @builders[method.to_s],
source: source, source: source,
vars: vars,
args: rest, args: rest,
} }
else else
@@ -212,10 +220,11 @@ module Rscons
if line =~ /^(.*)\\\s*$/ if line =~ /^(.*)\\\s*$/
buildup += ' ' + $1 buildup += ' ' + $1
else else
if line =~ /^(.*): (.*)$/ buildup += ' ' + line
target, tdeps = $1.strip, $2 if buildup =~ /^(.*): (.*)$/
if target == target mf_target, mf_deps = $1.strip, $2
deps += tdeps.split(' ').map(&:strip) if mf_target == target
deps += mf_deps.split(' ').map(&:strip)
end end
end end
buildup = '' buildup = ''
@@ -223,5 +232,32 @@ module Rscons
end end
deps deps
end 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.
# Return a list of the converted file names.
def build_sources(sources, suffixes, cache, vars = {})
sources.map do |source|
if source.has_suffix?(suffixes)
source
else
converted = nil
suffixes.each do |suffix|
converted_fname = get_build_fname(source, suffix)
builder = @builders.values.find { |b| b.produces?(converted_fname, source, self) }
if builder
converted = builder.run(converted_fname, [source], cache, self, vars)
return nil unless converted
break
end
end
converted or raise "Could not find a builder to handle #{source.inspect}."
end
end
end
end end
end end
+1
View File
@@ -6,6 +6,7 @@ class String
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)
suffix = suffix.flatten
suffix.find {|s| self.end_with?(s)} suffix.find {|s| self.end_with?(s)}
end end
end end
+5 -1
View File
@@ -8,7 +8,11 @@ module Rscons
# Create a VarSet # Create a VarSet
# @param vars [Hash] Optional initial variables. # @param vars [Hash] Optional initial variables.
def initialize(vars = {}) def initialize(vars = {})
@vars = vars if vars.is_a?(VarSet)
@vars = vars.clone.vars
else
@vars = vars
end
end end
# Access the value of variable as a particular type # Access the value of variable as a particular type
+1 -1
View File
@@ -1,4 +1,4 @@
module Rscons module Rscons
# gem version # gem version
VERSION = "0.0.1" VERSION = "0.0.11"
end end
+2 -1
View File
@@ -10,7 +10,8 @@ Gem::Specification.new do |gem|
gem.email = ["jholtrop@gmail.com"] gem.email = ["jholtrop@gmail.com"]
gem.description = %q{Software construction library inspired by SCons and implemented in Ruby} gem.description = %q{Software construction library inspired by SCons and implemented in Ruby}
gem.summary = %q{Software construction library inspired by SCons and implemented in Ruby} gem.summary = %q{Software construction library inspired by SCons and implemented in Ruby}
gem.homepage = "" gem.homepage = "https://github.com/holtrop/rscons"
gem.license = 'MIT'
gem.files = `git ls-files`.split($/) gem.files = `git ls-files`.split($/)
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
+52
View File
@@ -120,6 +120,35 @@ describe Rscons do
File.exists?('build/two/two.o').should be_true File.exists?('build/two/two.o').should be_true
end end
it 'cleans built files' do
lines = test_dir('build_dir')
`./build_dir`.should == "Hello from two()\n"
File.exists?('build/one/one.o').should be_true
File.exists?('build/two/two.o').should be_true
Rscons.clean
File.exists?('build/one/one.o').should be_false
File.exists?('build/two/two.o').should be_false
File.exists?('build/one').should be_false
File.exists?('build/two').should be_false
File.exists?('build').should be_false
File.exists?('src/one/one.c').should be_true
end
it 'does not clean created directories if other non-rscons-generated files reside there' do
lines = test_dir('build_dir')
`./build_dir`.should == "Hello from two()\n"
File.exists?('build/one/one.o').should be_true
File.exists?('build/two/two.o').should be_true
File.open('build/two/tmp', 'w') { |fh| fh.puts "dum" }
Rscons.clean
File.exists?('build/one/one.o').should be_false
File.exists?('build/two/two.o').should be_false
File.exists?('build/one').should be_false
File.exists?('build/two').should be_true
File.exists?('build').should be_true
File.exists?('src/one/one.c').should be_true
end
it 'allows Ruby classes as custom builders to be used to construct files' do it 'allows Ruby classes as custom builders to be used to construct files' do
lines = test_dir('custom_builder') lines = test_dir('custom_builder')
lines.should == ['CC program.o', 'LD program'] lines.should == ['CC program.o', 'LD program']
@@ -143,4 +172,27 @@ describe Rscons do
`./simple`.should == "This is a simple C++ program\n" `./simple`.should == "This is a simple C++ program\n"
end end
it 'allows overriding construction variables for individual builder calls' do
lines = test_dir('two_sources')
lines.should == [
'gcc -c -o one.o -MMD -MF one.mf -DONE one.c',
'gcc -c -o two.o -MMD -MF two.mf two.c',
'gcc -o two_sources one.o two.o',
]
File.exists?('two_sources').should be_true
`./two_sources`.should == "This is a C program with two sources.\n"
end
it 'builds a static library archive' do
lines = test_dir('library')
lines.should == [
'gcc -c -o one.o -MMD -MF one.mf -Dmake_lib one.c',
'gcc -c -o two.o -MMD -MF two.mf -Dmake_lib two.c',
'ar rcs lib.a one.o two.o',
'gcc -c -o three.o -MMD -MF three.mf three.c',
'gcc -o library lib.a three.o',
]
File.exists?('library').should be_true
`ar t lib.a`.should == "one.o\ntwo.o\n"
end
end end
+24
View File
@@ -0,0 +1,24 @@
module Rscons
describe Environment do
describe '.parse_makefile_deps' do
it 'handles dependencies on one line' do
File.should_receive(:read).with('makefile').and_return(<<EOS)
module.o: source.cc
EOS
env = Environment.new
env.parse_makefile_deps('makefile', 'module.o').should == ['source.cc']
end
it 'handles dependencies split across many lines' do
File.should_receive(:read).with('makefile').and_return(<<EOS)
module.o: module.c \\
module.h \\
other.h
EOS
env = Environment.new
env.parse_makefile_deps('makefile', 'module.o').should == [
'module.c', 'module.h', 'other.h']
end
end
end
end