waf

FORK: waf with some random patches
git clone https://git.neptards.moe/neptards/waf.git
Log | Files | Refs | README

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