123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- #!/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
- 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.Task):
- lst = [tg]
- else:
- lst = tg.tasks
- for tsk in lst:
- all_tasks.append(tsk)
- do_exec = False
- for node in tsk.inputs:
- try:
- uses[node].append(tsk)
- except:
- uses[node] = [tsk]
- if matcher(node, output=False):
- do_exec = True
- break
- for node in 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 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 and not out:
- return False
- if not output and not inn:
- return False
- if anode:
- return anode == node
- else:
- return pattern.match(node.abspath())
- return match
|