summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2011-04-06 13:35:49 +1000
committerAndrew Tridgell <tridge@samba.org>2011-04-06 06:44:14 +0200
commit59b588a16c7be9ccfe42703e7d4b161fa513da76 (patch)
tree71406cf37aa61e5b16854ccf47e9bdcd861c17a8
parent0846b3c8a28fa1baa4215694d098a32c83d59d6f (diff)
downloadsamba-59b588a16c7be9ccfe42703e7d4b161fa513da76.tar.gz
samba-59b588a16c7be9ccfe42703e7d4b161fa513da76.tar.xz
samba-59b588a16c7be9ccfe42703e7d4b161fa513da76.zip
waf: a better way to detect duplicated symbols
this detects when we have the same symbol linked in twice in any binary by using ldd and nm on the binary and its associated libraries. Some of these duplicates are caused by a subsystem being linked twice, and some are caused by two versions of the same function name being linked into a binary Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org> Autobuild-User: Andrew Tridgell <tridge@samba.org> Autobuild-Date: Wed Apr 6 06:44:14 CEST 2011 on sn-devel-104
-rw-r--r--buildtools/wafsamba/symbols.py102
1 files changed, 82 insertions, 20 deletions
diff --git a/buildtools/wafsamba/symbols.py b/buildtools/wafsamba/symbols.py
index 0e862cbe15..5059c60a45 100644
--- a/buildtools/wafsamba/symbols.py
+++ b/buildtools/wafsamba/symbols.py
@@ -17,6 +17,7 @@ from samba_utils import *
#
# bld.env.syslib_symbols: dictionary mapping system library name to set of symbols
# for that library
+# bld.env.library_dict : dictionary mapping built library paths to subsystem names
#
# LOCAL_CACHE(bld, 'TARGET_TYPE') : dictionary mapping subsystem name to target type
@@ -30,11 +31,11 @@ def symbols_extract(objfiles, dynamic=False):
if dynamic:
# needed for some .so files
cmd.append("-D")
- cmd.extend(objfiles)
+ cmd.extend(list(objfiles))
nmpipe = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
if len(objfiles) == 1:
- filename = objfiles[0]
+ filename = list(objfiles)[0]
ret[filename] = { "PUBLIC": set(), "UNDEFINED" : set()}
for line in nmpipe:
@@ -68,6 +69,35 @@ def real_name(name):
return name
+def get_ldd_libs(bld, binname):
+ '''find the list of linked libraries for any binary or library
+ binname is the path to the binary/library on disk
+ '''
+ ret = set()
+ lddpipe = subprocess.Popen(['ldd', binname], stdout=subprocess.PIPE).stdout
+ for line in lddpipe:
+ line = line.strip()
+ cols = line.split(" ")
+ if len(cols) < 3 or cols[1] != "=>" or cols[2] == '':
+ continue
+ ret.add(os.path.realpath(cols[2]))
+ return ret
+
+
+def get_ldd_libs_recursive(bld, binname, seen=set()):
+ '''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()
+ ret = get_ldd_libs(bld, binname)
+ seen.add(binname)
+ for lib in ret:
+ ret = ret.union(get_ldd_libs_recursive(bld, lib, seen))
+ return ret
+
+
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
@@ -160,6 +190,20 @@ def build_symbol_sets(bld, tgt_list):
bld.env.used_symbols[name] = bld.env.used_symbols[name].union(t2.used_symbols)
+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:
+ if t.samba_type in [ 'LIBRARY', 'PYTHON' ]:
+ linkpath = os.path.realpath(t.link_task.outputs[0].abspath(bld.env))
+ bld.env.library_dict[linkpath] = t.sname
+
+
def build_syslib_sets(bld, tgt_list):
'''build the public_symbols for all syslibs'''
@@ -444,6 +488,37 @@ def symbols_whyneeded(task):
Logs.info("target '%s' uses symbols %s from '%s'" % (target, overlap, subsystem))
+def report_duplicate(bld, binname, sym, libs):
+ '''report duplicated symbols'''
+ if sym in ['_init', '_fini']:
+ return
+ libnames = []
+ for lib in libs:
+ if lib in bld.env.library_dict:
+ libnames.append(bld.env.library_dict[lib])
+ else:
+ libnames.append(lib)
+ print("%s: Symbol %s linked in multiple libraries %s" % (binname, sym, libnames))
+
+
+def symbols_dupcheck_binary(bld, binname):
+ '''check for duplicated symbols in one binary'''
+ libs = get_ldd_libs_recursive(bld, binname)
+
+ symlist = symbols_extract(libs, dynamic=True)
+
+ symmap = {}
+ for libpath in symlist:
+ for sym in symlist[libpath]['PUBLIC']:
+ 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:
+ report_duplicate(bld, binname, sym, symmap[sym])
+ break
def symbols_dupcheck(task):
'''check for symbols defined in two different subsystems'''
@@ -452,25 +527,12 @@ def symbols_dupcheck(task):
targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
- Logs.info("Checking for duplicate symbols")
- for sym in bld.env.symbol_map:
- subsystems = set(bld.env.symbol_map[sym])
- if len(subsystems) == 1:
- continue
-
- if sym in ['main', '_init', '_fini', 'init_samba_module', 'samba_init_module', 'ldb_init_module' ]:
- # these are expected to be in many subsystems
- continue
+ build_library_dict(bld, tgt_list)
+ for t in tgt_list:
+ if t.samba_type == 'BINARY':
+ binname = os_path_relpath(t.link_task.outputs[0].abspath(bld.env), os.getcwd())
+ symbols_dupcheck_binary(bld, binname)
- # if all of them are in system libraries, we can ignore them. This copes
- # with the duplication between libc, libpthread and libattr
- all_syslib = True
- for s in subsystems:
- if s != 'c' and (not s in targets or targets[s] != 'SYSLIB'):
- all_syslib = False
- if all_syslib:
- continue
- Logs.info("symbol %s appears in %s" % (sym, subsystems))
def SYMBOL_CHECK(bld):