implement Cache to store info about target dependencies and checksums across invocations

This commit is contained in:
Josh Holtrop 2013-07-14 21:51:31 -04:00
parent 9c69a45f77
commit 0bf71ae4d1
4 changed files with 81 additions and 23 deletions

View File

@ -17,19 +17,20 @@ module Rscons
end end
def run(target, sources, cache) def run(target, sources, cache)
unless cache.up_to_date?(target, sources) vars = {
vars = { 'TARGET' => target,
'TARGET' => target, 'SOURCES' => sources,
'SOURCES' => sources, 'DEPFILE' => target.set_suffix('.mf'),
'DEPFILE' => target.set_suffix('.mf'), }
} command = @env.build_command(@env['CCCOM'], vars)
@env.execute("CC #{target}", @env['CCCOM'], vars) unless cache.up_to_date?(target, command, sources)
return false unless @env.execute("CC #{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, deps.uniq) cache.register_build(target, command, deps.uniq)
end end
target target
end end

View File

@ -24,13 +24,15 @@ module Rscons
builder.run(o_file, [source], cache) builder.run(o_file, [source], cache)
end end
end end
unless cache.up_to_date?(target, sources) vars = {
vars = { 'TARGET' => target,
'TARGET' => target, 'SOURCES' => sources,
'SOURCES' => sources, 'LD' => @env['LD'] || @env['CC'], # TODO: figure out whether to use CC or CXX
'LD' => @env['LD'] || @env['CC'], # TODO: figure out whether to use CC or CXX }
} command = @env.build_command(@env['LDCOM'], vars)
@env.execute("LD #{target}", @env['LDCOM'], vars) unless cache.up_to_date?(target, command, sources)
return false unless @env.execute("LD #{target}", command)
cache.register_build(target, command, sources)
end end
target target
end end

View File

@ -1,8 +1,36 @@
require 'yaml' require 'yaml'
require 'fileutils' require 'fileutils'
require 'digest/md5' require 'digest/md5'
require 'set'
module Rscons module Rscons
# Example cache:
# {
# 'program' => {
# 'checksum' => 'A1B2C3D4',
# 'command' => ['gcc', '-o', 'program', 'program.o'],
# 'deps' => [
# {
# 'fname' => 'program.o',
# 'checksum' => '87654321',
# }
# ],
# }
# 'program.o' => {
# 'checksum' => '87654321',
# 'command' => ['gcc', '-c', '-o', 'program.o', 'program.c'],
# 'deps' => [
# {
# 'fname' => 'program.c',
# 'checksum' => '456789ABC',
# },
# {
# 'fname' => 'program.h',
# 'checksum' => '7979764643',
# }
# ]
# }
# }
class Cache class Cache
# Constants # Constants
CACHE_FILE = '.rsconscache' CACHE_FILE = '.rsconscache'
@ -15,6 +43,7 @@ module Rscons
# Instance Methods # Instance Methods
def initialize def initialize
@cache = YAML.load(File.read(CACHE_FILE)) rescue {} @cache = YAML.load(File.read(CACHE_FILE)) rescue {}
@lookup_checksums = {}
end end
def write def write
@ -23,20 +52,43 @@ module Rscons
end end
end end
def up_to_date?(file, deps = nil) def up_to_date?(target, command, deps)
# TODO # target file must exist on disk
false return false unless File.exists?(target)
# target must be registered in the cache
return false unless @cache.has_key?(target)
# command line used to build target must be identical
return false unless @cache[target][:command] == command
# all dependencies passed in must exist in cache (but cache may have more)
return false unless (Set.new(deps) - Set.new(@cache[target][:deps])).empty?
# all cached dependencies must have their checksums match
@cache[target][:deps].map do |dep_cache|
dep_cache[:checksum] == lookup_checksum(dep_cache[:fname])
end.all?
end end
def register_build(target, deps) def register_build(target, command, deps)
# TODO @cache[target] = {
command: command,
checksum: calculate_checksum(target),
deps: deps.map do |dep|
{
fname: dep,
checksum: lookup_checksum(dep),
}
end
}
end end
# Private Instance Methods # Private Instance Methods
private private
def lookup_checksum(file)
@lookup_checksums[file] || calculate_checksum(file)
end
def calculate_checksum(file) def calculate_checksum(file)
Digest::MD5.hexdigest(File.read(file)).encode(__ENCODING__) @lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file)).encode(__ENCODING__) rescue ''
end end
end end
end end

View File

@ -74,8 +74,11 @@ module Rscons
cache.write cache.write
end end
def execute(short_desc, command, extra_vars) def build_command(command_template, extra_vars)
command = @varset.merge(extra_vars).expand_varref(command) @varset.merge(extra_vars).expand_varref(command_template)
end
def execute(short_desc, command)
if @varset[:echo] == :command if @varset[:echo] == :command
puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ') puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
elsif @varset[:echo] == :short elsif @varset[:echo] == :short