aboutsummaryrefslogtreecommitdiff
path: root/waflib/Tools/errcheck.py
blob: 93cb6c3cb5326beff09744322dd13293b18f630c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#! /usr/bin/env python
# encoding: utf-8
# WARNING! Do not edit! http://waf.googlecode.com/git/docs/wafbook/single.html#_obtaining_the_waf_file

import sys
if sys.hexversion < 0x020400f0: from sets import Set as set
typos={'feature':'features','sources':'source','targets':'target','include':'includes','export_include':'export_includes','define':'defines','importpath':'includes','installpath':'install_path',}
meths_typos=['__call__','program','shlib','stlib','objects']
from waflib import Logs,Build,Node,Task,TaskGen,ConfigSet,Errors,Utils
import waflib.Tools.ccroot
def check_same_targets(self):
	mp=Utils.defaultdict(list)
	uids={}
	def check_task(tsk):
		if not isinstance(tsk,Task.Task):
			return
		for node in tsk.outputs:
			mp[node].append(tsk)
		try:
			uids[tsk.uid()].append(tsk)
		except:
			uids[tsk.uid()]=[tsk]
	for g in self.groups:
		for tg in g:
			try:
				for tsk in tg.tasks:
					check_task(tsk)
			except AttributeError:
				check_task(tg)
	dupe=False
	for(k,v)in mp.items():
		if len(v)>1:
			dupe=True
			msg='* Node %r is created by more than once%s. The task generators are:'%(k,Logs.verbose==1 and" (full message on 'waf -v -v')"or"")
			Logs.error(msg)
			for x in v:
				if Logs.verbose>1:
					Logs.error('  %d. %r'%(1+v.index(x),x.generator))
				else:
					Logs.error('  %d. %r in %r'%(1+v.index(x),x.generator.name,getattr(x.generator,'path',None)))
	if not dupe:
		for(k,v)in uids.items():
			if len(v)>1:
				Logs.error('* Several tasks use the same identifier. Please check the information on\n   http://waf.googlecode.com/git/docs/apidocs/Task.html#waflib.Task.Task.uid')
				for tsk in v:
					Logs.error('  - object %r (%r) defined in %r'%(tsk.__class__.__name__,tsk,tsk.generator))
def check_invalid_constraints(self):
	feat=set([])
	for x in list(TaskGen.feats.values()):
		feat.union(set(x))
	for(x,y)in TaskGen.task_gen.prec.items():
		feat.add(x)
		feat.union(set(y))
	ext=set([])
	for x in TaskGen.task_gen.mappings.values():
		ext.add(x.__name__)
	invalid=ext&feat
	if invalid:
		Logs.error('The methods %r have invalid annotations:  @extension <-> @feature/@before_method/@after_method'%list(invalid))
	for cls in list(Task.classes.values()):
		for x in('before','after'):
			for y in Utils.to_list(getattr(cls,x,[])):
				if not Task.classes.get(y,None):
					Logs.error('Erroneous order constraint %r=%r on task class %r'%(x,y,cls.__name__))
		if getattr(cls,'rule',None):
			Logs.error('Erroneous attribute "rule" on task class %r (rename to "run_str")'%cls.__name__)
def replace(m):
	oldcall=getattr(Build.BuildContext,m)
	def call(self,*k,**kw):
		ret=oldcall(self,*k,**kw)
		for x in typos:
			if x in kw:
				err=True
				Logs.error('Fix the typo %r -> %r on %r'%(x,typos[x],ret))
		return ret
	setattr(Build.BuildContext,m,call)
def enhance_lib():
	for m in meths_typos:
		replace(m)
	def ant_glob(self,*k,**kw):
		if k:
			lst=Utils.to_list(k[0])
			for pat in lst:
				if'..'in pat.split('/'):
					Logs.error("In ant_glob pattern %r: '..' means 'two dots', not 'parent directory'"%k[0])
		if kw.get('remove',True):
			try:
				if self.is_child_of(self.ctx.bldnode)and not kw.get('quiet',False):
					Logs.error('Using ant_glob on the build folder (%r) is dangerous (quiet=True to disable this warning)'%self)
			except AttributeError:
				pass
		return self.old_ant_glob(*k,**kw)
	Node.Node.old_ant_glob=Node.Node.ant_glob
	Node.Node.ant_glob=ant_glob
	old=Task.is_before
	def is_before(t1,t2):
		ret=old(t1,t2)
		if ret and old(t2,t1):
			Logs.error('Contradictory order constraints in classes %r %r'%(t1,t2))
		return ret
	Task.is_before=is_before
	def check_err_features(self):
		lst=self.to_list(self.features)
		if'shlib'in lst:
			Logs.error('feature shlib -> cshlib, dshlib or cxxshlib')
		for x in('c','cxx','d','fc'):
			if not x in lst and lst and lst[0]in[x+y for y in('program','shlib','stlib')]:
				Logs.error('%r features is probably missing %r'%(self,x))
	TaskGen.feature('*')(check_err_features)
	def check_err_order(self):
		if not hasattr(self,'rule'):
			for x in('before','after','ext_in','ext_out'):
				if hasattr(self,x):
					Logs.warn('Erroneous order constraint %r on non-rule based task generator %r'%(x,self))
		else:
			for x in('before','after'):
				for y in self.to_list(getattr(self,x,[])):
					if not Task.classes.get(y,None):
						Logs.error('Erroneous order constraint %s=%r on %r'%(x,y,self))
	TaskGen.feature('*')(check_err_order)
	def check_compile(self):
		check_invalid_constraints(self)
		try:
			ret=self.orig_compile()
		finally:
			check_same_targets(self)
		return ret
	Build.BuildContext.orig_compile=Build.BuildContext.compile
	Build.BuildContext.compile=check_compile
	def use_rec(self,name,**kw):
		try:
			y=self.bld.get_tgen_by_name(name)
		except Errors.WafError:
			pass
		else:
			idx=self.bld.get_group_idx(self)
			odx=self.bld.get_group_idx(y)
			if odx>idx:
				msg="Invalid 'use' across build groups:"
				if Logs.verbose>1:
					msg+='\n  target %r\n  uses:\n  %r'%(self,y)
				else:
					msg+=" %r uses %r (try 'waf -v -v' for the full error)"%(self.name,name)
				raise Errors.WafError(msg)
		self.orig_use_rec(name,**kw)
	TaskGen.task_gen.orig_use_rec=TaskGen.task_gen.use_rec
	TaskGen.task_gen.use_rec=use_rec
	def getattri(self,name,default=None):
		if name=='append'or name=='add':
			raise Errors.WafError('env.append and env.add do not exist: use env.append_value/env.append_unique')
		elif name=='prepend':
			raise Errors.WafError('env.prepend does not exist: use env.prepend_value')
		if name in self.__slots__:
			return object.__getattr__(self,name,default)
		else:
			return self[name]
	ConfigSet.ConfigSet.__getattr__=getattri
def options(opt):
	enhance_lib()
def configure(conf):
	pass