Changeset 988 for vendor/current/buildtools/wafsamba/symbols.py
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/buildtools/wafsamba/symbols.py
r740 r988 2 2 # using nm, producing a set of exposed defined/undefined symbols 3 3 4 import Utils, Build, subprocess, Logs 5 from samba_wildcard import fake_build_environment 6 from samba_utils import * 4 import os, re, subprocess 5 import Utils, Build, Options, Logs 6 from Logs import debug 7 from samba_utils import TO_LIST, LOCAL_CACHE, get_tgt_list, os_path_relpath 7 8 8 9 # these are the data structures used in symbols.py: … … 18 19 # bld.env.syslib_symbols: dictionary mapping system library name to set of symbols 19 20 # for that library 21 # bld.env.library_dict : dictionary mapping built library paths to subsystem names 20 22 # 21 23 # LOCAL_CACHE(bld, 'TARGET_TYPE') : dictionary mapping subsystem name to target type 22 24 23 def symbols_extract(objfiles, dynamic=False): 25 26 def symbols_extract(bld, objfiles, dynamic=False): 24 27 '''extract symbols from objfile, returning a dictionary containing 25 28 the set of undefined and public symbols for each file''' 26 29 27 30 ret = {} 31 32 # see if we can get some results from the nm cache 33 if not bld.env.nm_cache: 34 bld.env.nm_cache = {} 35 36 objfiles = set(objfiles).copy() 37 38 remaining = set() 39 for obj in objfiles: 40 if obj in bld.env.nm_cache: 41 ret[obj] = bld.env.nm_cache[obj].copy() 42 else: 43 remaining.add(obj) 44 objfiles = remaining 45 46 if len(objfiles) == 0: 47 return ret 28 48 29 49 cmd = ["nm"] … … 31 51 # needed for some .so files 32 52 cmd.append("-D") 33 cmd.extend( objfiles)53 cmd.extend(list(objfiles)) 34 54 35 55 nmpipe = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout 36 56 if len(objfiles) == 1: 37 filename = objfiles[0]57 filename = list(objfiles)[0] 38 58 ret[filename] = { "PUBLIC": set(), "UNDEFINED" : set()} 39 59 … … 60 80 ret[filename]["UNDEFINED"].add(symbol) 61 81 82 # add to the cache 83 for obj in objfiles: 84 if obj in ret: 85 bld.env.nm_cache[obj] = ret[obj].copy() 86 else: 87 bld.env.nm_cache[obj] = { "PUBLIC": set(), "UNDEFINED" : set() } 88 62 89 return ret 63 90 … … 69 96 70 97 71 def find_ syslib_path(bld, libname, deps):98 def find_ldd_path(bld, libname, binary): 72 99 '''find the path to the syslib we will link against''' 73 # the strategy is to use the targets that depend on the library, and run ldd74 # on it to find the real location of the library that is used75 76 linkpath = deps[0].link_task.outputs[0].abspath(bld.env)77 78 if libname == "python":79 libname += bld.env.PYTHON_VERSION80 81 100 ret = None 82 83 lddpipe = subprocess.Popen(['ldd', linkpath], stdout=subprocess.PIPE).stdout 101 if not bld.env.syslib_paths: 102 bld.env.syslib_paths = {} 103 if libname in bld.env.syslib_paths: 104 return bld.env.syslib_paths[libname] 105 106 lddpipe = subprocess.Popen(['ldd', binary], stdout=subprocess.PIPE).stdout 84 107 for line in lddpipe: 85 108 line = line.strip() … … 87 110 if len(cols) < 3 or cols[1] != "=>": 88 111 continue 89 if cols[0].startswith("lib%s." % libname.lower()):90 ret = cols[2]91 112 if cols[0].startswith("libc."): 92 113 # save this one too 93 114 bld.env.libc_path = cols[2] 115 if cols[0].startswith(libname): 116 ret = cols[2] 117 bld.env.syslib_paths[libname] = ret 94 118 return ret 119 120 121 # some regular expressions for parsing readelf output 122 re_sharedlib = re.compile('Shared library: \[(.*)\]') 123 re_rpath = re.compile('Library rpath: \[(.*)\]') 124 125 def get_libs(bld, binname): 126 '''find the list of linked libraries for any binary or library 127 binname is the path to the binary/library on disk 128 129 We do this using readelf instead of ldd as we need to avoid recursing 130 into system libraries 131 ''' 132 133 # see if we can get the result from the ldd cache 134 if not bld.env.lib_cache: 135 bld.env.lib_cache = {} 136 if binname in bld.env.lib_cache: 137 return bld.env.lib_cache[binname].copy() 138 139 rpath = [] 140 libs = set() 141 142 elfpipe = subprocess.Popen(['readelf', '--dynamic', binname], stdout=subprocess.PIPE).stdout 143 for line in elfpipe: 144 m = re_sharedlib.search(line) 145 if m: 146 libs.add(m.group(1)) 147 m = re_rpath.search(line) 148 if m: 149 rpath.extend(m.group(1).split(":")) 150 151 ret = set() 152 for lib in libs: 153 found = False 154 for r in rpath: 155 path = os.path.join(r, lib) 156 if os.path.exists(path): 157 ret.add(os.path.realpath(path)) 158 found = True 159 break 160 if not found: 161 # we didn't find this lib using rpath. It is probably a system 162 # library, so to find the path to it we either need to use ldd 163 # or we need to start parsing /etc/ld.so.conf* ourselves. We'll 164 # use ldd for now, even though it is slow 165 path = find_ldd_path(bld, lib, binname) 166 if path: 167 ret.add(os.path.realpath(path)) 168 169 bld.env.lib_cache[binname] = ret.copy() 170 171 return ret 172 173 174 def get_libs_recursive(bld, binname, seen): 175 '''find the recursive list of linked libraries for any binary or library 176 binname is the path to the binary/library on disk. seen is a set used 177 to prevent loops 178 ''' 179 if binname in seen: 180 return set() 181 ret = get_libs(bld, binname) 182 seen.add(binname) 183 for lib in ret: 184 # we don't want to recurse into system libraries. If a system 185 # library that we use (eg. libcups) happens to use another library 186 # (such as libkrb5) which contains common symbols with our own 187 # libraries, then that is not an error 188 if lib in bld.env.library_dict: 189 ret = ret.union(get_libs_recursive(bld, lib, seen)) 190 return ret 191 192 193 194 def find_syslib_path(bld, libname, deps): 195 '''find the path to the syslib we will link against''' 196 # the strategy is to use the targets that depend on the library, and run ldd 197 # on it to find the real location of the library that is used 198 199 linkpath = deps[0].link_task.outputs[0].abspath(bld.env) 200 201 if libname == "python": 202 libname += bld.env.PYTHON_VERSION 203 204 return find_ldd_path(bld, "lib%s" % libname.lower(), linkpath) 95 205 96 206 … … 114 224 objmap[objpath] = t 115 225 116 symbols = symbols_extract( objlist)226 symbols = symbols_extract(bld, objlist) 117 227 for obj in objlist: 118 228 t = objmap[obj] … … 143 253 if t.samba_type == 'LIBRARY': 144 254 for dep in t.add_objects: 145 t2 = bld. name_to_obj(dep, bld.env)255 t2 = bld.get_tgen_by_name(dep) 146 256 bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep)) 147 257 bld.env.public_symbols[name] = bld.env.public_symbols[name].union(t2.public_symbols) … … 156 266 if t.samba_type == 'LIBRARY': 157 267 for dep in t.add_objects: 158 t2 = bld. name_to_obj(dep, bld.env)268 t2 = bld.get_tgen_by_name(dep) 159 269 bld.ASSERT(t2 is not None, "Library '%s' has unknown dependency '%s'" % (name, dep)) 160 270 bld.env.used_symbols[name] = bld.env.used_symbols[name].union(t2.used_symbols) 271 272 273 def build_library_dict(bld, tgt_list): 274 '''build the library_dict dictionary''' 275 276 if bld.env.library_dict: 277 return 278 279 bld.env.library_dict = {} 280 281 for t in tgt_list: 282 if t.samba_type in [ 'LIBRARY', 'PYTHON' ]: 283 linkpath = os.path.realpath(t.link_task.outputs[0].abspath(bld.env)) 284 bld.env.library_dict[linkpath] = t.sname 161 285 162 286 … … 193 317 objmap[bld.env.libc_path] = 'c' 194 318 195 symbols = symbols_extract( syslib_paths, dynamic=True)319 symbols = symbols_extract(bld, syslib_paths, dynamic=True) 196 320 197 321 # keep a map of syslib names to public symbols … … 240 364 deps.add(depname[0]) 241 365 continue 242 t2 = bld. name_to_obj(depname[0], bld.env)366 t2 = bld.get_tgen_by_name(depname[0]) 243 367 if len(t2.in_library) != 1: 244 368 deps.add(depname[0]) … … 263 387 if t.samba_type in [ 'LIBRARY' ]: 264 388 for obj in t.samba_deps_extended: 265 t2 = bld. name_to_obj(obj, bld.env)389 t2 = bld.get_tgen_by_name(obj) 266 390 if t2 and t2.samba_type in [ 'SUBSYSTEM', 'ASN1' ]: 267 391 if not t.sname in t2.in_library: … … 280 404 281 405 for dep in t.autodeps: 282 t2 = bld. name_to_obj(dep, bld.env)406 t2 = bld.get_tgen_by_name(dep) 283 407 if t2 is None: 284 408 continue … … 313 437 '''check for depenencies that should be changed''' 314 438 315 if bld. name_to_obj(t.sname + ".objlist", bld.env):439 if bld.get_tgen_by_name(t.sname + ".objlist"): 316 440 return 317 441 … … 325 449 deps = set(t.samba_deps) 326 450 for d in t.samba_deps: 327 if targets[d] in [ 'EMPTY', 'DISABLED', 'SYSLIB' ]:451 if targets[d] in [ 'EMPTY', 'DISABLED', 'SYSLIB', 'GENERATOR' ]: 328 452 continue 329 453 bld.ASSERT(d in bld.env.public_symbols, "Failed to find symbol list for dependency '%s'" % d) … … 353 477 '''check for syslib depenencies''' 354 478 355 if bld. name_to_obj(t.sname + ".objlist", bld.env):479 if bld.get_tgen_by_name(t.sname + ".objlist"): 356 480 return 357 481 … … 362 486 features = TO_LIST(t.features) 363 487 if 'pyembed' in features or 'pyext' in features: 364 t.unsatisfied_symbols = t.unsatisfied_symbols.difference(bld.env.public_symbols['python']) 488 if 'python' in bld.env.public_symbols: 489 t.unsatisfied_symbols = t.unsatisfied_symbols.difference(bld.env.public_symbols['python']) 365 490 366 491 needed = {} … … 444 569 445 570 446 447 def symbols_dupcheck(task): 571 def report_duplicate(bld, binname, sym, libs, fail_on_error): 572 '''report duplicated symbols''' 573 if sym in ['_init', '_fini', '_edata', '_end', '__bss_start']: 574 return 575 libnames = [] 576 for lib in libs: 577 if lib in bld.env.library_dict: 578 libnames.append(bld.env.library_dict[lib]) 579 else: 580 libnames.append(lib) 581 if fail_on_error: 582 raise Utils.WafError("%s: Symbol %s linked in multiple libraries %s" % (binname, sym, libnames)) 583 else: 584 print("%s: Symbol %s linked in multiple libraries %s" % (binname, sym, libnames)) 585 586 587 def symbols_dupcheck_binary(bld, binname, fail_on_error): 588 '''check for duplicated symbols in one binary''' 589 590 libs = get_libs_recursive(bld, binname, set()) 591 symlist = symbols_extract(bld, libs, dynamic=True) 592 593 symmap = {} 594 for libpath in symlist: 595 for sym in symlist[libpath]['PUBLIC']: 596 if sym == '_GLOBAL_OFFSET_TABLE_': 597 continue 598 if not sym in symmap: 599 symmap[sym] = set() 600 symmap[sym].add(libpath) 601 for sym in symmap: 602 if len(symmap[sym]) > 1: 603 for libpath in symmap[sym]: 604 if libpath in bld.env.library_dict: 605 report_duplicate(bld, binname, sym, symmap[sym], fail_on_error) 606 break 607 608 def symbols_dupcheck(task, fail_on_error=False): 448 609 '''check for symbols defined in two different subsystems''' 449 610 bld = task.env.bld … … 452 613 targets = LOCAL_CACHE(bld, 'TARGET_TYPE') 453 614 454 Logs.info("Checking for duplicate symbols") 455 for sym in bld.env.symbol_map: 456 subsystems = set(bld.env.symbol_map[sym]) 457 if len(subsystems) == 1: 458 continue 459 460 if sym in ['main', '_init', '_fini', 'init_samba_module', 'samba_init_module', 'ldb_init_module' ]: 461 # these are expected to be in many subsystems 462 continue 463 464 # if all of them are in system libraries, we can ignore them. This copes 465 # with the duplication between libc, libpthread and libattr 466 all_syslib = True 467 for s in subsystems: 468 if s != 'c' and (not s in targets or targets[s] != 'SYSLIB'): 469 all_syslib = False 470 if all_syslib: 471 continue 472 Logs.info("symbol %s appears in %s" % (sym, subsystems)) 615 build_library_dict(bld, tgt_list) 616 for t in tgt_list: 617 if t.samba_type == 'BINARY': 618 binname = os_path_relpath(t.link_task.outputs[0].abspath(bld.env), os.getcwd()) 619 symbols_dupcheck_binary(bld, binname, fail_on_error) 620 621 622 def symbols_dupcheck_fatal(task): 623 '''check for symbols defined in two different subsystems (and fail if duplicates are found)''' 624 symbols_dupcheck(task, fail_on_error=True) 473 625 474 626 … … 495 647 496 648 Build.BuildContext.SYMBOL_CHECK = SYMBOL_CHECK 649 650 def DUP_SYMBOL_CHECK(bld): 651 if Options.options.DUP_SYMBOLCHECK and bld.env.DEVELOPER: 652 '''check for duplicate symbols''' 653 bld.SET_BUILD_GROUP('syslibcheck') 654 task = bld(rule=symbols_dupcheck_fatal, always=True, name='symbol duplicate checking') 655 task.env.bld = bld 656 657 Build.BuildContext.DUP_SYMBOL_CHECK = DUP_SYMBOL_CHECK
Note:
See TracChangeset
for help on using the changeset viewer.