2010-10-29 04:50:25 +04:00
# a waf tool to extract symbols from object files or libraries
# using nm, producing a set of exposed defined/undefined symbols
2015-10-27 22:46:46 +03:00
import os , re , subprocess
2018-01-31 12:48:43 +03:00
from waflib import Utils , Build , Options , Logs , Errors
from waflib . Logs import debug
2019-11-04 07:07:44 +03:00
from samba_utils import TO_LIST , LOCAL_CACHE , get_tgt_list
2010-10-29 04:50:25 +04:00
2011-02-22 02:47:27 +03:00
# these are the data structures used in symbols.py:
#
# bld.env.symbol_map : dictionary mapping public symbol names to list of
# subsystem names where that symbol exists
#
# t.in_library : list of libraries that t is in
#
# bld.env.public_symbols: set of public symbols for each subsystem
# bld.env.used_symbols : set of used symbols for each subsystem
#
# bld.env.syslib_symbols: dictionary mapping system library name to set of symbols
# for that library
2011-04-06 07:35:49 +04:00
# bld.env.library_dict : dictionary mapping built library paths to subsystem names
2011-02-22 02:47:27 +03:00
#
# LOCAL_CACHE(bld, 'TARGET_TYPE') : dictionary mapping subsystem name to target type
2011-04-12 05:11:55 +04:00
def symbols_extract ( bld , objfiles , dynamic = False ) :
2010-10-29 04:50:25 +04:00
''' extract symbols from objfile, returning a dictionary containing
the set of undefined and public symbols for each file '''
ret = { }
2011-04-12 05:11:55 +04:00
# see if we can get some results from the nm cache
if not bld . env . nm_cache :
bld . env . nm_cache = { }
objfiles = set ( objfiles ) . copy ( )
remaining = set ( )
for obj in objfiles :
if obj in bld . env . nm_cache :
ret [ obj ] = bld . env . nm_cache [ obj ] . copy ( )
else :
remaining . add ( obj )
objfiles = remaining
if len ( objfiles ) == 0 :
return ret
2010-10-29 04:50:25 +04:00
cmd = [ " nm " ]
if dynamic :
# needed for some .so files
cmd . append ( " -D " )
2011-04-06 07:35:49 +04:00
cmd . extend ( list ( objfiles ) )
2010-10-29 04:50:25 +04:00
nmpipe = subprocess . Popen ( cmd , stdout = subprocess . PIPE ) . stdout
if len ( objfiles ) == 1 :
2011-04-06 07:35:49 +04:00
filename = list ( objfiles ) [ 0 ]
2010-10-29 04:50:25 +04:00
ret [ filename ] = { " PUBLIC " : set ( ) , " UNDEFINED " : set ( ) }
for line in nmpipe :
line = line . strip ( )
2018-12-12 00:54:47 +03:00
if line . endswith ( b ' : ' ) :
2010-10-29 04:50:25 +04:00
filename = line [ : - 1 ]
ret [ filename ] = { " PUBLIC " : set ( ) , " UNDEFINED " : set ( ) }
continue
2018-12-12 00:54:47 +03:00
cols = line . split ( b " " )
if cols == [ b ' ' ] :
2010-10-29 04:50:25 +04:00
continue
# see if the line starts with an address
if len ( cols ) == 3 :
symbol_type = cols [ 1 ]
symbol = cols [ 2 ]
else :
symbol_type = cols [ 0 ]
symbol = cols [ 1 ]
2018-12-12 00:54:47 +03:00
if symbol_type in b " BDGTRVWSi " :
2010-10-29 04:50:25 +04:00
# its a public symbol
ret [ filename ] [ " PUBLIC " ] . add ( symbol )
2018-12-12 00:54:47 +03:00
elif symbol_type in b " U " :
2010-10-29 04:50:25 +04:00
ret [ filename ] [ " UNDEFINED " ] . add ( symbol )
2011-04-12 05:11:55 +04:00
# add to the cache
for obj in objfiles :
if obj in ret :
bld . env . nm_cache [ obj ] = ret [ obj ] . copy ( )
else :
bld . env . nm_cache [ obj ] = { " PUBLIC " : set ( ) , " UNDEFINED " : set ( ) }
2010-10-29 04:50:25 +04:00
return ret
def real_name ( name ) :
if name . find ( " .objlist " ) != - 1 :
name = name [ : - 8 ]
return name
2011-04-12 15:20:41 +04:00
def find_ldd_path ( bld , libname , binary ) :
''' find the path to the syslib we will link against '''
ret = None
if not bld . env . syslib_paths :
bld . env . syslib_paths = { }
if libname in bld . env . syslib_paths :
return bld . env . syslib_paths [ libname ]
lddpipe = subprocess . Popen ( [ ' ldd ' , binary ] , stdout = subprocess . PIPE ) . stdout
for line in lddpipe :
line = line . strip ( )
2018-12-12 00:54:47 +03:00
cols = line . split ( b " " )
if len ( cols ) < 3 or cols [ 1 ] != b " => " :
2011-04-12 15:20:41 +04:00
continue
2018-12-12 00:54:47 +03:00
if cols [ 0 ] . startswith ( b " libc. " ) :
2011-04-12 15:20:41 +04:00
# save this one too
bld . env . libc_path = cols [ 2 ]
if cols [ 0 ] . startswith ( libname ) :
ret = cols [ 2 ]
bld . env . syslib_paths [ libname ] = ret
return ret
# some regular expressions for parsing readelf output
2018-12-12 00:54:47 +03:00
re_sharedlib = re . compile ( b ' Shared library: \ [(.*) \ ] ' )
2019-02-15 01:46:22 +03:00
# output from readelf could be `Library rpath` or `Libray runpath`
re_rpath = re . compile ( b ' Library (rpath|runpath): \ [(.*) \ ] ' )
2011-04-12 15:20:41 +04:00
def get_libs ( bld , binname ) :
2011-04-06 07:35:49 +04:00
''' find the list of linked libraries for any binary or library
binname is the path to the binary / library on disk
2011-04-12 15:20:41 +04:00
We do this using readelf instead of ldd as we need to avoid recursing
into system libraries
2011-04-06 07:35:49 +04:00
'''
2011-04-12 05:11:55 +04:00
# see if we can get the result from the ldd cache
2011-04-12 15:20:41 +04:00
if not bld . env . lib_cache :
bld . env . lib_cache = { }
if binname in bld . env . lib_cache :
return bld . env . lib_cache [ binname ] . copy ( )
rpath = [ ]
libs = set ( )
elfpipe = subprocess . Popen ( [ ' readelf ' , ' --dynamic ' , binname ] , stdout = subprocess . PIPE ) . stdout
for line in elfpipe :
m = re_sharedlib . search ( line )
if m :
libs . add ( m . group ( 1 ) )
m = re_rpath . search ( line )
if m :
2019-02-15 01:23:17 +03:00
# output from Popen is always bytestr even in py3
2019-02-15 01:46:22 +03:00
rpath . extend ( m . group ( 2 ) . split ( b " : " ) )
2011-04-12 05:11:55 +04:00
2011-04-06 07:35:49 +04:00
ret = set ( )
2011-04-12 15:20:41 +04:00
for lib in libs :
found = False
for r in rpath :
path = os . path . join ( r , lib )
if os . path . exists ( path ) :
ret . add ( os . path . realpath ( path ) )
found = True
break
if not found :
# we didn't find this lib using rpath. It is probably a system
# library, so to find the path to it we either need to use ldd
# or we need to start parsing /etc/ld.so.conf* ourselves. We'll
# use ldd for now, even though it is slow
path = find_ldd_path ( bld , lib , binname )
if path :
ret . add ( os . path . realpath ( path ) )
bld . env . lib_cache [ binname ] = ret . copy ( )
2011-04-12 05:11:55 +04:00
2011-04-06 07:35:49 +04:00
return ret
2011-04-12 15:20:41 +04:00
def get_libs_recursive ( bld , binname , seen ) :
2011-04-06 07:35:49 +04:00
''' find the recursive list of linked libraries for any binary or library
binname is the path to the binary / library on disk . seen is a set used
to prevent loops
'''
if binname in seen :
return set ( )
2011-04-12 15:20:41 +04:00
ret = get_libs ( bld , binname )
2011-04-06 07:35:49 +04:00
seen . add ( binname )
for lib in ret :
2011-04-12 15:20:41 +04:00
# we don't want to recurse into system libraries. If a system
# library that we use (eg. libcups) happens to use another library
# (such as libkrb5) which contains common symbols with our own
# libraries, then that is not an error
if lib in bld . env . library_dict :
ret = ret . union ( get_libs_recursive ( bld , lib , seen ) )
2011-04-06 07:35:49 +04:00
return ret
2011-04-12 15:20:41 +04:00
2010-10-29 04:50:25 +04:00
def find_syslib_path ( bld , libname , deps ) :
''' find the path to the syslib we will link against '''
# the strategy is to use the targets that depend on the library, and run ldd
# on it to find the real location of the library that is used
linkpath = deps [ 0 ] . link_task . outputs [ 0 ] . abspath ( bld . env )
if libname == " python " :
libname + = bld . env . PYTHON_VERSION
2011-04-12 15:20:41 +04:00
return find_ldd_path ( bld , " lib %s " % libname . lower ( ) , linkpath )
2010-10-29 04:50:25 +04:00
def build_symbol_sets ( bld , tgt_list ) :
''' build the public_symbols and undefined_symbols attributes for each target '''
2011-02-22 02:59:44 +03:00
if bld . env . public_symbols :
return
2010-10-29 04:50:25 +04:00
objlist = [ ] # list of object file
2011-02-22 02:47:27 +03:00
objmap = { } # map from object filename to target (subsystem) name
2010-10-29 04:50:25 +04:00
for t in tgt_list :
t . public_symbols = set ( )
t . undefined_symbols = set ( )
2011-02-22 02:47:27 +03:00
t . used_symbols = set ( )
2010-10-29 04:50:25 +04:00
for tsk in getattr ( t , ' compiled_tasks ' , [ ] ) :
for output in tsk . outputs :
objpath = output . abspath ( bld . env )
objlist . append ( objpath )
objmap [ objpath ] = t
2011-04-12 05:11:55 +04:00
symbols = symbols_extract ( bld , objlist )
2010-10-29 04:50:25 +04:00
for obj in objlist :
t = objmap [ obj ]
t . public_symbols = t . public_symbols . union ( symbols [ obj ] [ " PUBLIC " ] )
2010-10-30 04:17:30 +04:00
t . undefined_symbols = t . undefined_symbols . union ( symbols [ obj ] [ " UNDEFINED " ] )
2011-02-22 02:47:27 +03:00
t . used_symbols = t . used_symbols . union ( symbols [ obj ] [ " UNDEFINED " ] )
2010-10-29 04:50:25 +04:00
t . undefined_symbols = t . undefined_symbols . difference ( t . public_symbols )
# and the reverse map of public symbols to subsystem name
bld . env . symbol_map = { }
for t in tgt_list :
for s in t . public_symbols :
2011-02-22 02:47:27 +03:00
if not s in bld . env . symbol_map :
bld . env . symbol_map [ s ] = [ ]
bld . env . symbol_map [ s ] . append ( real_name ( t . sname ) )
2010-10-29 04:50:25 +04:00
2010-10-30 04:17:30 +04:00
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
bld . env . public_symbols = { }
for t in tgt_list :
name = real_name ( t . sname )
if name in bld . env . public_symbols :
bld . env . public_symbols [ name ] = bld . env . public_symbols [ name ] . union ( t . public_symbols )
else :
bld . env . public_symbols [ name ] = t . public_symbols
2021-08-21 00:05:57 +03:00
if t . samba_type in [ ' LIBRARY ' , ' PLUGIN ' ] :
2010-10-30 04:17:30 +04:00
for dep in t . add_objects :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( dep )
2010-10-30 04:17:30 +04:00
bld . ASSERT ( t2 is not None , " Library ' %s ' has unknown dependency ' %s ' " % ( name , dep ) )
bld . env . public_symbols [ name ] = bld . env . public_symbols [ name ] . union ( t2 . public_symbols )
2011-02-22 02:47:27 +03:00
bld . env . used_symbols = { }
for t in tgt_list :
name = real_name ( t . sname )
if name in bld . env . used_symbols :
bld . env . used_symbols [ name ] = bld . env . used_symbols [ name ] . union ( t . used_symbols )
else :
bld . env . used_symbols [ name ] = t . used_symbols
2021-08-21 00:05:57 +03:00
if t . samba_type in [ ' LIBRARY ' , ' PLUGIN ' ] :
2011-02-22 02:47:27 +03:00
for dep in t . add_objects :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( dep )
2011-02-22 02:47:27 +03:00
bld . ASSERT ( t2 is not None , " Library ' %s ' has unknown dependency ' %s ' " % ( name , dep ) )
bld . env . used_symbols [ name ] = bld . env . used_symbols [ name ] . union ( t2 . used_symbols )
2010-10-30 04:17:30 +04:00
2011-04-06 07:35:49 +04:00
def build_library_dict ( bld , tgt_list ) :
''' build the library_dict dictionary '''
if bld . env . library_dict :
return
bld . env . library_dict = { }
for t in tgt_list :
2021-08-21 00:05:57 +03:00
if t . samba_type in [ ' LIBRARY ' , ' PLUGIN ' , ' PYTHON ' ] :
2011-04-06 07:35:49 +04:00
linkpath = os . path . realpath ( t . link_task . outputs [ 0 ] . abspath ( bld . env ) )
bld . env . library_dict [ linkpath ] = t . sname
2010-10-30 04:17:30 +04:00
def build_syslib_sets ( bld , tgt_list ) :
''' build the public_symbols for all syslibs '''
2010-10-29 04:50:25 +04:00
2011-02-22 02:59:44 +03:00
if bld . env . syslib_symbols :
return
2010-10-29 04:50:25 +04:00
# work out what syslibs we depend on, and what targets those are used in
syslibs = { }
objmap = { }
for t in tgt_list :
2021-08-21 00:05:57 +03:00
if getattr ( t , ' uselib ' , [ ] ) and t . samba_type in [ ' LIBRARY ' , ' PLUGIN ' , ' BINARY ' , ' PYTHON ' ] :
2010-10-29 04:50:25 +04:00
for lib in t . uselib :
if lib in [ ' PYEMBED ' , ' PYEXT ' ] :
lib = " python "
if not lib in syslibs :
syslibs [ lib ] = [ ]
syslibs [ lib ] . append ( t )
# work out the paths to each syslib
syslib_paths = [ ]
for lib in syslibs :
path = find_syslib_path ( bld , lib , syslibs [ lib ] )
if path is None :
2010-12-01 03:42:35 +03:00
Logs . warn ( " Unable to find syslib path for %s " % lib )
2010-10-29 04:50:25 +04:00
if path is not None :
syslib_paths . append ( path )
2010-10-30 04:17:30 +04:00
objmap [ path ] = lib . lower ( )
2010-10-29 04:50:25 +04:00
# add in libc
syslib_paths . append ( bld . env . libc_path )
objmap [ bld . env . libc_path ] = ' c '
2011-04-12 05:11:55 +04:00
symbols = symbols_extract ( bld , syslib_paths , dynamic = True )
2010-10-29 04:50:25 +04:00
# keep a map of syslib names to public symbols
bld . env . syslib_symbols = { }
for lib in symbols :
bld . env . syslib_symbols [ lib ] = symbols [ lib ] [ " PUBLIC " ]
# add to the map of symbols to dependencies
for lib in symbols :
for sym in symbols [ lib ] [ " PUBLIC " ] :
2011-02-22 02:47:27 +03:00
if not sym in bld . env . symbol_map :
bld . env . symbol_map [ sym ] = [ ]
bld . env . symbol_map [ sym ] . append ( objmap [ lib ] )
2010-10-29 04:50:25 +04:00
# keep the libc symbols as well, as these are useful for some of the
# sanity checks
bld . env . libc_symbols = symbols [ bld . env . libc_path ] [ " PUBLIC " ]
2010-10-30 04:17:30 +04:00
# add to the combined map of dependency name to public_symbols
2010-10-29 04:50:25 +04:00
for lib in bld . env . syslib_symbols :
2010-10-30 04:17:30 +04:00
bld . env . public_symbols [ objmap [ lib ] ] = bld . env . syslib_symbols [ lib ]
2010-10-29 04:50:25 +04:00
2011-02-22 02:59:44 +03:00
2010-10-29 04:50:25 +04:00
def build_autodeps ( bld , t ) :
''' build the set of dependencies for a target '''
deps = set ( )
name = real_name ( t . sname )
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
for sym in t . undefined_symbols :
if sym in t . public_symbols :
continue
if sym in bld . env . symbol_map :
depname = bld . env . symbol_map [ sym ]
2011-02-22 02:47:27 +03:00
if depname == [ name ] :
2010-10-29 04:50:25 +04:00
# self dependencies aren't interesting
continue
2011-02-22 02:47:27 +03:00
if t . in_library == depname :
2010-10-29 04:50:25 +04:00
# no need to depend on the library we are part of
continue
2011-02-22 02:47:27 +03:00
if depname [ 0 ] in [ ' c ' , ' python ' ] :
2010-10-29 04:50:25 +04:00
# these don't go into autodeps
continue
2011-02-22 02:47:27 +03:00
if targets [ depname [ 0 ] ] in [ ' SYSLIB ' ] :
deps . add ( depname [ 0 ] )
2010-10-29 04:50:25 +04:00
continue
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( depname [ 0 ] )
2010-10-29 04:50:25 +04:00
if len ( t2 . in_library ) != 1 :
2011-02-22 02:47:27 +03:00
deps . add ( depname [ 0 ] )
2010-10-29 04:50:25 +04:00
continue
if t2 . in_library == t . in_library :
# if we're part of the same library, we don't need to autodep
continue
deps . add ( t2 . in_library [ 0 ] )
t . autodeps = deps
def build_library_names ( bld , tgt_list ) :
''' add a in_library attribute to all targets that are part of a library '''
2011-02-22 02:59:44 +03:00
if bld . env . done_build_library_names :
return
2010-10-29 04:50:25 +04:00
for t in tgt_list :
t . in_library = [ ]
for t in tgt_list :
2021-08-21 00:05:57 +03:00
if t . samba_type in [ ' LIBRARY ' , ' PLUGIN ' ] :
2010-10-29 04:50:25 +04:00
for obj in t . samba_deps_extended :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( obj )
2021-08-19 18:31:24 +03:00
if t2 and t2 . samba_type in [ ' SUBSYSTEM ' , ' BUILTIN ' , ' ASN1 ' ] :
2010-10-30 04:17:30 +04:00
if not t . sname in t2 . in_library :
t2 . in_library . append ( t . sname )
2011-02-22 02:59:44 +03:00
bld . env . done_build_library_names = True
2010-10-29 04:50:25 +04:00
def check_library_deps ( bld , t ) :
''' check that all the autodeps that have mutual dependency of this
target are in the same library as the target '''
name = real_name ( t . sname )
if len ( t . in_library ) > 1 :
Logs . warn ( " WARNING: Target ' %s ' in multiple libraries: %s " % ( t . sname , t . in_library ) )
for dep in t . autodeps :
2015-06-26 23:32:43 +03:00
t2 = bld . get_tgen_by_name ( dep )
2010-10-29 04:50:25 +04:00
if t2 is None :
continue
for dep2 in t2 . autodeps :
if dep2 == name and t . in_library != t2 . in_library :
2010-10-30 04:17:30 +04:00
Logs . warn ( " WARNING: mutual dependency %s <=> %s " % ( name , real_name ( t2 . sname ) ) )
Logs . warn ( " Libraries should match. %s != %s " % ( t . in_library , t2 . in_library ) )
2018-01-31 12:48:43 +03:00
# raise Errors.WafError("illegal mutual dependency")
2010-10-29 04:50:25 +04:00
def check_syslib_collisions ( bld , tgt_list ) :
''' check if a target has any symbol collisions with a syslib
We do not want any code in Samba to use a symbol name from a
system library . The chance of that causing problems is just too
high . Note that libreplace uses a rep_XX approach of renaming
symbols via macros
'''
has_error = False
for t in tgt_list :
for lib in bld . env . syslib_symbols :
common = t . public_symbols . intersection ( bld . env . syslib_symbols [ lib ] )
if common :
Logs . error ( " ERROR: Target ' %s ' has symbols ' %s ' which is also in syslib ' %s ' " % ( t . sname , common , lib ) )
has_error = True
if has_error :
2018-01-31 12:48:43 +03:00
raise Errors . WafError ( " symbols in common with system libraries " )
2010-10-29 04:50:25 +04:00
2010-10-30 04:17:30 +04:00
def check_dependencies ( bld , t ) :
''' check for depenencies that should be changed '''
2015-06-26 23:32:43 +03:00
if bld . get_tgen_by_name ( t . sname + " .objlist " ) :
2010-10-29 04:50:25 +04:00
return
2010-10-30 04:17:30 +04:00
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
remaining = t . undefined_symbols . copy ( )
remaining = remaining . difference ( t . public_symbols )
sname = real_name ( t . sname )
2010-10-29 04:50:25 +04:00
deps = set ( t . samba_deps )
2010-10-30 04:17:30 +04:00
for d in t . samba_deps :
2011-06-10 06:16:59 +04:00
if targets [ d ] in [ ' EMPTY ' , ' DISABLED ' , ' SYSLIB ' , ' GENERATOR ' ] :
2010-10-30 04:17:30 +04:00
continue
bld . ASSERT ( d in bld . env . public_symbols , " Failed to find symbol list for dependency ' %s ' " % d )
diff = remaining . intersection ( bld . env . public_symbols [ d ] )
if not diff and targets [ sname ] != ' LIBRARY ' :
Logs . info ( " Target ' %s ' has no dependency on %s " % ( sname , d ) )
else :
remaining = remaining . difference ( diff )
t . unsatisfied_symbols = set ( )
needed = { }
for sym in remaining :
if sym in bld . env . symbol_map :
dep = bld . env . symbol_map [ sym ]
2011-02-22 02:47:27 +03:00
if not dep [ 0 ] in needed :
needed [ dep [ 0 ] ] = set ( )
needed [ dep [ 0 ] ] . add ( sym )
2010-10-30 04:17:30 +04:00
else :
t . unsatisfied_symbols . add ( sym )
for dep in needed :
Logs . info ( " Target ' %s ' should add dep ' %s ' for symbols %s " % ( sname , dep , " " . join ( needed [ dep ] ) ) )
def check_syslib_dependencies ( bld , t ) :
''' check for syslib depenencies '''
2015-06-26 23:32:43 +03:00
if bld . get_tgen_by_name ( t . sname + " .objlist " ) :
2010-10-30 04:17:30 +04:00
return
sname = real_name ( t . sname )
remaining = set ( )
features = TO_LIST ( t . features )
if ' pyembed ' in features or ' pyext ' in features :
2011-03-23 04:15:33 +03:00
if ' python ' in bld . env . public_symbols :
t . unsatisfied_symbols = t . unsatisfied_symbols . difference ( bld . env . public_symbols [ ' python ' ] )
2010-10-30 04:17:30 +04:00
needed = { }
for sym in t . unsatisfied_symbols :
if sym in bld . env . symbol_map :
2011-02-22 02:47:27 +03:00
dep = bld . env . symbol_map [ sym ] [ 0 ]
2010-10-30 04:17:30 +04:00
if dep == ' c ' :
continue
if not dep in needed :
needed [ dep ] = set ( )
needed [ dep ] . add ( sym )
else :
remaining . add ( sym )
for dep in needed :
Logs . info ( " Target ' %s ' should add syslib dep ' %s ' for symbols %s " % ( sname , dep , " " . join ( needed [ dep ] ) ) )
if remaining :
debug ( " deps: Target ' %s ' has unsatisfied symbols: %s " % ( sname , " " . join ( remaining ) ) )
def symbols_symbolcheck ( task ) :
''' check the internal dependency lists '''
2010-10-29 04:50:25 +04:00
bld = task . env . bld
tgt_list = get_tgt_list ( bld )
build_symbol_sets ( bld , tgt_list )
build_library_names ( bld , tgt_list )
for t in tgt_list :
t . autodeps = set ( )
if getattr ( t , ' source ' , ' ' ) :
build_autodeps ( bld , t )
2010-10-30 04:17:30 +04:00
for t in tgt_list :
check_dependencies ( bld , t )
2010-10-29 04:50:25 +04:00
for t in tgt_list :
check_library_deps ( bld , t )
2010-10-30 04:17:30 +04:00
def symbols_syslibcheck ( task ) :
''' check the syslib dependencies '''
bld = task . env . bld
tgt_list = get_tgt_list ( bld )
2010-10-29 04:50:25 +04:00
2010-10-30 04:17:30 +04:00
build_syslib_sets ( bld , tgt_list )
check_syslib_collisions ( bld , tgt_list )
2010-10-29 04:50:25 +04:00
for t in tgt_list :
2010-10-30 04:17:30 +04:00
check_syslib_dependencies ( bld , t )
2010-10-29 04:50:25 +04:00
2011-02-22 02:59:44 +03:00
def symbols_whyneeded ( task ) :
2011-02-22 02:47:27 +03:00
""" check why ' target ' needs to link to ' subsystem ' """
2011-02-22 02:59:44 +03:00
bld = task . env . bld
tgt_list = get_tgt_list ( bld )
why = Options . options . WHYNEEDED . split ( " : " )
if len ( why ) != 2 :
2018-01-31 12:48:43 +03:00
raise Errors . WafError ( " usage: WHYNEEDED=TARGET:DEPENDENCY " )
2011-02-22 02:59:44 +03:00
target = why [ 0 ]
subsystem = why [ 1 ]
build_symbol_sets ( bld , tgt_list )
build_library_names ( bld , tgt_list )
build_syslib_sets ( bld , tgt_list )
2011-02-22 02:47:27 +03:00
Logs . info ( " Checking why %s needs to link to %s " % ( target , subsystem ) )
if not target in bld . env . used_symbols :
2011-02-22 02:59:44 +03:00
Logs . warn ( " unable to find target ' %s ' in used_symbols dict " % target )
2011-02-22 02:47:27 +03:00
return
if not subsystem in bld . env . public_symbols :
2011-02-22 02:59:44 +03:00
Logs . warn ( " unable to find subsystem ' %s ' in public_symbols dict " % subsystem )
2011-02-22 02:47:27 +03:00
return
overlap = bld . env . used_symbols [ target ] . intersection ( bld . env . public_symbols [ subsystem ] )
if not overlap :
2011-02-22 02:59:44 +03:00
Logs . info ( " target ' %s ' doesn ' t use any public symbols from ' %s ' " % ( target , subsystem ) )
2011-02-22 02:47:27 +03:00
else :
2011-02-22 02:59:44 +03:00
Logs . info ( " target ' %s ' uses symbols %s from ' %s ' " % ( target , overlap , subsystem ) )
2011-02-22 02:47:27 +03:00
2011-09-08 13:07:47 +04:00
def report_duplicate ( bld , binname , sym , libs , fail_on_error ) :
2011-04-06 07:35:49 +04:00
''' report duplicated symbols '''
2012-10-11 16:39:50 +04:00
if sym in [ ' _init ' , ' _fini ' , ' _edata ' , ' _end ' , ' __bss_start ' ] :
2011-04-06 07:35:49 +04:00
return
libnames = [ ]
for lib in libs :
if lib in bld . env . library_dict :
libnames . append ( bld . env . library_dict [ lib ] )
else :
libnames . append ( lib )
2011-09-08 13:07:47 +04:00
if fail_on_error :
2018-01-31 12:48:43 +03:00
raise Errors . WafError ( " %s : Symbol %s linked in multiple libraries %s " % ( binname , sym , libnames ) )
2011-09-08 13:07:47 +04:00
else :
print ( " %s : Symbol %s linked in multiple libraries %s " % ( binname , sym , libnames ) )
2011-04-06 07:35:49 +04:00
2011-09-08 13:07:47 +04:00
def symbols_dupcheck_binary ( bld , binname , fail_on_error ) :
2011-04-06 07:35:49 +04:00
''' check for duplicated symbols in one binary '''
2011-04-12 15:20:41 +04:00
libs = get_libs_recursive ( bld , binname , set ( ) )
2011-04-12 05:11:55 +04:00
symlist = symbols_extract ( bld , libs , dynamic = True )
2011-04-06 07:35:49 +04:00
symmap = { }
for libpath in symlist :
for sym in symlist [ libpath ] [ ' PUBLIC ' ] :
2012-04-23 05:37:39 +04:00
if sym == ' _GLOBAL_OFFSET_TABLE_ ' :
continue
2011-04-06 07:35:49 +04:00
if not sym in symmap :
symmap [ sym ] = set ( )
symmap [ sym ] . add ( libpath )
for sym in symmap :
if len ( symmap [ sym ] ) > 1 :
for libpath in symmap [ sym ] :
if libpath in bld . env . library_dict :
2011-09-08 13:07:47 +04:00
report_duplicate ( bld , binname , sym , symmap [ sym ] , fail_on_error )
2011-04-06 07:35:49 +04:00
break
2011-02-22 02:47:27 +03:00
2011-09-08 13:07:47 +04:00
def symbols_dupcheck ( task , fail_on_error = False ) :
2011-02-22 02:47:27 +03:00
''' check for symbols defined in two different subsystems '''
bld = task . env . bld
tgt_list = get_tgt_list ( bld )
2011-02-23 02:20:15 +03:00
targets = LOCAL_CACHE ( bld , ' TARGET_TYPE ' )
2011-04-06 07:35:49 +04:00
build_library_dict ( bld , tgt_list )
for t in tgt_list :
if t . samba_type == ' BINARY ' :
2019-11-04 07:07:44 +03:00
binname = os . path . relpath ( t . link_task . outputs [ 0 ] . abspath ( bld . env ) , os . getcwd ( ) )
2011-09-08 13:07:47 +04:00
symbols_dupcheck_binary ( bld , binname , fail_on_error )
2011-02-23 09:05:47 +03:00
2011-09-08 13:07:47 +04:00
def symbols_dupcheck_fatal ( task ) :
''' check for symbols defined in two different subsystems (and fail if duplicates are found) '''
symbols_dupcheck ( task , fail_on_error = True )
2011-02-22 02:47:27 +03:00
2010-10-30 04:17:30 +04:00
def SYMBOL_CHECK ( bld ) :
2010-10-29 04:50:25 +04:00
''' check our dependency lists '''
2010-10-30 04:17:30 +04:00
if Options . options . SYMBOLCHECK :
bld . SET_BUILD_GROUP ( ' symbolcheck ' )
task = bld ( rule = symbols_symbolcheck , always = True , name = ' symbol checking ' )
task . env . bld = bld
bld . SET_BUILD_GROUP ( ' syslibcheck ' )
task = bld ( rule = symbols_syslibcheck , always = True , name = ' syslib checking ' )
2010-10-29 04:50:25 +04:00
task . env . bld = bld
2011-02-22 02:47:27 +03:00
bld . SET_BUILD_GROUP ( ' syslibcheck ' )
task = bld ( rule = symbols_dupcheck , always = True , name = ' symbol duplicate checking ' )
task . env . bld = bld
2011-02-22 02:59:44 +03:00
if Options . options . WHYNEEDED :
bld . SET_BUILD_GROUP ( ' syslibcheck ' )
task = bld ( rule = symbols_whyneeded , always = True , name = ' check why a dependency is needed ' )
task . env . bld = bld
2010-10-30 04:17:30 +04:00
Build . BuildContext . SYMBOL_CHECK = SYMBOL_CHECK
2011-09-08 13:07:47 +04:00
def DUP_SYMBOL_CHECK ( bld ) :
2012-08-21 02:16:24 +04:00
if Options . options . DUP_SYMBOLCHECK and bld . env . DEVELOPER :
2011-09-08 13:07:47 +04:00
''' check for duplicate symbols '''
bld . SET_BUILD_GROUP ( ' syslibcheck ' )
task = bld ( rule = symbols_dupcheck_fatal , always = True , name = ' symbol duplicate checking ' )
task . env . bld = bld
Build . BuildContext . DUP_SYMBOL_CHECK = DUP_SYMBOL_CHECK