2016-03-26 15:32:11 +03:00
#!/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 :
2018-01-31 12:48:43 +03:00
if isinstance ( tg , Task . Task ) :
2016-03-26 15:32:11 +03:00
lst = [ tg ]
else :
lst = tg . tasks
for tsk in lst :
all_tasks . append ( tsk )
do_exec = False
2018-01-31 12:48:43 +03:00
for node in tsk . inputs :
2016-03-26 15:32:11 +03:00
try :
uses [ node ] . append ( tsk )
except :
uses [ node ] = [ tsk ]
if matcher ( node , output = False ) :
do_exec = True
break
2018-01-31 12:48:43 +03:00
for node in tsk . outputs :
2016-03-26 15:32:11 +03:00
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...
2018-01-31 12:48:43 +03:00
result = set ( )
seen = set ( )
2016-03-26 15:32:11 +03:00
cur = set ( tasks )
while cur :
result | = cur
2018-01-31 12:48:43 +03:00
tosee = set ( )
2016-03-26 15:32:11 +03:00
for tsk in cur :
2018-01-31 12:48:43 +03:00
for node in tsk . inputs :
2016-03-26 15:32:11 +03:00
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 ) :
2018-01-31 12:48:43 +03:00
if output and not out :
2016-03-26 15:32:11 +03:00
return False
2018-01-31 12:48:43 +03:00
if not output and not inn :
2016-03-26 15:32:11 +03:00
return False
if anode :
return anode == node
else :
return pattern . match ( node . abspath ( ) )
return match
2018-01-31 12:48:43 +03:00