blob: 43d091654d2dc84e499e1950cc3a0303879d4d33 [file] [log] [blame]
Victor Stinner87d332d2017-10-24 01:29:53 -07001#!/usr/bin/env python
2# Script checking that all symbols exported by libpython start with Py or _Py
3
4import subprocess
5import sys
6import sysconfig
7
8
9def get_exported_symbols():
10 LIBRARY = sysconfig.get_config_var('LIBRARY')
11 if not LIBRARY:
12 raise Exception("failed to get LIBRARY")
13
14 args = ('nm', '-p', LIBRARY)
15 print("+ %s" % ' '.join(args))
16 proc = subprocess.run(args, stdout=subprocess.PIPE, universal_newlines=True)
17 if proc.returncode:
18 sys.stdout.write(proc.stdout)
19 sys.exit(proc.returncode)
20
21 stdout = proc.stdout.rstrip()
22 if not stdout:
23 raise Exception("command output is empty")
24 return stdout
25
26
27def get_smelly_symbols(stdout):
28 symbols = []
29 ignored_symtypes = set()
Antoine Pitroud7687eb2018-02-27 21:40:37 +010030
31 allowed_prefixes = ('Py', '_Py')
32 if sys.platform == 'darwin':
33 allowed_prefixes += ('__Py',)
34
Victor Stinner87d332d2017-10-24 01:29:53 -070035 for line in stdout.splitlines():
36 # Split line '0000000000001b80 D PyTextIOWrapper_Type'
37 if not line:
38 continue
39
40 parts = line.split(maxsplit=2)
41 if len(parts) < 3:
42 continue
43
44 symtype = parts[1].strip()
45 # Ignore private symbols.
46 #
47 # If lowercase, the symbol is usually local; if uppercase, the symbol
48 # is global (external). There are however a few lowercase symbols that
49 # are shown for special global symbols ("u", "v" and "w").
50 if symtype.islower() and symtype not in "uvw":
51 ignored_symtypes.add(symtype)
52 continue
53
54 symbol = parts[-1]
Antoine Pitroud7687eb2018-02-27 21:40:37 +010055 if symbol.startswith(allowed_prefixes):
Victor Stinner87d332d2017-10-24 01:29:53 -070056 continue
57 symbol = '%s (type: %s)' % (symbol, symtype)
58 symbols.append(symbol)
59
60 if ignored_symtypes:
61 print("Ignored symbol types: %s" % ', '.join(sorted(ignored_symtypes)))
62 print()
63 return symbols
64
65
66def main():
67 nm_output = get_exported_symbols()
68 symbols = get_smelly_symbols(nm_output)
69
70 if not symbols:
71 print("OK: no smelly symbol found")
72 sys.exit(0)
73
74 symbols.sort()
75 for symbol in symbols:
76 print("Smelly symbol: %s" % symbol)
77 print()
78 print("ERROR: Found %s smelly symbols!" % len(symbols))
79 sys.exit(1)
80
81
82if __name__ == "__main__":
83 main()