symbols-check: skip test if we can't get the symbols list
[mesa.git] / bin / symbols-check.py
1 #!/usr/bin/env python
2
3 import argparse
4 import subprocess
5 import os
6
7 # This list contains symbols that _might_ be exported for some platforms
8 PLATFORM_SYMBOLS = [
9 '__bss_end__',
10 '__bss_start__',
11 '__bss_start',
12 '__end__',
13 '_bss_end__',
14 '_edata',
15 '_end',
16 '_fini',
17 '_init',
18 ]
19
20
21 def get_symbols(nm, lib):
22 '''
23 List all the (non platform-specific) symbols exported by the library
24 '''
25 symbols = []
26 output = subprocess.check_output([nm, '--format=bsd', '-D', '--defined-only', lib],
27 stderr=open(os.devnull, 'w')).decode("ascii")
28 for line in output.splitlines():
29 (_, _, symbol_name) = line.split()
30 symbols.append(symbol_name)
31 return symbols
32
33
34 def main():
35 parser = argparse.ArgumentParser()
36 parser.add_argument('--symbols-file',
37 action='store',
38 required=True,
39 help='path to file containing symbols')
40 parser.add_argument('--lib',
41 action='store',
42 required=True,
43 help='path to library')
44 parser.add_argument('--nm',
45 action='store',
46 required=True,
47 help='path to binary (or name in $PATH)')
48 args = parser.parse_args()
49
50 try:
51 lib_symbols = get_symbols(args.nm, args.lib)
52 except:
53 # We can't run this test, but we haven't technically failed it either
54 # Return the GNU "skip" error code
55 exit(77)
56 mandatory_symbols = []
57 optional_symbols = []
58 with open(args.symbols_file) as symbols_file:
59 qualifier_optional = '(optional)'
60 for line in symbols_file.readlines():
61
62 # Strip comments
63 line = line.split('#')[0]
64 line = line.strip()
65 if not line:
66 continue
67
68 # Line format:
69 # [qualifier] symbol
70 qualifier = None
71 symbol = None
72
73 fields = line.split()
74 if len(fields) == 1:
75 symbol = fields[0]
76 elif len(fields) == 2:
77 qualifier = fields[0]
78 symbol = fields[1]
79 else:
80 print(args.symbols_file + ': invalid format: ' + line)
81 exit(1)
82
83 # The only supported qualifier is 'optional', which means the
84 # symbol doesn't have to be exported by the library
85 if qualifier and not qualifier == qualifier_optional:
86 print(args.symbols_file + ': invalid qualifier: ' + qualifier)
87 exit(1)
88
89 if qualifier == qualifier_optional:
90 optional_symbols.append(symbol)
91 else:
92 mandatory_symbols.append(symbol)
93
94 unknown_symbols = []
95 for symbol in lib_symbols:
96 if symbol in mandatory_symbols:
97 continue
98 if symbol in optional_symbols:
99 continue
100 if symbol in PLATFORM_SYMBOLS:
101 continue
102 unknown_symbols.append(symbol)
103
104 missing_symbols = [
105 sym for sym in mandatory_symbols if sym not in lib_symbols
106 ]
107
108 for symbol in unknown_symbols:
109 print(args.lib + ': unknown symbol exported: ' + symbol)
110
111 for symbol in missing_symbols:
112 print(args.lib + ': missing symbol: ' + symbol)
113
114 if unknown_symbols or missing_symbols:
115 exit(1)
116 exit(0)
117
118
119 if __name__ == '__main__':
120 main()