build:wafsamba: Remove unnecessary parameters to cmd_and_log
[samba.git] / third_party / waf / waflib / Tools / errcheck.py
1 #! /usr/bin/env python
2 # encoding: utf-8
3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
4
5 #! /usr/bin/env python
6 # encoding: utf-8
7 # Thomas Nagy, 2011 (ita)
8
9 """
10 Common mistakes highlighting.
11
12 There is a performance impact, so this tool is only loaded when running ``waf -v``
13 """
14
15 typos = {
16 'feature':'features',
17 'sources':'source',
18 'targets':'target',
19 'include':'includes',
20 'export_include':'export_includes',
21 'define':'defines',
22 'importpath':'includes',
23 'installpath':'install_path',
24 'iscopy':'is_copy',
25 }
26
27 meths_typos = ['__call__', 'program', 'shlib', 'stlib', 'objects']
28
29 import sys
30 from waflib import Logs, Build, Node, Task, TaskGen, ConfigSet, Errors, Utils
31 from waflib.Tools import ccroot
32
33 def check_same_targets(self):
34         mp = Utils.defaultdict(list)
35         uids = {}
36
37         def check_task(tsk):
38                 if not isinstance(tsk, Task.Task):
39                         return
40                 if hasattr(tsk, 'no_errcheck_out'):
41                         return
42
43                 for node in tsk.outputs:
44                         mp[node].append(tsk)
45                 try:
46                         uids[tsk.uid()].append(tsk)
47                 except KeyError:
48                         uids[tsk.uid()] = [tsk]
49
50         for g in self.groups:
51                 for tg in g:
52                         try:
53                                 for tsk in tg.tasks:
54                                         check_task(tsk)
55                         except AttributeError:
56                                 # raised if not a task generator, which should be uncommon
57                                 check_task(tg)
58
59         dupe = False
60         for (k, v) in mp.items():
61                 if len(v) > 1:
62                         dupe = True
63                         msg = '* Node %r is created more than once%s. The task generators are:' % (k, Logs.verbose == 1 and " (full message on 'waf -v -v')" or "")
64                         Logs.error(msg)
65                         for x in v:
66                                 if Logs.verbose > 1:
67                                         Logs.error('  %d. %r', 1 + v.index(x), x.generator)
68                                 else:
69                                         Logs.error('  %d. %r in %r', 1 + v.index(x), x.generator.name, getattr(x.generator, 'path', None))
70                         Logs.error('If you think that this is an error, set no_errcheck_out on the task instance')
71
72         if not dupe:
73                 for (k, v) in uids.items():
74                         if len(v) > 1:
75                                 Logs.error('* Several tasks use the same identifier. Please check the information on\n   https://waf.io/apidocs/Task.html?highlight=uid#waflib.Task.Task.uid')
76                                 for tsk in v:
77                                         Logs.error('  - object %r (%r) defined in %r', tsk.__class__.__name__, tsk, tsk.generator)
78
79 def check_invalid_constraints(self):
80         feat = set()
81         for x in list(TaskGen.feats.values()):
82                 feat.union(set(x))
83         for (x, y) in TaskGen.task_gen.prec.items():
84                 feat.add(x)
85                 feat.union(set(y))
86         ext = set()
87         for x in TaskGen.task_gen.mappings.values():
88                 ext.add(x.__name__)
89         invalid = ext & feat
90         if invalid:
91                 Logs.error('The methods %r have invalid annotations:  @extension <-> @feature/@before_method/@after_method', list(invalid))
92
93         # the build scripts have been read, so we can check for invalid after/before attributes on task classes
94         for cls in list(Task.classes.values()):
95                 if sys.hexversion > 0x3000000 and issubclass(cls, Task.Task) and isinstance(cls.hcode, str):
96                         raise Errors.WafError('Class %r has hcode value %r of type <str>, expecting <bytes> (use Utils.h_cmd() ?)' % (cls, cls.hcode))
97
98                 for x in ('before', 'after'):
99                         for y in Utils.to_list(getattr(cls, x, [])):
100                                 if not Task.classes.get(y):
101                                         Logs.error('Erroneous order constraint %r=%r on task class %r', x, y, cls.__name__)
102                 if getattr(cls, 'rule', None):
103                         Logs.error('Erroneous attribute "rule" on task class %r (rename to "run_str")', cls.__name__)
104
105 def replace(m):
106         """
107         Replaces existing BuildContext methods to verify parameter names,
108         for example ``bld(source=)`` has no ending *s*
109         """
110         oldcall = getattr(Build.BuildContext, m)
111         def call(self, *k, **kw):
112                 ret = oldcall(self, *k, **kw)
113                 for x in typos:
114                         if x in kw:
115                                 if x == 'iscopy' and 'subst' in getattr(self, 'features', ''):
116                                         continue
117                                 Logs.error('Fix the typo %r -> %r on %r', x, typos[x], ret)
118                 return ret
119         setattr(Build.BuildContext, m, call)
120
121 def enhance_lib():
122         """
123         Modifies existing classes and methods to enable error verification
124         """
125         for m in meths_typos:
126                 replace(m)
127
128         # catch '..' in ant_glob patterns
129         def ant_glob(self, *k, **kw):
130                 if k:
131                         lst = Utils.to_list(k[0])
132                         for pat in lst:
133                                 sp = pat.split('/')
134                                 if '..' in sp:
135                                         Logs.error("In ant_glob pattern %r: '..' means 'two dots', not 'parent directory'", k[0])
136                                 if '.' in sp:
137                                         Logs.error("In ant_glob pattern %r: '.' means 'one dot', not 'current directory'", k[0])
138                 if kw.get('remove', True):
139                         try:
140                                 if self.is_child_of(self.ctx.bldnode) and not kw.get('quiet', False):
141                                         Logs.error('Using ant_glob on the build folder (%r) is dangerous (quiet=True to disable this warning)', self)
142                         except AttributeError:
143                                 pass
144                 return self.old_ant_glob(*k, **kw)
145         Node.Node.old_ant_glob = Node.Node.ant_glob
146         Node.Node.ant_glob = ant_glob
147
148         # catch conflicting ext_in/ext_out/before/after declarations
149         old = Task.is_before
150         def is_before(t1, t2):
151                 ret = old(t1, t2)
152                 if ret and old(t2, t1):
153                         Logs.error('Contradictory order constraints in classes %r %r', t1, t2)
154                 return ret
155         Task.is_before = is_before
156
157         # check for bld(feature='cshlib') where no 'c' is given - this can be either a mistake or on purpose
158         # so we only issue a warning
159         def check_err_features(self):
160                 lst = self.to_list(self.features)
161                 if 'shlib' in lst:
162                         Logs.error('feature shlib -> cshlib, dshlib or cxxshlib')
163                 for x in ('c', 'cxx', 'd', 'fc'):
164                         if not x in lst and lst and lst[0] in [x+y for y in ('program', 'shlib', 'stlib')]:
165                                 Logs.error('%r features is probably missing %r', self, x)
166         TaskGen.feature('*')(check_err_features)
167
168         # check for erroneous order constraints
169         def check_err_order(self):
170                 if not hasattr(self, 'rule') and not 'subst' in Utils.to_list(self.features):
171                         for x in ('before', 'after', 'ext_in', 'ext_out'):
172                                 if hasattr(self, x):
173                                         Logs.warn('Erroneous order constraint %r on non-rule based task generator %r', x, self)
174                 else:
175                         for x in ('before', 'after'):
176                                 for y in self.to_list(getattr(self, x, [])):
177                                         if not Task.classes.get(y, None):
178                                                 Logs.error('Erroneous order constraint %s=%r on %r (no such class)', x, y, self)
179         TaskGen.feature('*')(check_err_order)
180
181         # check for @extension used with @feature/@before_method/@after_method
182         def check_compile(self):
183                 check_invalid_constraints(self)
184                 try:
185                         ret = self.orig_compile()
186                 finally:
187                         check_same_targets(self)
188                 return ret
189         Build.BuildContext.orig_compile = Build.BuildContext.compile
190         Build.BuildContext.compile = check_compile
191
192         # check for invalid build groups #914
193         def use_rec(self, name, **kw):
194                 try:
195                         y = self.bld.get_tgen_by_name(name)
196                 except Errors.WafError:
197                         pass
198                 else:
199                         idx = self.bld.get_group_idx(self)
200                         odx = self.bld.get_group_idx(y)
201                         if odx > idx:
202                                 msg = "Invalid 'use' across build groups:"
203                                 if Logs.verbose > 1:
204                                         msg += '\n  target %r\n  uses:\n  %r' % (self, y)
205                                 else:
206                                         msg += " %r uses %r (try 'waf -v -v' for the full error)" % (self.name, name)
207                                 raise Errors.WafError(msg)
208                 self.orig_use_rec(name, **kw)
209         TaskGen.task_gen.orig_use_rec = TaskGen.task_gen.use_rec
210         TaskGen.task_gen.use_rec = use_rec
211
212         # check for env.append
213         def _getattr(self, name, default=None):
214                 if name == 'append' or name == 'add':
215                         raise Errors.WafError('env.append and env.add do not exist: use env.append_value/env.append_unique')
216                 elif name == 'prepend':
217                         raise Errors.WafError('env.prepend does not exist: use env.prepend_value')
218                 if name in self.__slots__:
219                         return object.__getattr__(self, name, default)
220                 else:
221                         return self[name]
222         ConfigSet.ConfigSet.__getattr__ = _getattr
223
224
225 def options(opt):
226         """
227         Error verification can be enabled by default (not just on ``waf -v``) by adding to the user script options
228         """
229         enhance_lib()