Do not rebuild targets when they are up to date
Store dependencies and file checksums in a cache file
This commit is contained in:
parent
8af27d7775
commit
119f3c9f0f
@ -1,6 +1,7 @@
|
|||||||
require "rscons/version"
|
require "rscons/version"
|
||||||
require "rscons/builder"
|
require "rscons/builder"
|
||||||
require "rscons/environment"
|
require "rscons/environment"
|
||||||
|
require "rscons/cache"
|
||||||
|
|
||||||
# default builders
|
# default builders
|
||||||
require "rscons/builders/cc"
|
require "rscons/builders/cc"
|
||||||
|
@ -17,14 +17,17 @@ module Rscons
|
|||||||
def run(env, target, source)
|
def run(env, target, source)
|
||||||
raise "String expected, not #{source.inspect}" unless source.is_a?(String)
|
raise "String expected, not #{source.inspect}" unless source.is_a?(String)
|
||||||
o_file = "#{env.stem(source)}#{env['OBJSUFFIX']}"
|
o_file = "#{env.stem(source)}#{env['OBJSUFFIX']}"
|
||||||
command = [
|
unless Cache.open.up_to_date?(target, [source])
|
||||||
env['CC'],
|
command = [
|
||||||
*env['CPPFLAGS'],
|
env['CC'],
|
||||||
*env['CFLAGS'],
|
*env['CPPFLAGS'],
|
||||||
'-o', o_file,
|
*env['CFLAGS'],
|
||||||
source
|
'-o', o_file,
|
||||||
]
|
source
|
||||||
env.execute("CC #{o_file}", command)
|
]
|
||||||
|
env.execute("CC #{o_file}", command)
|
||||||
|
Cache.open.register_build(target, [source])
|
||||||
|
end
|
||||||
o_file
|
o_file
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -11,6 +11,7 @@ module Rscons
|
|||||||
|
|
||||||
def run(env, target, sources)
|
def run(env, target, sources)
|
||||||
sources = [sources] if sources.is_a?(String)
|
sources = [sources] if sources.is_a?(String)
|
||||||
|
# convert sources to object file names
|
||||||
sources = sources.map do |source|
|
sources = sources.map do |source|
|
||||||
if source =~ /#{env['OBJSUFFIX']}$/ or source =~ /#{env['LIBSUFFIX']}$/
|
if source =~ /#{env['OBJSUFFIX']}$/ or source =~ /#{env['LIBSUFFIX']}$/
|
||||||
source
|
source
|
||||||
@ -24,15 +25,18 @@ module Rscons
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
command = [
|
unless Cache.open.up_to_date?(target, sources)
|
||||||
env['LD'] || env['CC'],
|
command = [
|
||||||
'-o', target,
|
env['LD'] || env['CC'],
|
||||||
*env['LDFLAGS'],
|
'-o', target,
|
||||||
*sources,
|
*env['LDFLAGS'],
|
||||||
*env['LIBPATHS'].map {|lp| "-L#{lp}"},
|
*sources,
|
||||||
*env['LIBS'].map {|lib| "-l#{lib}"}
|
*env['LIBPATHS'].map {|lp| "-L#{lp}"},
|
||||||
]
|
*env['LIBS'].map {|lib| "-l#{lib}"}
|
||||||
env.execute("LINK #{target}", command)
|
]
|
||||||
|
env.execute("LINK #{target}", command)
|
||||||
|
Cache.open.register_build(target, sources)
|
||||||
|
end
|
||||||
target
|
target
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
74
lib/rscons/cache.rb
Normal file
74
lib/rscons/cache.rb
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
require 'yaml'
|
||||||
|
require 'fileutils'
|
||||||
|
require 'digest/md5'
|
||||||
|
require 'set'
|
||||||
|
|
||||||
|
module Rscons
|
||||||
|
class Cache
|
||||||
|
CACHE_FILE = '.rscons'
|
||||||
|
|
||||||
|
private_class_method :new
|
||||||
|
def initialize
|
||||||
|
@cache = YAML.load(File.read(CACHE_FILE)) rescue {}
|
||||||
|
@lookup_checksums = {}
|
||||||
|
@stored_checksums = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.open
|
||||||
|
@@cache ||= new
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear
|
||||||
|
FileUtils.rm_f(CACHE_FILE)
|
||||||
|
initialize
|
||||||
|
end
|
||||||
|
|
||||||
|
def write
|
||||||
|
File.open(CACHE_FILE, 'w') do |fh|
|
||||||
|
fh.puts(YAML.dump(@cache))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def up_to_date?(file, deps = nil)
|
||||||
|
return false unless File.exists?(file)
|
||||||
|
stored_md5 = @cache[:checksums][file] rescue nil
|
||||||
|
return false unless stored_md5
|
||||||
|
return false unless lookup_checksum(file) == stored_md5
|
||||||
|
cached_deps = @cache[:deps][file] || [] rescue []
|
||||||
|
return false if deps and Set.new(cached_deps) != Set.new(deps)
|
||||||
|
cached_deps.map {|d| up_to_date?(d)}.all?
|
||||||
|
end
|
||||||
|
|
||||||
|
def register_build(target, deps)
|
||||||
|
@cache[:deps] ||= {}
|
||||||
|
@cache[:deps][target] = deps
|
||||||
|
store_checksum(target)
|
||||||
|
deps.each do |dep|
|
||||||
|
store_checksum(dep)
|
||||||
|
end
|
||||||
|
# it is unfortunate to write the file here since many file writes may
|
||||||
|
# occur before the final version, but I don't know where else to do so
|
||||||
|
write
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def lookup_checksum(file)
|
||||||
|
@lookup_checksums[file] ||= calculate_checksum(file)
|
||||||
|
end
|
||||||
|
|
||||||
|
def store_checksum(file)
|
||||||
|
cs = calculate_checksum(file)
|
||||||
|
if @stored_checksums[file] and @stored_checksums[file] != cs
|
||||||
|
$stderr.puts "Warning: file #{file.inspect} changed after previously used by builder"
|
||||||
|
end
|
||||||
|
@cache[:checksums] ||= {}
|
||||||
|
@cache[:checksums][file] = cs
|
||||||
|
@lookup_checksums[file] = cs
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_checksum(file)
|
||||||
|
Digest::MD5.hexdigest(File.read(file))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -17,6 +17,7 @@ describe Rscons do
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
$stdout.stub(:puts) { nil }
|
$stdout.stub(:puts) { nil }
|
||||||
|
Rscons::Cache.open.clear
|
||||||
end
|
end
|
||||||
|
|
||||||
###########################################################################
|
###########################################################################
|
||||||
@ -31,4 +32,14 @@ describe Rscons do
|
|||||||
`./simple`.should =~ /This is a simple C program/
|
`./simple`.should =~ /This is a simple C program/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'does not rebuild the program if no sources changed' do
|
||||||
|
$stdout.should_receive(:puts).once.with('gcc -c -o simple.o simple.c')
|
||||||
|
$stdout.should_receive(:puts).once.with('gcc -o simple simple.o')
|
||||||
|
setup_testdir(['simple.c']) do
|
||||||
|
env = Rscons::Environment.new
|
||||||
|
env.Program('simple', 'simple.c')
|
||||||
|
env.Program('simple', 'simple.c')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user