blob: 385959bdef781aabe4f392480855a2fc97f5e099 [file] [log] [blame]
Ebrahim Byagowi7250ade2020-05-29 12:34:30 +04301#!/usr/bin/env python3
2
3import sys, os, shutil, subprocess, re, difflib
4
5os.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order
6
Ebrahim Byagowia07672d2020-07-04 14:12:55 +04307builddir = os.getenv ('builddir', os.path.dirname (__file__))
8libs = os.getenv ('libs', '.libs')
Ebrahim Byagowi7250ade2020-05-29 12:34:30 +04309
10IGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss',
11 '__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__',
Khaled Hosnyd56afb72021-07-13 00:56:54 +020012 '__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path',
13 'lprofDirMode', 'reset_fn_list'])
Ebrahim Byagowi7250ade2020-05-29 12:34:30 +043014
Behdad Esfahbod13c6ad92021-06-12 11:00:19 -060015nm = os.getenv ('NM', shutil.which ('nm'))
Ebrahim Byagowi7250ade2020-05-29 12:34:30 +043016if not nm:
17 print ('check-symbols.py: \'nm\' not found; skipping test')
18 sys.exit (77)
19
20cxxflit = shutil.which ('c++filt')
21
22tested = False
23stat = 0
24
25for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject']:
26 for suffix in ['so', 'dylib']:
27 so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix))
28 if not os.path.exists (so): continue
29
30 # On macOS, C symbols are prefixed with _
31 symprefix = '_' if suffix == 'dylib' else ''
32
33 EXPORTED_SYMBOLS = [s.split ()[2]
Behdad Esfahbod13c6ad92021-06-12 11:00:19 -060034 for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
35 if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
Ebrahim Byagowi7250ade2020-05-29 12:34:30 +043036
37 # run again c++flit also if is available
38 if cxxflit:
39 EXPORTED_SYMBOLS = subprocess.check_output (
40 [cxxflit], input='\n'.join (EXPORTED_SYMBOLS).encode ()
41 ).decode ('utf-8').splitlines ()
42
43 prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0]
44
45 print ('Checking that %s does not expose internal symbols' % so)
46 suspicious_symbols = [x for x in EXPORTED_SYMBOLS if not re.match (r'^%s(_|$)' % prefix, x)]
47 if suspicious_symbols:
48 print ('Ouch, internal symbols exposed:', suspicious_symbols)
49 stat = 1
50
51 def_path = os.path.join (builddir, soname + '.def')
52 if not os.path.exists (def_path):
53 print ('\'%s\' not found; skipping' % def_path)
54 else:
55 print ('Checking that %s has the same symbol list as %s' % (so, def_path))
56 with open (def_path, 'r', encoding='utf-8') as f: def_file = f.read ()
57 diff_result = list (difflib.context_diff (
58 def_file.splitlines (),
59 ['EXPORTS'] + [re.sub ('^%shb' % symprefix, 'hb', x) for x in EXPORTED_SYMBOLS] +
60 # cheat: copy the last line from the def file!
61 [def_file.splitlines ()[-1]]
62 ))
63
64 if diff_result:
65 print ('\n'.join (diff_result))
66 stat = 1
67
68 tested = True
69
70if not tested:
Khaled Hosnyd56afb72021-07-13 00:56:54 +020071 print ('check-symbols.py: no shared libraries found; skipping test')
Ebrahim Byagowi7250ade2020-05-29 12:34:30 +043072 sys.exit (77)
73
74sys.exit (stat)