mirror of
https://gitlab.com/ita1024/waf.git
synced 2024-11-29 13:30:32 +01:00
Split fast_partial data storage from the main pickle file
This commit is contained in:
parent
ee3f706bb7
commit
6ed9a9231f
@ -30,12 +30,36 @@ NEEDED = 2
|
|||||||
|
|
||||||
SKIPPABLE = ['cshlib', 'cxxshlib', 'cstlib', 'cxxstlib', 'cprogram', 'cxxprogram']
|
SKIPPABLE = ['cshlib', 'cxxshlib', 'cstlib', 'cxxstlib', 'cprogram', 'cxxprogram']
|
||||||
|
|
||||||
|
TSTAMP_DB = '.wafpickle_tstamp_db_file'
|
||||||
|
|
||||||
class bld(Build.BuildContext):
|
class bld(Build.BuildContext):
|
||||||
def store(self):
|
def is_dirty(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def store_tstamps(self):
|
||||||
# For each task generator, record all files involved in task objects
|
# For each task generator, record all files involved in task objects
|
||||||
# optimization: done only if there was something built
|
# optimization: done only if there was something built
|
||||||
|
do_store = False
|
||||||
|
try:
|
||||||
|
f_deps = self.f_deps
|
||||||
|
except AttributeError:
|
||||||
|
f_deps = self.f_deps = {}
|
||||||
|
|
||||||
for g in self.groups:
|
for g in self.groups:
|
||||||
for tg in g:
|
for tg in g:
|
||||||
|
try:
|
||||||
|
staleness = tg.staleness
|
||||||
|
except AttributeError:
|
||||||
|
staleness = DIRTY
|
||||||
|
|
||||||
|
if staleness != DIRTY:
|
||||||
|
# DONE case: there was nothing built
|
||||||
|
# NEEDED case: the tg was brought in because of 'use' propagation
|
||||||
|
# but nothing really changed for them, there may be incomplete
|
||||||
|
# tasks (object files) and in this case it is best to let the next build
|
||||||
|
# figure out if an input/output file changed
|
||||||
|
continue
|
||||||
|
|
||||||
do_cache = False
|
do_cache = False
|
||||||
for tsk in tg.tasks:
|
for tsk in tg.tasks:
|
||||||
if tsk.hasrun == Task.SUCCESS:
|
if tsk.hasrun == Task.SUCCESS:
|
||||||
@ -44,21 +68,31 @@ class bld(Build.BuildContext):
|
|||||||
elif tsk.hasrun == Task.SKIPPED:
|
elif tsk.hasrun == Task.SKIPPED:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
# dependencies are incomplete, clear the cache
|
# one failed task, clear the cache for this tg
|
||||||
try:
|
try:
|
||||||
del self.raw_deps[(tg.path.abspath(), tg.idx)]
|
del f_deps[(tg.path.abspath(), tg.idx)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
else:
|
||||||
|
# just store the new state because there is a change
|
||||||
|
do_store = True
|
||||||
|
|
||||||
|
# skip the rest because there is no valid cache possible
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if not do_cache:
|
if not do_cache:
|
||||||
|
# all skipped, but is there anything in cache?
|
||||||
try:
|
try:
|
||||||
self.raw_deps[(tg.path.abspath(), tg.idx)]
|
f_deps[(tg.path.abspath(), tg.idx)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
# probably cleared because a wscript file changed
|
# probably cleared because a wscript file changed
|
||||||
|
# store it
|
||||||
do_cache = True
|
do_cache = True
|
||||||
|
|
||||||
if do_cache:
|
if do_cache:
|
||||||
|
# all tasks skipped but no cache
|
||||||
|
# or a successful task build
|
||||||
|
do_store = True
|
||||||
st = set()
|
st = set()
|
||||||
for tsk in tg.tasks:
|
for tsk in tg.tasks:
|
||||||
st.update(tsk.inputs)
|
st.update(tsk.inputs)
|
||||||
@ -67,13 +101,41 @@ class bld(Build.BuildContext):
|
|||||||
lst = [x.abspath() for x in tg.path.ant_glob('wscript*')]
|
lst = [x.abspath() for x in tg.path.ant_glob('wscript*')]
|
||||||
lst.extend(sorted(x.abspath() for x in st))
|
lst.extend(sorted(x.abspath() for x in st))
|
||||||
tss = [os.stat(x).st_mtime for x in lst]
|
tss = [os.stat(x).st_mtime for x in lst]
|
||||||
self.raw_deps[(tg.path.abspath(), tg.idx)] = (lst, tss)
|
f_deps[(tg.path.abspath(), tg.idx)] = (lst, tss)
|
||||||
|
|
||||||
return Build.BuildContext.store(self)
|
if do_store:
|
||||||
|
dbfn = os.path.join(self.variant_dir, TSTAMP_DB)
|
||||||
|
Logs.debug('rev_use: storing %s', dbfn)
|
||||||
|
dbfn_tmp = dbfn + '.tmp'
|
||||||
|
x = Build.cPickle.dumps(f_deps)
|
||||||
|
Utils.writef(dbfn_tmp, x, m='wb')
|
||||||
|
os.rename(dbfn_tmp, dbfn)
|
||||||
|
|
||||||
|
def store(self):
|
||||||
|
self.store_tstamps()
|
||||||
|
if self.producer.dirty:
|
||||||
|
Build.BuildContext.store(self)
|
||||||
|
|
||||||
def compute_needed_tgs(self):
|
def compute_needed_tgs(self):
|
||||||
# assume the 'use' keys are not modified during the build phase
|
# assume the 'use' keys are not modified during the build phase
|
||||||
|
|
||||||
|
dbfn = os.path.join(self.variant_dir, TSTAMP_DB)
|
||||||
|
Logs.debug('rev_use: Loading %s', dbfn)
|
||||||
|
try:
|
||||||
|
data = Utils.readf(dbfn, 'rb')
|
||||||
|
except (EnvironmentError, EOFError):
|
||||||
|
Logs.debug('rev_use: Could not load the build cache %s (missing)', dbfn)
|
||||||
|
self.f_deps = {}
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
self.f_deps = Build.cPickle.loads(data)
|
||||||
|
except Exception as e:
|
||||||
|
Logs.debug('rev_use: Could not pickle the build cache %s: %r', dbfn, e)
|
||||||
|
self.f_deps = {}
|
||||||
|
else:
|
||||||
|
Logs.debug('rev_use: Loaded %s', dbfn)
|
||||||
|
|
||||||
|
|
||||||
# 1. obtain task generators that contain rebuilds
|
# 1. obtain task generators that contain rebuilds
|
||||||
# 2. obtain the 'use' graph and its dual
|
# 2. obtain the 'use' graph and its dual
|
||||||
stales = set()
|
stales = set()
|
||||||
@ -179,9 +241,16 @@ def is_stale(self):
|
|||||||
Logs.debug('rev_use: must post %r because the configuration has changed', self.name)
|
Logs.debug('rev_use: must post %r because the configuration has changed', self.name)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# 3.a any tstamp data?
|
||||||
|
try:
|
||||||
|
f_deps = self.bld.f_deps
|
||||||
|
except AttributeError:
|
||||||
|
Logs.debug('rev_use: must post %r because there is no f_deps', self.name)
|
||||||
|
return True
|
||||||
|
|
||||||
# 4. check if this is the first build (no cache)
|
# 4. check if this is the first build (no cache)
|
||||||
try:
|
try:
|
||||||
lst, tss = self.bld.raw_deps[(self.path.abspath(), self.idx)]
|
lst, tss = f_deps[(self.path.abspath(), self.idx)]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
Logs.debug('rev_use: must post %r because there it has no cached data', self.name)
|
Logs.debug('rev_use: must post %r because there it has no cached data', self.name)
|
||||||
return True
|
return True
|
||||||
@ -205,7 +274,7 @@ def is_stale(self):
|
|||||||
try:
|
try:
|
||||||
ts = tstamp(x)
|
ts = tstamp(x)
|
||||||
except OSError:
|
except OSError:
|
||||||
del self.bld.raw_deps[(self.path.abspath(), self.idx)]
|
del f_deps[(self.path.abspath(), self.idx)]
|
||||||
Logs.debug('rev_use: must post %r because %r does not exist anymore', self.name, x)
|
Logs.debug('rev_use: must post %r because %r does not exist anymore', self.name, x)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
@ -219,6 +288,7 @@ def is_stale(self):
|
|||||||
@taskgen_method
|
@taskgen_method
|
||||||
def create_compiled_task(self, name, node):
|
def create_compiled_task(self, name, node):
|
||||||
# the purpose is to skip the creation of object files
|
# the purpose is to skip the creation of object files
|
||||||
|
# assumption: object-only targets are not skippable
|
||||||
if self.staleness == NEEDED:
|
if self.staleness == NEEDED:
|
||||||
# only libraries/programs can skip object files
|
# only libraries/programs can skip object files
|
||||||
for x in SKIPPABLE:
|
for x in SKIPPABLE:
|
||||||
@ -236,7 +306,6 @@ def create_compiled_task(self, name, node):
|
|||||||
@feature(*SKIPPABLE)
|
@feature(*SKIPPABLE)
|
||||||
@after_method('apply_link')
|
@after_method('apply_link')
|
||||||
def apply_link_after(self):
|
def apply_link_after(self):
|
||||||
# assumption: object-only targets are not skippable
|
|
||||||
# cprogram/cxxprogram might be unnecessary
|
# cprogram/cxxprogram might be unnecessary
|
||||||
if self.staleness != NEEDED:
|
if self.staleness != NEEDED:
|
||||||
return
|
return
|
||||||
|
Loading…
Reference in New Issue
Block a user