pass env to Cache#up_to_date?() and #register_build() instead of user_deps

This commit is contained in:
Josh Holtrop 2013-12-31 12:46:30 -05:00
parent 1868193b54
commit f8af0630b0
8 changed files with 65 additions and 46 deletions

View File

@ -22,12 +22,12 @@ module Rscons
# Check if the cache is up to date for the target and if not execute the # Check if the cache is up to date for the target and if not execute the
# build command. # build command.
# Return the name of the target or false on failure. # Return the name of the target or false on failure.
def standard_build(short_cmd_string, target, command, sources, user_deps, env, cache) def standard_build(short_cmd_string, target, command, sources, env, cache)
unless cache.up_to_date?(target, command, sources, user_deps) unless cache.up_to_date?(target, command, sources, env)
cache.mkdir_p(File.dirname(target)) cache.mkdir_p(File.dirname(target))
FileUtils.rm_f(target) FileUtils.rm_f(target)
return false unless env.execute(short_cmd_string, command) return false unless env.execute(short_cmd_string, command)
cache.register_build(target, command, sources, user_deps) cache.register_build(target, command, sources, env)
end end
target target
end end

View File

@ -12,7 +12,7 @@ module Rscons
} }
end end
def run(target, sources, user_deps, cache, env, vars) def run(target, sources, cache, env, vars)
# build sources to linkable objects # build sources to linkable objects
objects = env.build_sources(sources, [env['OBJSUFFIX'], env['LIBSUFFIX']].flatten, cache, vars) objects = env.build_sources(sources, [env['OBJSUFFIX'], env['LIBSUFFIX']].flatten, cache, vars)
if objects if objects
@ -21,7 +21,7 @@ module Rscons
'_SOURCES' => objects, '_SOURCES' => objects,
}) })
command = env.build_command(env['ARCMD'], vars) command = env.build_command(env['ARCMD'], vars)
standard_build("AR #{target}", target, command, objects, user_deps, env, cache) standard_build("AR #{target}", target, command, objects, env, cache)
end end
end end
end end

View File

@ -50,7 +50,7 @@ module Rscons
end end
end end
def run(target, sources, user_deps, cache, env, vars) def run(target, sources, cache, env, vars)
vars = vars.merge({ vars = vars.merge({
'_TARGET' => target, '_TARGET' => target,
'_SOURCES' => sources, '_SOURCES' => sources,
@ -62,7 +62,7 @@ module Rscons
v.nil? and raise "Error: unknown input file type: #{sources.first.inspect}" v.nil? and raise "Error: unknown input file type: #{sources.first.inspect}"
end.first end.first
command = env.build_command(env["#{com_prefix}CMD"], vars) command = env.build_command(env["#{com_prefix}CMD"], vars)
unless cache.up_to_date?(target, command, sources, user_deps) unless cache.up_to_date?(target, command, sources, env)
cache.mkdir_p(File.dirname(target)) cache.mkdir_p(File.dirname(target))
FileUtils.rm_f(target) FileUtils.rm_f(target)
return false unless env.execute("#{com_prefix} #{target}", command) return false unless env.execute("#{com_prefix} #{target}", command)
@ -71,7 +71,7 @@ module Rscons
deps += Environment.parse_makefile_deps(vars['_DEPFILE'], target) deps += Environment.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, user_deps) cache.register_build(target, command, deps.uniq, env)
end end
target target
end end

View File

@ -14,7 +14,7 @@ module Rscons
} }
end end
def run(target, sources, user_deps, cache, env, vars) def run(target, sources, cache, env, vars)
# build sources to linkable objects # build sources to linkable objects
objects = env.build_sources(sources, [env['OBJSUFFIX'], env['LIBSUFFIX']].flatten, cache, vars) objects = env.build_sources(sources, [env['OBJSUFFIX'], env['LIBSUFFIX']].flatten, cache, vars)
return false unless objects return false unless objects
@ -33,7 +33,7 @@ module Rscons
'LD' => ld, 'LD' => ld,
}) })
command = env.build_command(env['LDCMD'], vars) command = env.build_command(env['LDCMD'], vars)
standard_build("LD #{target}", target, command, objects, user_deps, env, cache) standard_build("LD #{target}", target, command, objects, env, cache)
end end
end end
end end

View File

@ -89,7 +89,7 @@ module Rscons
# @param target [String] The name of the target file. # @param target [String] The name of the target file.
# @param command [Array] The command used to build the target. # @param command [Array] The command used to build the target.
# @param deps [Array] List of the target's dependency files. # @param deps [Array] List of the target's dependency files.
# @param user_deps [Array] List of user-specified extra dependencies. # @param env [Environment] The Rscons::Environment.
# @param options [Hash] Optional options. Can contain the following keys: # @param options [Hash] Optional options. Can contain the following keys:
# :strict_deps:: # :strict_deps::
# Only consider a target up to date if its list of dependencies is # Only consider a target up to date if its list of dependencies is
@ -104,7 +104,7 @@ module Rscons
# exactly equal to those cached # exactly equal to those cached
# - each cached dependency file's current checksum matches the checksum # - each cached dependency file's current checksum matches the checksum
# stored in the cache file # stored in the cache file
def up_to_date?(target, command, deps, user_deps, options = {}) def up_to_date?(target, command, deps, env, 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)
@ -117,20 +117,24 @@ module Rscons
# 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
cached_deps = @cache[:targets][target][:deps].map { |dc| dc[:fname] } cached_deps = @cache[:targets][target][:deps] or []
cached_deps_fnames = cached_deps.map { |dc| dc[:fname] }
if options[:strict_deps] if options[:strict_deps]
# depedencies passed in must exactly equal those in the cache # depedencies passed in must exactly equal those in the cache
return false unless deps == cached_deps return false unless deps == cached_deps_fnames
else else
# all dependencies passed in must exist in cache (but cache may have more) # all dependencies passed in must exist in cache (but cache may have more)
return false unless (Set.new(deps) - Set.new(cached_deps)).empty? return false unless (Set.new(deps) - Set.new(cached_deps_fnames)).empty?
end end
# set of user dependencies must match # set of user dependencies must match
return false unless user_deps == @cache[:targets][target][:user_deps].map { |dc| dc[:fname] } user_deps = env.get_user_deps(target) || []
cached_user_deps = @cache[:targets][target][:user_deps] or []
cached_user_deps_fnames = cached_user_deps.map { |dc| dc[:fname] }
return false unless user_deps == cached_user_deps_fnames
# all cached dependencies must have their checksums match # all cached dependencies must have their checksums match
(@cache[:targets][target][:deps] + @cache[:targets][target][:user_deps]).each do |dep_cache| (cached_deps + cached_user_deps).each do |dep_cache|
return false unless dep_cache[:checksum] == lookup_checksum(dep_cache[:fname]) return false unless dep_cache[:checksum] == lookup_checksum(dep_cache[:fname])
end end
@ -141,8 +145,8 @@ module Rscons
# @param target [String] The name of the target. # @param target [String] The name of the target.
# @param command [Array] The command used to build the target. # @param command [Array] The command used to build the target.
# @param deps [Array] List of dependencies for the target. # @param deps [Array] List of dependencies for the target.
# @param user_deps [Array] List of user-specified extra dependencies. # @param env [Environment] The Rscons::Environment.
def register_build(target, command, deps, user_deps) def register_build(target, command, deps, env)
@cache[:targets][target.encode(__ENCODING__)] = { @cache[:targets][target.encode(__ENCODING__)] = {
command: command, command: command,
checksum: calculate_checksum(target), checksum: calculate_checksum(target),
@ -152,7 +156,7 @@ module Rscons
checksum: lookup_checksum(dep), checksum: lookup_checksum(dep),
} }
end, end,
user_deps: user_deps.map do |dep| user_deps: (env.get_user_deps(target) || []).map do |dep|
{ {
fname: dep.encode(__ENCODING__), fname: dep.encode(__ENCODING__),
checksum: lookup_checksum(dep), checksum: lookup_checksum(dep),

View File

@ -151,7 +151,6 @@ module Rscons
result = run_builder(@targets[target][:builder], result = run_builder(@targets[target][:builder],
target, target,
@targets[target][:source], @targets[target][:source],
@user_deps[target] || [],
cache, cache,
@targets[target][:vars] || {}) @targets[target][:vars] || {})
unless result unless result
@ -232,6 +231,12 @@ module Rscons
@user_deps[target] = (@user_deps[target] + user_deps).uniq @user_deps[target] = (@user_deps[target] + user_deps).uniq
end end
# Return the list of user dependencies for a given target, or +nil+ for
# none.
def get_user_deps(target)
@user_deps[target]
end
# Build a list of source files into files containing one of the suffixes # Build a list of source files into files containing one of the suffixes
# given by suffixes. # given by suffixes.
# This method is used internally by RScons builders. # This method is used internally by RScons builders.
@ -250,7 +255,7 @@ module Rscons
converted_fname = get_build_fname(source, suffix) converted_fname = get_build_fname(source, suffix)
builder = @builders.values.find { |b| b.produces?(converted_fname, source, self) } builder = @builders.values.find { |b| b.produces?(converted_fname, source, self) }
if builder if builder
converted = run_builder(builder, converted_fname, [source], [], cache, vars) converted = run_builder(builder, converted_fname, [source], cache, vars)
return nil unless converted return nil unless converted
break break
end end
@ -267,19 +272,18 @@ module Rscons
# @param cache [Cache] The Cache. # @param cache [Cache] The Cache.
# @param vars [Hash] Extra variables to pass to the builder. # @param vars [Hash] Extra variables to pass to the builder.
# Return the result of the builder's run() method. # Return the result of the builder's run() method.
def run_builder(builder, target, sources, user_deps, cache, vars) def run_builder(builder, target, sources, cache, vars)
vars = @varset.merge(vars) vars = @varset.merge(vars)
@build_hooks.each do |build_hook_block| @build_hooks.each do |build_hook_block|
build_operation = { build_operation = {
builder: builder, builder: builder,
target: target, target: target,
sources: sources, sources: sources,
user_deps: user_deps,
vars: vars, vars: vars,
} }
build_hook_block.call(build_operation) build_hook_block.call(build_operation)
end end
builder.run(target, sources, user_deps, cache, self, vars) builder.run(target, sources, cache, self, vars)
end end
# Parse dependencies for a given target from a Makefile. # Parse dependencies for a given target from a Makefile.

View File

@ -38,14 +38,19 @@ module Rscons
end end
describe "#up_to_date?" do describe "#up_to_date?" do
empty_env = "env"
before do
empty_env.stub(:get_user_deps) { nil }
end
it "returns false when target file does not exist" do it "returns false when target file does not exist" do
File.should_receive(:exists?).with("target").and_return(false) File.should_receive(:exists?).with("target").and_return(false)
build_from({}).up_to_date?("target", "command", [], []).should be_false build_from({}).up_to_date?("target", "command", [], empty_env).should be_false
end end
it "returns false when target is not registered in the cache" do it "returns false when target is not registered in the cache" do
File.should_receive(:exists?).with("target").and_return(true) File.should_receive(:exists?).with("target").and_return(true)
build_from({}).up_to_date?("target", "command", [], []).should be_false build_from({}).up_to_date?("target", "command", [], empty_env).should be_false
end end
it "returns false when the target's checksum does not match" do it "returns false when the target's checksum does not match" do
@ -53,7 +58,7 @@ module Rscons
cache = build_from(_cache) cache = build_from(_cache)
File.should_receive(:exists?).with("target").and_return(true) File.should_receive(:exists?).with("target").and_return(true)
cache.should_receive(:calculate_checksum).with("target").and_return("def") cache.should_receive(:calculate_checksum).with("target").and_return("def")
cache.up_to_date?("target", "command", [], []).should be_false cache.up_to_date?("target", "command", [], empty_env).should be_false
end end
it "returns false when the build command has changed" do it "returns false when the build command has changed" do
@ -61,7 +66,7 @@ module Rscons
cache = build_from(_cache) cache = build_from(_cache)
File.should_receive(:exists?).with("target").and_return(true) File.should_receive(:exists?).with("target").and_return(true)
cache.should_receive(:calculate_checksum).with("target").and_return("abc") cache.should_receive(:calculate_checksum).with("target").and_return("abc")
cache.up_to_date?("target", "command", [], []).should be_false cache.up_to_date?("target", "command", [], empty_env).should be_false
end end
it "returns false when there is a new dependency" do it "returns false when there is a new dependency" do
@ -71,7 +76,7 @@ module Rscons
cache = build_from(_cache) cache = build_from(_cache)
File.should_receive(:exists?).with("target").and_return(true) File.should_receive(:exists?).with("target").and_return(true)
cache.should_receive(:calculate_checksum).with("target").and_return("abc") cache.should_receive(:calculate_checksum).with("target").and_return("abc")
cache.up_to_date?("target", "command", ["dep.1", "dep.2"], []).should be_false cache.up_to_date?("target", "command", ["dep.1", "dep.2"], empty_env).should be_false
end end
it "returns false when a dependency's checksum has changed" do it "returns false when a dependency's checksum has changed" do
@ -89,7 +94,7 @@ module Rscons
cache.should_receive(:calculate_checksum).with("target").and_return("abc") cache.should_receive(:calculate_checksum).with("target").and_return("abc")
cache.should_receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk") cache.should_receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk")
cache.should_receive(:calculate_checksum).with("dep.2").and_return("dep.2.changed") cache.should_receive(:calculate_checksum).with("dep.2").and_return("dep.2.changed")
cache.up_to_date?("target", "command", ["dep.1", "dep.2"], []).should be_false cache.up_to_date?("target", "command", ["dep.1", "dep.2"], empty_env).should be_false
end end
it "returns false with strict_deps=true when cache has an extra dependency" do it "returns false with strict_deps=true when cache has an extra dependency" do
@ -105,7 +110,7 @@ module Rscons
cache = build_from(_cache) cache = build_from(_cache)
File.should_receive(:exists?).with("target").and_return(true) File.should_receive(:exists?).with("target").and_return(true)
cache.should_receive(:calculate_checksum).with("target").and_return("abc") cache.should_receive(:calculate_checksum).with("target").and_return("abc")
cache.up_to_date?("target", "command", ["dep.1", "dep.2"], [], strict_deps: true).should be_false cache.up_to_date?("target", "command", ["dep.1", "dep.2"], empty_env, strict_deps: true).should be_false
end end
it "returns false when there is a new user dependency" do it "returns false when there is a new user dependency" do
@ -114,9 +119,11 @@ module Rscons
deps: [{fname: "dep.1"}], deps: [{fname: "dep.1"}],
user_deps: []}}} user_deps: []}}}
cache = build_from(_cache) cache = build_from(_cache)
env = "env"
env.should_receive(:get_user_deps).with("target").and_return(["file.ld"])
File.should_receive(:exists?).with("target").and_return(true) File.should_receive(:exists?).with("target").and_return(true)
cache.should_receive(:calculate_checksum).with("target").and_return("abc") cache.should_receive(:calculate_checksum).with("target").and_return("abc")
cache.up_to_date?("target", "command", ["dep.1"], ["file.ld"]).should be_false cache.up_to_date?("target", "command", ["dep.1"], env).should be_false
end end
it "returns false when a user dependency checksum has changed" do it "returns false when a user dependency checksum has changed" do
@ -131,13 +138,15 @@ module Rscons
user_deps: [{fname: "user.dep", user_deps: [{fname: "user.dep",
checksum: "user.dep.chk"}]}}} checksum: "user.dep.chk"}]}}}
cache = build_from(_cache) cache = build_from(_cache)
env = "env"
env.should_receive(:get_user_deps).with("target").and_return(["user.dep"])
File.should_receive(:exists?).with("target").and_return(true) File.should_receive(:exists?).with("target").and_return(true)
cache.should_receive(:calculate_checksum).with("target").and_return("abc") cache.should_receive(:calculate_checksum).with("target").and_return("abc")
cache.should_receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk") cache.should_receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk")
cache.should_receive(:calculate_checksum).with("dep.2").and_return("dep.2.chk") cache.should_receive(:calculate_checksum).with("dep.2").and_return("dep.2.chk")
cache.should_receive(:calculate_checksum).with("extra.dep").and_return("extra.dep.chk") cache.should_receive(:calculate_checksum).with("extra.dep").and_return("extra.dep.chk")
cache.should_receive(:calculate_checksum).with("user.dep").and_return("INCORRECT") cache.should_receive(:calculate_checksum).with("user.dep").and_return("INCORRECT")
cache.up_to_date?("target", "command", ["dep.1", "dep.2"], ["user.dep"]).should be_false cache.up_to_date?("target", "command", ["dep.1", "dep.2"], env).should be_false
end end
it "returns true when no condition for false is met" do it "returns true when no condition for false is met" do
@ -156,7 +165,7 @@ module Rscons
cache.should_receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk") cache.should_receive(:calculate_checksum).with("dep.1").and_return("dep.1.chk")
cache.should_receive(:calculate_checksum).with("dep.2").and_return("dep.2.chk") cache.should_receive(:calculate_checksum).with("dep.2").and_return("dep.2.chk")
cache.should_receive(:calculate_checksum).with("extra.dep").and_return("extra.dep.chk") cache.should_receive(:calculate_checksum).with("extra.dep").and_return("extra.dep.chk")
cache.up_to_date?("target", "command", ["dep.1", "dep.2"], []).should be_true cache.up_to_date?("target", "command", ["dep.1", "dep.2"], empty_env).should be_true
end end
end end
@ -164,11 +173,13 @@ module Rscons
it "stores the given information in the cache" do it "stores the given information in the cache" do
_cache = {} _cache = {}
cache = build_from(_cache) cache = build_from(_cache)
env = "env"
env.should_receive(:get_user_deps).with("the target").and_return(["user.dep"])
cache.should_receive(:calculate_checksum).with("the target").and_return("the checksum") cache.should_receive(:calculate_checksum).with("the target").and_return("the checksum")
cache.should_receive(:calculate_checksum).with("dep 1").and_return("dep 1 checksum") cache.should_receive(:calculate_checksum).with("dep 1").and_return("dep 1 checksum")
cache.should_receive(:calculate_checksum).with("dep 2").and_return("dep 2 checksum") cache.should_receive(:calculate_checksum).with("dep 2").and_return("dep 2 checksum")
cache.should_receive(:calculate_checksum).with("user.dep").and_return("user.dep checksum") cache.should_receive(:calculate_checksum).with("user.dep").and_return("user.dep checksum")
cache.register_build("the target", "the command", ["dep 1", "dep 2"], ["user.dep"]) cache.register_build("the target", "the command", ["dep 1", "dep 2"], env)
cached_target = cache.instance_variable_get(:@cache)[:targets]["the target"] cached_target = cache.instance_variable_get(:@cache)[:targets]["the target"]
cached_target.should_not be_nil cached_target.should_not be_nil
cached_target[:command].should == "the command" cached_target[:command].should == "the command"

View File

@ -141,7 +141,7 @@ module Rscons
cache = "cache" cache = "cache"
Cache.should_receive(:new).and_return(cache) Cache.should_receive(:new).and_return(cache)
env.should_receive(:run_builder).with(anything, "a.out", ["main.c"], [], cache, {}).and_return(true) env.should_receive(:run_builder).with(anything, "a.out", ["main.c"], cache, {}).and_return(true)
cache.should_receive(:write) cache.should_receive(:write)
env.process env.process
@ -154,8 +154,8 @@ module Rscons
cache = "cache" cache = "cache"
Cache.should_receive(:new).and_return(cache) Cache.should_receive(:new).and_return(cache)
env.should_receive(:run_builder).with(anything, "main.o", ["other.cc"], [], cache, {}).and_return("main.o") env.should_receive(:run_builder).with(anything, "main.o", ["other.cc"], cache, {}).and_return("main.o")
env.should_receive(:run_builder).with(anything, "a.out", ["main.o"], [], cache, {}).and_return("a.out") env.should_receive(:run_builder).with(anything, "a.out", ["main.o"], cache, {}).and_return("a.out")
cache.should_receive(:write) cache.should_receive(:write)
env.process env.process
@ -168,7 +168,7 @@ module Rscons
cache = "cache" cache = "cache"
Cache.should_receive(:new).and_return(cache) Cache.should_receive(:new).and_return(cache)
env.should_receive(:run_builder).with(anything, "main.o", ["other.cc"], [], cache, {}).and_return(false) env.should_receive(:run_builder).with(anything, "main.o", ["other.cc"], cache, {}).and_return(false)
cache.should_receive(:write) cache.should_receive(:write)
expect { env.process }.to raise_error BuildError, /Failed.to.build.main.o/ expect { env.process }.to raise_error BuildError, /Failed.to.build.main.o/
@ -282,8 +282,8 @@ module Rscons
cache = "cache" cache = "cache"
env = Environment.new env = Environment.new
env.add_builder(ABuilder.new) env.add_builder(ABuilder.new)
env.builders["Object"].should_receive(:run).with("mod.o", ["mod.c"], [], cache, env, anything).and_return("mod.o") env.builders["Object"].should_receive(:run).with("mod.o", ["mod.c"], cache, env, anything).and_return("mod.o")
env.builders["ABuilder"].should_receive(:run).with("mod2.ab_out", ["mod2.ab_in"], [], cache, env, anything).and_return("mod2.ab_out") env.builders["ABuilder"].should_receive(:run).with("mod2.ab_out", ["mod2.ab_in"], cache, env, anything).and_return("mod2.ab_out")
env.build_sources(["precompiled.o", "mod.c", "mod2.ab_in"], [".o", ".ab_out"], cache, {}).should == ["precompiled.o", "mod.o", "mod2.ab_out"] env.build_sources(["precompiled.o", "mod.c", "mod2.ab_in"], [".o", ".ab_out"], cache, {}).should == ["precompiled.o", "mod.o", "mod2.ab_out"]
end end
end end
@ -296,14 +296,14 @@ module Rscons
build_op[:vars]["CFLAGS"] += ["-O3", "-DSPECIAL"] build_op[:vars]["CFLAGS"] += ["-O3", "-DSPECIAL"]
end end
end end
env.builders["Object"].stub(:run) do |target, sources, user_deps, cache, env, vars| env.builders["Object"].stub(:run) do |target, sources, cache, env, vars|
vars["CFLAGS"].should == [] vars["CFLAGS"].should == []
end end
env.run_builder(env.builders["Object"], "build/normal/module.o", ["src/normal/module.c"], [], "cache", {}) env.run_builder(env.builders["Object"], "build/normal/module.o", ["src/normal/module.c"], "cache", {})
env.builders["Object"].stub(:run) do |target, sources, user_deps, cache, env, vars| env.builders["Object"].stub(:run) do |target, sources, cache, env, vars|
vars["CFLAGS"].should == ["-O3", "-DSPECIAL"] vars["CFLAGS"].should == ["-O3", "-DSPECIAL"]
end end
env.run_builder(env.builders["Object"], "build/special/module.o", ["src/special/module.c"], [], "cache", {}) env.run_builder(env.builders["Object"], "build/special/module.o", ["src/special/module.c"], "cache", {})
end end
end end