| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778 |
- #!/usr/bin/env python
- # Script checking that all symbols exported by libpython start with Py or _Py
- import subprocess
- import sys
- import sysconfig
- def get_exported_symbols():
- LIBRARY = sysconfig.get_config_var('LIBRARY')
- if not LIBRARY:
- raise Exception("failed to get LIBRARY")
- args = ('nm', '-p', LIBRARY)
- print("+ %s" % ' '.join(args))
- proc = subprocess.run(args, stdout=subprocess.PIPE, universal_newlines=True)
- if proc.returncode:
- sys.stdout.write(proc.stdout)
- sys.exit(proc.returncode)
- stdout = proc.stdout.rstrip()
- if not stdout:
- raise Exception("command output is empty")
- return stdout
- def get_smelly_symbols(stdout):
- symbols = []
- ignored_symtypes = set()
- for line in stdout.splitlines():
- # Split line '0000000000001b80 D PyTextIOWrapper_Type'
- if not line:
- continue
- parts = line.split(maxsplit=2)
- if len(parts) < 3:
- continue
- symtype = parts[1].strip()
- # Ignore private symbols.
- #
- # If lowercase, the symbol is usually local; if uppercase, the symbol
- # is global (external). There are however a few lowercase symbols that
- # are shown for special global symbols ("u", "v" and "w").
- if symtype.islower() and symtype not in "uvw":
- ignored_symtypes.add(symtype)
- continue
- symbol = parts[-1]
- if symbol.startswith(('Py', '_Py')):
- continue
- symbol = '%s (type: %s)' % (symbol, symtype)
- symbols.append(symbol)
- if ignored_symtypes:
- print("Ignored symbol types: %s" % ', '.join(sorted(ignored_symtypes)))
- print()
- return symbols
- def main():
- nm_output = get_exported_symbols()
- symbols = get_smelly_symbols(nm_output)
- if not symbols:
- print("OK: no smelly symbol found")
- sys.exit(0)
- symbols.sort()
- for symbol in symbols:
- print("Smelly symbol: %s" % symbol)
- print()
- print("ERROR: Found %s smelly symbols!" % len(symbols))
- sys.exit(1)
- if __name__ == "__main__":
- main()
|