mirror of
https://gitlab.com/ita1024/waf.git
synced 2024-11-16 15:09:44 +01:00
143 lines
3.2 KiB
Python
143 lines
3.2 KiB
Python
|
#!/usr/bin/env python
|
||
|
# encoding: utf-8
|
||
|
# Thomas Nagy, 2011 (ita)
|
||
|
|
||
|
"""
|
||
|
A make-like way of executing the build, following the relationships between inputs/outputs
|
||
|
|
||
|
This algorithm will lead to slower builds, will not be as flexible as "waf build", but
|
||
|
it might be useful for building data files (?)
|
||
|
|
||
|
It is likely to break in the following cases:
|
||
|
- files are created dynamically (no inputs or outputs)
|
||
|
- headers
|
||
|
- building two files from different groups
|
||
|
"""
|
||
|
|
||
|
import re
|
||
|
from waflib import Options, Task, Logs
|
||
|
from waflib.Build import BuildContext
|
||
|
|
||
|
class MakeContext(BuildContext):
|
||
|
'''executes tasks in a step-by-step manner, following dependencies between inputs/outputs'''
|
||
|
cmd = 'make'
|
||
|
fun = 'build'
|
||
|
|
||
|
def __init__(self, **kw):
|
||
|
super(MakeContext, self).__init__(**kw)
|
||
|
self.files = Options.options.files
|
||
|
|
||
|
def get_build_iterator(self):
|
||
|
if not self.files:
|
||
|
while 1:
|
||
|
yield super(MakeContext, self).get_build_iterator()
|
||
|
|
||
|
for g in self.groups:
|
||
|
for tg in g:
|
||
|
try:
|
||
|
f = tg.post
|
||
|
except AttributeError:
|
||
|
pass
|
||
|
else:
|
||
|
f()
|
||
|
|
||
|
provides = {}
|
||
|
uses = {}
|
||
|
all_tasks = []
|
||
|
tasks = []
|
||
|
for pat in self.files.split(','):
|
||
|
matcher = self.get_matcher(pat)
|
||
|
for tg in g:
|
||
|
if isinstance(tg, Task.TaskBase):
|
||
|
lst = [tg]
|
||
|
else:
|
||
|
lst = tg.tasks
|
||
|
for tsk in lst:
|
||
|
all_tasks.append(tsk)
|
||
|
|
||
|
do_exec = False
|
||
|
for node in getattr(tsk, 'inputs', []):
|
||
|
try:
|
||
|
uses[node].append(tsk)
|
||
|
except:
|
||
|
uses[node] = [tsk]
|
||
|
|
||
|
if matcher(node, output=False):
|
||
|
do_exec = True
|
||
|
break
|
||
|
|
||
|
for node in getattr(tsk, 'outputs', []):
|
||
|
try:
|
||
|
provides[node].append(tsk)
|
||
|
except:
|
||
|
provides[node] = [tsk]
|
||
|
|
||
|
if matcher(node, output=True):
|
||
|
do_exec = True
|
||
|
break
|
||
|
if do_exec:
|
||
|
tasks.append(tsk)
|
||
|
|
||
|
# so we have the tasks that we need to process, the list of all tasks,
|
||
|
# the map of the tasks providing nodes, and the map of tasks using nodes
|
||
|
|
||
|
if not tasks:
|
||
|
# if there are no tasks matching, return everything in the current group
|
||
|
result = all_tasks
|
||
|
else:
|
||
|
# this is like a big filter...
|
||
|
result = set([])
|
||
|
seen = set([])
|
||
|
cur = set(tasks)
|
||
|
while cur:
|
||
|
result |= cur
|
||
|
tosee = set([])
|
||
|
for tsk in cur:
|
||
|
for node in getattr(tsk, 'inputs', []):
|
||
|
if node in seen:
|
||
|
continue
|
||
|
seen.add(node)
|
||
|
tosee |= set(provides.get(node, []))
|
||
|
cur = tosee
|
||
|
result = list(result)
|
||
|
|
||
|
Task.set_file_constraints(result)
|
||
|
Task.set_precedence_constraints(result)
|
||
|
yield result
|
||
|
|
||
|
while 1:
|
||
|
yield []
|
||
|
|
||
|
def get_matcher(self, pat):
|
||
|
# this returns a function
|
||
|
inn = True
|
||
|
out = True
|
||
|
if pat.startswith('in:'):
|
||
|
out = False
|
||
|
pat = pat.replace('in:', '')
|
||
|
elif pat.startswith('out:'):
|
||
|
inn = False
|
||
|
pat = pat.replace('out:', '')
|
||
|
|
||
|
anode = self.root.find_node(pat)
|
||
|
pattern = None
|
||
|
if not anode:
|
||
|
if not pat.startswith('^'):
|
||
|
pat = '^.+?%s' % pat
|
||
|
if not pat.endswith('$'):
|
||
|
pat = '%s$' % pat
|
||
|
pattern = re.compile(pat)
|
||
|
|
||
|
def match(node, output):
|
||
|
if output == True and not out:
|
||
|
return False
|
||
|
if output == False and not inn:
|
||
|
return False
|
||
|
|
||
|
if anode:
|
||
|
return anode == node
|
||
|
else:
|
||
|
return pattern.match(node.abspath())
|
||
|
return match
|
||
|
|