make.py (3202B)
1 #!/usr/bin/env python 2 # encoding: utf-8 3 # Thomas Nagy, 2011 (ita) 4 5 """ 6 A make-like way of executing the build, following the relationships between inputs/outputs 7 8 This algorithm will lead to slower builds, will not be as flexible as "waf build", but 9 it might be useful for building data files (?) 10 11 It is likely to break in the following cases: 12 - files are created dynamically (no inputs or outputs) 13 - headers 14 - building two files from different groups 15 """ 16 17 import re 18 from waflib import Options, Task 19 from waflib.Build import BuildContext 20 21 class MakeContext(BuildContext): 22 '''executes tasks in a step-by-step manner, following dependencies between inputs/outputs''' 23 cmd = 'make' 24 fun = 'build' 25 26 def __init__(self, **kw): 27 super(MakeContext, self).__init__(**kw) 28 self.files = Options.options.files 29 30 def get_build_iterator(self): 31 if not self.files: 32 while 1: 33 yield super(MakeContext, self).get_build_iterator() 34 35 for g in self.groups: 36 for tg in g: 37 try: 38 f = tg.post 39 except AttributeError: 40 pass 41 else: 42 f() 43 44 provides = {} 45 uses = {} 46 all_tasks = [] 47 tasks = [] 48 for pat in self.files.split(','): 49 matcher = self.get_matcher(pat) 50 for tg in g: 51 if isinstance(tg, Task.Task): 52 lst = [tg] 53 else: 54 lst = tg.tasks 55 for tsk in lst: 56 all_tasks.append(tsk) 57 58 do_exec = False 59 for node in tsk.inputs: 60 try: 61 uses[node].append(tsk) 62 except: 63 uses[node] = [tsk] 64 65 if matcher(node, output=False): 66 do_exec = True 67 break 68 69 for node in tsk.outputs: 70 try: 71 provides[node].append(tsk) 72 except: 73 provides[node] = [tsk] 74 75 if matcher(node, output=True): 76 do_exec = True 77 break 78 if do_exec: 79 tasks.append(tsk) 80 81 # so we have the tasks that we need to process, the list of all tasks, 82 # the map of the tasks providing nodes, and the map of tasks using nodes 83 84 if not tasks: 85 # if there are no tasks matching, return everything in the current group 86 result = all_tasks 87 else: 88 # this is like a big filter... 89 result = set() 90 seen = set() 91 cur = set(tasks) 92 while cur: 93 result |= cur 94 tosee = set() 95 for tsk in cur: 96 for node in tsk.inputs: 97 if node in seen: 98 continue 99 seen.add(node) 100 tosee |= set(provides.get(node, [])) 101 cur = tosee 102 result = list(result) 103 104 Task.set_file_constraints(result) 105 Task.set_precedence_constraints(result) 106 yield result 107 108 while 1: 109 yield [] 110 111 def get_matcher(self, pat): 112 # this returns a function 113 inn = True 114 out = True 115 if pat.startswith('in:'): 116 out = False 117 pat = pat.replace('in:', '') 118 elif pat.startswith('out:'): 119 inn = False 120 pat = pat.replace('out:', '') 121 122 anode = self.root.find_node(pat) 123 pattern = None 124 if not anode: 125 if not pat.startswith('^'): 126 pat = '^.+?%s' % pat 127 if not pat.endswith('$'): 128 pat = '%s$' % pat 129 pattern = re.compile(pat) 130 131 def match(node, output): 132 if output and not out: 133 return False 134 if not output and not inn: 135 return False 136 137 if anode: 138 return anode == node 139 else: 140 return pattern.match(node.abspath()) 141 return match 142