2011-09-10 11:13:51 +02:00
#! /usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2011 (ita)
"""
2012-04-08 20:20:10 +02:00
errcheck : highlight common mistakes
2011-09-10 11:13:51 +02:00
There is a performance hit , so this tool is only loaded when running " waf -v "
"""
typos = {
' feature ' : ' features ' ,
' sources ' : ' source ' ,
' targets ' : ' target ' ,
' include ' : ' includes ' ,
' export_include ' : ' export_includes ' ,
' define ' : ' defines ' ,
' importpath ' : ' includes ' ,
' installpath ' : ' install_path ' ,
2012-08-03 19:38:50 +02:00
' iscopy ' : ' is_copy ' ,
2011-09-10 11:13:51 +02:00
}
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 )
2012-02-11 14:49:27 +01:00
except KeyError :
2011-09-10 11:13:51 +02:00
uids [ tsk . uid ( ) ] = [ tsk ]
for g in self . groups :
for tg in g :
try :
for tsk in tg . tasks :
check_task ( tsk )
except AttributeError :
# raised if not a task generator, which should be uncommon
check_task ( tg )
dupe = False
for ( k , v ) in mp . items ( ) :
if len ( v ) > 1 :
dupe = True
2012-07-20 20:16:25 +02:00
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 " " )
2011-09-10 11:13:51 +02:00
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 :
2012-02-25 16:47:30 +01:00
Logs . error ( ' * Several tasks use the same identifier. Please check the information on \n http://docs.waf.googlecode.com/git/apidocs_16/Task.html#waflib.Task.Task.uid ' )
2011-09-10 11:13:51 +02:00
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 ) )
# the build scripts have been read, so we can check for invalid after/before attributes on task classes
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__ ) )
2011-10-04 19:45:30 +02:00
if getattr ( cls , ' rule ' , None ) :
Logs . error ( ' Erroneous attribute " rule " on task class %r (rename to " run_str " ) ' % cls . __name__ )
2011-09-10 11:13:51 +02:00
def replace ( m ) :
"""
We could add properties , but they would not work in some cases :
bld . program ( . . . ) requires ' source ' in the attributes
"""
oldcall = getattr ( Build . BuildContext , m )
def call ( self , * k , * * kw ) :
ret = oldcall ( self , * k , * * kw )
for x in typos :
if x in kw :
2012-08-03 19:38:50 +02:00
if x == ' iscopy ' and ' subst ' in getattr ( self , ' features ' , ' ' ) :
continue
2011-09-10 11:13:51 +02:00
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 ( ) :
"""
modify existing classes and methods
"""
for m in meths_typos :
replace ( m )
# catch '..' in ant_glob patterns
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 ] )
2011-12-02 19:13:30 +01:00
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
2011-09-10 11:13:51 +02:00
Node . Node . ant_glob = ant_glob
# catch conflicting ext_in/ext_out/before/after declarations
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
# check for bld(feature='cshlib') where no 'c' is given - this can be either a mistake or on purpose
# so we only issue a warning
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 )
# check for erroneous order constraints
def check_err_order ( self ) :
2012-04-08 20:20:10 +02:00
if not hasattr ( self , ' rule ' ) and not ' subst ' in Utils . to_list ( self . features ) :
2011-09-10 11:13:51 +02:00
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 ) :
2012-04-08 20:20:10 +02:00
Logs . error ( ' Erroneous order constraint %s = %r on %r (no such class) ' % ( x , y , self ) )
2011-09-10 11:13:51 +02:00
TaskGen . feature ( ' * ' ) ( check_err_order )
# check for @extension used with @feature/@before_method/@after_method
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
# check for invalid build groups #914
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
# check for env.append
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 ) :
"""
Add a few methods
"""
enhance_lib ( )
def configure ( conf ) :
pass