Please note:The SCons wiki is in read-only mode due to ongoing spam/DoS issues. Also, new account creation is currently disabled. We are looking into alternative wiki hosts.
Differences between revisions 1 and 2
Revision 1 as of 2014-07-18 01:58:01
Size: 2360
Editor: AlexBurton
Comment: Created NonDeterministicDependencies
Revision 2 as of 2014-07-18 02:05:18
Size: 2370
Editor: AlexBurton
Comment: python syntax highlight
Deletions are marked like this. Additions are marked like this.
Line 14: Line 14:
#!python

Non Deterministic Dependencies

This problem arises when a builder can create more than one target, and the number of targets cannot be known until that builder is executed. Other builders may be required to process each of those targets, and other builders may then be dependent on all of those results.

The solution is to have the non deterministic builder create a file listing it's targets, and have a dependant builder use a scanner to read that file to find the dependancies, process them and use them as sources.

The stand alone example below shows how to make such a dynamic builder so that scons can build the whole tree despite not knowing the number of processes when scons is invoked.

The example behaves correctly when intermediate files are deleted.

   1 def PartMakerFunc(target, source, env):
   2 #a builder that makes a result requiring a number of subsequent operations not known when scons is called
   3         targets = ["%d.out" % i for i in range(3)]
   4         open(target[0].get_path(),'w').write('\n'.join(targets))
   5 
   6 def DynamicFunc(target, source, env):
   7 #a builder that depends on a variable number of sources not known when scons is called
   8         sourceFiles = [f for f in source[0].get_text_contents().split('\n') if len(f)]
   9 
  10         f = open(target[0].get_path(),'w')
  11         for sf in sourceFiles:
  12                 f.writelines(open(sf).readlines() + ["\n\n"])
  13         f.close()
  14 
  15 def DynamicScannerFunc(node,env,path):
  16 #a scanner that can scan the variable results of PartMaker identifying it's parts
  17 #and performing an operation on each, in this case a simple copy
  18         sourceFiles = [f for f in node.get_text_contents().split('\n') if len(f)]
  19         result = []
  20         for f in sourceFiles:
  21                 env.Command(f,node,Copy("$TARGET","$SOURCE"))
  22                 result.append(env.File(f))
  23         return result
  24 
  25 
  26 env = Environment()
  27 
  28 #make the builders
  29 env['BUILDERS']['Dynamic'] = Builder(action=Action(DynamicFunc),source_scanner=Scanner(DynamicScannerFunc))
  30 env['BUILDERS']['PartMaker'] = Builder(action=Action(PartMakerFunc))
  31 
  32 #Create a variable number of parts
  33 env.PartMaker("parts.txt","x.txt")
  34 #Process that variable number of parts, using a operation for each process and an operation dependant on each part process
  35 env.Dynamic("result.txt","parts.txt")
  36 #Perform an operation that depends on the result
  37 env.Command("final.txt","result.txt",Copy("$TARGET","$SOURCE"))

NonDeterministicDependencies (last edited 2014-07-18 02:05:18 by AlexBurton)