process jobs from the JobSet

This commit is contained in:
Josh Holtrop 2017-02-16 18:44:20 -05:00
parent e1d8dfbab6
commit 3601359c08
4 changed files with 61 additions and 88 deletions

View File

@ -38,7 +38,7 @@ module Rscons
# when the block returns, the {#process} method is automatically called.
def initialize(options = {})
@varset = VarSet.new
@targets = {}
@job_set = JobSet.new
@user_deps = {}
@builders = {}
@build_dirs = []
@ -280,48 +280,32 @@ module Rscons
#
# @return [void]
def process
while @targets.size > 0
expand_paths!
targets = @targets
@targets = {}
cache = Cache.instance
cache.clear_checksum_cache!
targets_processed = Set.new
process_target = proc do |target|
unless targets_processed.include?(target)
targets_processed << target
targets[target].each do |target_params|
target_params[:sources].each do |src|
if targets.include?(src) and not targets_processed.include?(src)
process_target.call(src)
end
end
result = run_builder(target_params[:builder],
target,
target_params[:sources],
cache,
target_params[:vars] || {})
unless result
raise BuildError.new("Failed to build #{target}")
end
end
end
end
begin
targets.each_key do |target|
process_target.call(target)
while job = @job_set.get_next_job_to_run
expand_paths(job)
# TODO: have Cache determine when checksums may be invalid based on
# file size and/or timestamp.
cache.clear_checksum_cache!
result = run_builder(job[:builder],
job[:target],
job[:sources],
cache,
job[:vars])
unless result
raise BuildError.new("Failed to build #{job[:target]}")
end
end
ensure
cache.write
end
end
end
# Clear all targets registered for the Environment.
#
# @return [void]
def clear_targets
@targets = {}
@job_set.clear!
end
# Expand a construction variable reference.
@ -389,7 +373,7 @@ module Rscons
sources = Array(sources)
builder = @builders[method.to_s]
build_target = builder.create_build_target(env: self, target: target, sources: sources)
add_target(build_target.to_s, builder, sources, vars, rest)
add_target(build_target.to_s, builder, sources, vars || {}, rest)
build_target
else
super
@ -402,17 +386,11 @@ module Rscons
# @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}.
# @param args [Object] Deprecated; unused.
#
# @return [void]
def add_target(target, builder, sources, vars, args)
@targets[target] ||= []
@targets[target] << {
builder: builder,
sources: sources,
vars: vars,
args: args,
}
@job_set.add_job(builder, target, sources, vars)
end
# Manually record a given target as depending on the specified files.
@ -676,26 +654,20 @@ module Rscons
private
# Expand target and source paths before invoking builders.
# Expand target and source paths of a job before invoking the builder.
#
# 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_list)|
target = expand_path(target) if @build_root
target = expand_varref(target)
result[target] = target_params_list.map do |target_params|
sources = target_params[:sources].map do |source|
def expand_paths(job)
job[:target] = expand_path(job[:target]) if @build_root
job[:target] = expand_varref(job[:target])
job[:sources] = job[:sources].map do |source|
source = expand_path(source) if @build_root
expand_varref(source)
end.flatten
target_params.merge(sources: sources)
end
result
end
end
# Parse dependencies for a given target from a Makefile.

View File

@ -20,7 +20,12 @@ module Rscons
# @param vars [Hash]
# Construction variable overrides.
def add_job(builder, target, sources, vars)
@jobs[target] = {
# We allow multiple jobs to be registered per target for cases like:
# env.Directory("dest")
# env.Install("dest", "bin")
# env.Install("dest", "share")
@jobs[target] ||= []
@jobs[target] << {
builder: builder,
target: target,
sources: sources,
@ -39,18 +44,27 @@ module Rscons
evaluated_targets = Set.new
attempt = lambda do |target|
evaluated_targets << target
@jobs[target][:sources].each do |src|
@jobs[target][0][:sources].each do |src|
if @jobs.include?(src) and not evaluated_targets.include?(src)
return attempt[src]
end
end
job = @jobs[target].merge(target: target)
job = @jobs[target][0].merge(target: target)
if @jobs[target].size > 1
@jobs[target].slice!(0)
else
@jobs.delete(target)
end
return job
end
attempt[@jobs.first.first]
end
end
# Remove all jobs from the JobSet.
def clear!
@jobs.clear
end
end
end

View File

@ -966,4 +966,15 @@ EOF
end
end
context "Environment#clear_targets" do
it "clears registered targets" do
test_dir('header')
env = Rscons::Environment.new do |env|
env.Program('header', Dir['*.c'])
env.clear_targets
end
expect(lines).to eq []
end
end
end

View File

@ -169,7 +169,7 @@ module Rscons
cache = "cache"
expect(Cache).to receive(:instance).and_return(cache)
expect(cache).to receive(:clear_checksum_cache!)
allow(cache).to receive(:clear_checksum_cache!)
expect(env).to receive(:run_builder).with(anything, "a.out", ["main.c"], cache, {}).and_return(true)
expect(cache).to receive(:write)
@ -183,7 +183,7 @@ module Rscons
cache = "cache"
expect(Cache).to receive(:instance).and_return(cache)
expect(cache).to receive(:clear_checksum_cache!)
allow(cache).to receive(:clear_checksum_cache!)
expect(env).to receive(:run_builder).with(anything, "main.o", ["other.cc"], cache, {}).and_return("main.o")
expect(env).to receive(:run_builder).with(anything, "a.out", ["main.o"], cache, {}).and_return("a.out")
expect(cache).to receive(:write)
@ -198,7 +198,7 @@ module Rscons
cache = "cache"
expect(Cache).to receive(:instance).and_return(cache)
expect(cache).to receive(:clear_checksum_cache!)
allow(cache).to receive(:clear_checksum_cache!)
expect(env).to receive(:run_builder).with(anything, "main.o", ["other.cc"], cache, {}).and_return(false)
expect(cache).to receive(:write)
@ -221,18 +221,6 @@ module Rscons
end
end
describe "#clear_targets" do
it "resets @targets to an empty hash" do
env = Environment.new
env.Program("a.out", "main.o")
expect(env.instance_variable_get(:@targets).keys).to eq(["a.out"])
env.clear_targets
expect(env.instance_variable_get(:@targets).keys).to eq([])
end
end
describe "#build_command" do
it "returns a command based on the variables in the Environment" do
env = Environment.new
@ -299,18 +287,6 @@ module Rscons
expect {env.foobar}.to raise_error /undefined method .foobar./
end
it "records the target when the target method is a known builder" do
env = Environment.new
expect(env.instance_variable_get(:@targets)).to eq({})
env.Object("target.o", ["src1.c", "src2.c"], var: "val")
target = env.instance_variable_get(:@targets)["target.o"]
expect(target).to_not be_nil
expect(target[0][:builder].is_a?(Builder)).to be_truthy
expect(target[0][:sources]).to eq ["src1.c", "src2.c"]
expect(target[0][:vars]).to eq({var: "val"})
expect(target[0][:args]).to eq []
end
it "raises an error when vars is not a Hash" do
env = Environment.new
expect { env.Program("a.out", "main.c", "other") }.to raise_error /Unexpected construction variable set/