Revision 1 as of 2014-07-18 01:58:01
python syntax highlight
|Deletions are marked like this.||Additions are marked like this.|
|Line 14:||Line 14:|
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.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.get_text_contents().split('\n') if len(f)] 9 10 f = open(target.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"))