fixing build signatures

I have a lot of functional tests for my build process. Recently I changed the program name on one of the intermediate steps. As result, SCons
* thinks the build signatures are updated, and
* wants to rebuild starting from that step instead of doing the expected rebuilds.
Therefore, I have to update the most part of the tests. But it’s near to impossible to update manually.

I decided to update build signatures automatically.

To get the list of all the defined targets, I use the variable “env.ans” where env is an Environment object.

Then, for each the target, I traverse the tree of dependencies.

While traversing, the following nodes are ignored:

* those which have no build information (either source files, either defined, but not used),
* the default target (because executing the last step to get the default target is the essence of many tests).

To make a node up-to-date:

* code reads the data from .sconsign using get_stored_info(),
* new build signatures are calculated using calc_bsig(),
* .sconsign build information (bsig, bact and bactsig) is updated using set_entry().

The full code:

#
# Walk over the dependencies tree
#
def walk_dep_tree(node, func, tabs=''):
  for ch in node.children():
    walk_dep_tree(ch, func, tabs + ' ')
  #
  # Apply the function, ignoring:
  # the nodes which were not built,
  # default targets
  #
  if not node.is_derived():
    return
  old = node.get_stored_info()
  if None == old:
    return
  if None == getattr(old, 'bactsig', None):
    return
  if str(node) in map(str, DEFAULT_TARGETS):
    return
  func(node, tabs)

def fix_build_signatures(target, source, env):
  def print_node(node, tabs):
    print tabs + str(node) 
  def update_bsig(node, tabs):
    #print tabs + str(node)
    #
    # Check if the build information is changed
    #
    old = node.get_stored_info()
    node.calc_bsig()
    new  = node.binfo
    is_changed = (old.bactsig != new.bactsig) or (old.bact != new.bact) or (old.bsig != new.bsig)
    if not is_changed:
      return
    #
    # Update the build information
    #
    print 'Updating the build signature for ' + str(node)
    old.bactsig = node.binfo.bactsig
    old.bact    = node.binfo.bact
    old.bsig    = node.binfo.bsig
    node.dir.sconsign().set_entry(node.name, old)
  #
  # Update the signatures of all the targets
  #
  #for k in env.ans.keys():
  #  walk_dep_tree(env.ans[k], print_node)
  for k in env.ans.keys():
    walk_dep_tree(env.ans[k], update_bsig)

node = Local('fix-build-signatures')
env['BUILDERS']['fixbs'] = Builder(action = fix_build_signatures)
env.fixbs(node, None)
env.Alias('fixbs', node)

Usage:

scons fixbs

15 September 2006, update

Starting with SCons 0.96.92, the code doesn’t work due to the signature refactoring of SCons.

Leave a Reply