wscript (4216B)
1 #! /usr/bin/env python 2 # encoding: utf-8 3 # Thomas Nagy, 2010 (ita) 4 5 VERSION='0.0.1' 6 APPNAME='cpp_gen' 7 8 top = '.' 9 out = 'build' 10 11 def options(opt): 12 opt.load('compiler_cxx') 13 14 def configure(conf): 15 conf.load('compiler_cxx') 16 conf.check(header_name='stdio.h', features='cxx cxxprogram', mandatory=False) 17 18 def build(bld): 19 bld.program(source='main.cpp a.cpp', target='app') 20 21 #-------- 22 23 import os 24 from waflib import Task, TaskGen, Utils 25 from waflib.Tools import cxx 26 27 @TaskGen.extension('.cpp') 28 def more_tasks_at_once(self, node): 29 task1 = self.create_task('prog1', node, []) 30 task2 = self.create_compiled_task('cxx', node) 31 32 def cmpnodes(a, b): 33 return cmp(a.abspath(), b.abspath()) 34 35 class prog1(Task.Task): 36 before = ['cxxprogram', 'cxxshlib', 'cxxstlib'] 37 38 def uid(self): 39 """ 40 the unique id of this task should only depend on the file inputs 41 """ 42 m = Utils.md5() 43 up = m.update 44 up(self.__class__.__name__.encode()) 45 for x in self.inputs: 46 up(x.abspath().encode()) 47 return m.digest() 48 49 def runnable_status(self): 50 """ 51 since it is called after the build has started, 52 any task added must be passed through 'more_tasks' 53 """ 54 for x in self.run_after: 55 if not x.hasrun: 56 return Task.ASK_LATER 57 58 # so this is a bit special, the goal here is to set the output nodes 59 # and to create the c++ tasks before the normal processing is done 60 sig = self.signature() 61 for x in self.generator.bld.raw_deps.get(sig, []): 62 self.outputs.append(self.generator.bld.srcnode.find_node(x)) 63 64 if not self.outputs: 65 self.read_outputs_from_cache() 66 67 if self.outputs: 68 self.create_cxx_task() 69 70 ret = Task.Task.runnable_status(self) 71 return ret 72 73 def create_cxx_task(self): 74 """ 75 create a task dynamically during the build 76 notice the use of 'more_tasks' 77 """ 78 tsk = cxx.cxx_hook(self.generator, self.outputs[0]) 79 tsk.set_run_after(self) # the build has started, so the order must be set manually 80 self.more_tasks = [tsk] # add tasks dynamically during the build 81 self.generator.link_task.inputs.append(tsk.outputs[0]) # add another input for the link task 82 try: 83 self.generator.link_task.inputs.sort(cmp=cmpnodes) # eliminate the random order (more tasks like this) 84 except: 85 self.generator.link_task.inputs.sort(key=lambda x: x.abspath()) # python3 86 self.generator.link_task.set_run_after(tsk) # do not forget to set the build order there too 87 88 def run(self): 89 """ 90 actual execution 91 this code should not be executed if the files are retrieved from the cache 92 """ 93 if self.inputs[0].name == 'a.cpp': 94 # simulate the creation of an interface file 95 out = self.inputs[0].parent.get_bld().make_node('a.ser.cpp') 96 out.write('\n\n') 97 98 # read the file system 99 # remember that nodes cannot be created concurrently 100 # so you might to crate a lock if several tasks want the same nodes 101 inp = self.inputs[0] 102 node = inp.parent.get_bld().find_node(inp.name.replace('.cpp', '.ser.cpp')) 103 if node: 104 self.outputs = [node] 105 h_node = inp.parent.find_node(inp.name.replace('.cpp', '.ser.h')) 106 if h_node: 107 self.outputs.append(h_node) 108 109 # if there are outputs, create a new c++ task 110 if self.outputs: 111 self.create_cxx_task() 112 113 # access the scanner data 114 self.generator.bld.raw_deps[self.signature()] = [x.path_from(self.generator.bld.srcnode) for x in self.outputs] 115 116 def read_outputs_from_cache(self): 117 """ 118 set the outputs from the results found in the cache 119 we assume that the files are created in the same folder as the inputs 120 if it is not like this, the nodes should be restored by another system, for example 121 by storing them in a separate file during run() 122 """ 123 env = self.env 124 sig = self.signature() 125 ssig = Utils.to_hex(sig) 126 127 # first try to access the cache folder for the task 128 dname = os.path.join(self.generator.bld.cache_global, ssig) 129 try: 130 t1 = os.stat(dname).st_mtime 131 except OSError: 132 return None 133 134 try: 135 lst = os.listdir(dname) 136 except: 137 return 138 139 for x in lst: 140 self.outputs.append(self.inputs[0].parent.find_or_declare(x)) 141 142 # not a fresh build and the cache is removed -> remember the files in the scanner data 143 self.generator.bld.raw_deps[self.signature()] = [x.path_from(self.generator.bld.srcnode) for x in self.outputs] 144