1*2d1272b8SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*2d1272b8SAndroid Build Coastguard Worker 3*2d1272b8SAndroid Build Coastguard Workerimport sys, os, shutil, subprocess, re, difflib 4*2d1272b8SAndroid Build Coastguard Worker 5*2d1272b8SAndroid Build Coastguard Workeros.environ['LC_ALL'] = 'C' # otherwise 'nm' prints in wrong order 6*2d1272b8SAndroid Build Coastguard Worker 7*2d1272b8SAndroid Build Coastguard Workerbuilddir = os.getenv ('builddir', os.path.dirname (__file__)) 8*2d1272b8SAndroid Build Coastguard Workerlibs = os.getenv ('libs', '.libs') 9*2d1272b8SAndroid Build Coastguard Worker 10*2d1272b8SAndroid Build Coastguard WorkerIGNORED_SYMBOLS = '|'.join(['_fini', '_init', '_fdata', '_ftext', '_fbss', 11*2d1272b8SAndroid Build Coastguard Worker '__bss_start', '__bss_start__', '__bss_end__', '_edata', '_end', '_bss_end__', 12*2d1272b8SAndroid Build Coastguard Worker '__end__', '__gcov_.*', 'llvm_.*', 'flush_fn_list', 'writeout_fn_list', 'mangle_path', 13*2d1272b8SAndroid Build Coastguard Worker 'lprofDirMode', 'reset_fn_list']) 14*2d1272b8SAndroid Build Coastguard Worker 15*2d1272b8SAndroid Build Coastguard Workernm = os.getenv ('NM', shutil.which ('nm')) 16*2d1272b8SAndroid Build Coastguard Workerif not nm: 17*2d1272b8SAndroid Build Coastguard Worker print ('check-symbols.py: \'nm\' not found; skipping test') 18*2d1272b8SAndroid Build Coastguard Worker sys.exit (77) 19*2d1272b8SAndroid Build Coastguard Worker 20*2d1272b8SAndroid Build Coastguard Workercxxfilt = shutil.which ('c++filt') 21*2d1272b8SAndroid Build Coastguard Worker 22*2d1272b8SAndroid Build Coastguard Workertested = False 23*2d1272b8SAndroid Build Coastguard Workerstat = 0 24*2d1272b8SAndroid Build Coastguard Worker 25*2d1272b8SAndroid Build Coastguard Workerfor soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject', 'harfbuzz-cairo']: 26*2d1272b8SAndroid Build Coastguard Worker for suffix in ['so', 'dylib']: 27*2d1272b8SAndroid Build Coastguard Worker so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix)) 28*2d1272b8SAndroid Build Coastguard Worker if not os.path.exists (so): continue 29*2d1272b8SAndroid Build Coastguard Worker 30*2d1272b8SAndroid Build Coastguard Worker # On macOS, C symbols are prefixed with _ 31*2d1272b8SAndroid Build Coastguard Worker symprefix = '_' if suffix == 'dylib' else '' 32*2d1272b8SAndroid Build Coastguard Worker 33*2d1272b8SAndroid Build Coastguard Worker EXPORTED_SYMBOLS = [s.split ()[2] 34*2d1272b8SAndroid Build Coastguard Worker for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE) 35*2d1272b8SAndroid Build Coastguard Worker if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)] 36*2d1272b8SAndroid Build Coastguard Worker 37*2d1272b8SAndroid Build Coastguard Worker # run again c++filt also if is available 38*2d1272b8SAndroid Build Coastguard Worker if cxxfilt: 39*2d1272b8SAndroid Build Coastguard Worker EXPORTED_SYMBOLS = subprocess.check_output ( 40*2d1272b8SAndroid Build Coastguard Worker [cxxfilt], input='\n'.join (EXPORTED_SYMBOLS).encode () 41*2d1272b8SAndroid Build Coastguard Worker ).decode ('utf-8').splitlines () 42*2d1272b8SAndroid Build Coastguard Worker 43*2d1272b8SAndroid Build Coastguard Worker prefix = (symprefix + os.path.basename (so)).replace ('libharfbuzz', 'hb').replace ('-', '_').split ('.')[0] 44*2d1272b8SAndroid Build Coastguard Worker 45*2d1272b8SAndroid Build Coastguard Worker print ('Checking that %s does not expose internal symbols' % so) 46*2d1272b8SAndroid Build Coastguard Worker suspicious_symbols = [x for x in EXPORTED_SYMBOLS if not re.match (r'^%s(_|$)' % prefix, x)] 47*2d1272b8SAndroid Build Coastguard Worker if suspicious_symbols: 48*2d1272b8SAndroid Build Coastguard Worker print ('Ouch, internal symbols exposed:', suspicious_symbols) 49*2d1272b8SAndroid Build Coastguard Worker stat = 1 50*2d1272b8SAndroid Build Coastguard Worker 51*2d1272b8SAndroid Build Coastguard Worker def_path = os.path.join (builddir, soname + '.def') 52*2d1272b8SAndroid Build Coastguard Worker if not os.path.exists (def_path): 53*2d1272b8SAndroid Build Coastguard Worker print ('\'%s\' not found; skipping' % def_path) 54*2d1272b8SAndroid Build Coastguard Worker else: 55*2d1272b8SAndroid Build Coastguard Worker print ('Checking that %s has the same symbol list as %s' % (so, def_path)) 56*2d1272b8SAndroid Build Coastguard Worker with open (def_path, 'r', encoding='utf-8') as f: def_file = f.read () 57*2d1272b8SAndroid Build Coastguard Worker diff_result = list (difflib.context_diff ( 58*2d1272b8SAndroid Build Coastguard Worker def_file.splitlines (), 59*2d1272b8SAndroid Build Coastguard Worker ['EXPORTS'] + [re.sub ('^%shb' % symprefix, 'hb', x) for x in EXPORTED_SYMBOLS] + 60*2d1272b8SAndroid Build Coastguard Worker # cheat: copy the last line from the def file! 61*2d1272b8SAndroid Build Coastguard Worker [def_file.splitlines ()[-1]] 62*2d1272b8SAndroid Build Coastguard Worker )) 63*2d1272b8SAndroid Build Coastguard Worker 64*2d1272b8SAndroid Build Coastguard Worker if diff_result: 65*2d1272b8SAndroid Build Coastguard Worker print ('\n'.join (diff_result)) 66*2d1272b8SAndroid Build Coastguard Worker stat = 1 67*2d1272b8SAndroid Build Coastguard Worker 68*2d1272b8SAndroid Build Coastguard Worker tested = True 69*2d1272b8SAndroid Build Coastguard Worker 70*2d1272b8SAndroid Build Coastguard Workerif not tested: 71*2d1272b8SAndroid Build Coastguard Worker print ('check-symbols.py: no shared libraries found; skipping test') 72*2d1272b8SAndroid Build Coastguard Worker sys.exit (77) 73*2d1272b8SAndroid Build Coastguard Worker 74*2d1272b8SAndroid Build Coastguard Workersys.exit (stat) 75