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