# functions for handling ABI checking of libraries
-import Options, Utils, os, Logs, samba_utils, sys, Task, fnmatch, re, Build
-from TaskGen import feature, before, after
+import os
+import sys
+import re
+import fnmatch
+
+from waflib import Options, Utils, Logs, Task, Build, Errors
+from waflib.TaskGen import feature, before, after
+import samba_utils
# these type maps cope with platform specific names for common types
# please add new type mappings into the list below
def normalise_signature(sig):
'''normalise a signature from gdb'''
sig = sig.strip()
- sig = re.sub('^\$[0-9]+\s=\s\{*', '', sig)
- sig = re.sub('\}(\s0x[0-9a-f]+\s<\w+>)?$', '', sig)
+ sig = re.sub('^\$[0-9]+\s=\s\{(.+)\}$', r'\1', sig)
+ sig = re.sub('^\$[0-9]+\s=\s\{(.+)\}(\s0x[0-9a-f]+\s<\w+>)+$', r'\1', sig)
+ sig = re.sub('^\$[0-9]+\s=\s(0x[0-9a-f]+)\s?(<\w+>)?$', r'\1', sig)
sig = re.sub('0x[0-9a-f]+', '0xXXXX', sig)
sig = re.sub('", <incomplete sequence (\\\\[a-z0-9]+)>', r'\1"', sig)
sa = s.split(':')
if abi_match:
matched = False
+ negative = False
for p in abi_match:
if p[0] == '!' and fnmatch.fnmatch(sa[0], p[1:]):
+ negative = True
break
elif fnmatch.fnmatch(sa[0], p):
matched = True
break
- if not matched:
+ if (not matched) and negative:
continue
Logs.debug("%s -> %s" % (sa[1], normalise_signature(sa[1])))
ret[sa[0]] = normalise_signature(sa[1])
old_sigs = samba_utils.load_file(sig_file)
if old_sigs is None or Options.options.ABI_UPDATE:
if not save_sigs(sig_file, parsed_sigs):
- raise Utils.WafError('Failed to save ABI file "%s"' % sig_file)
+ raise Errors.WafError('Failed to save ABI file "%s"' % sig_file)
Logs.warn('Generated ABI signatures %s' % sig_file)
return
got_error = True
if got_error:
- raise Utils.WafError('ABI for %s has changed - please fix library version then build with --abi-update\nSee http://wiki.samba.org/index.php/Waf#ABI_Checking for more information' % libname)
+ raise Errors.WafError('ABI for %s has changed - please fix library version then build with --abi-update\nSee http://wiki.samba.org/index.php/Waf#ABI_Checking for more information\nIf you have not changed any ABI, and your platform always gives this error, please configure with --abi-check-disable to skip this check' % libname)
-t = Task.task_type_from_func('abi_check', abi_check_task, color='BLUE', ext_in='.bin')
+t = Task.task_factory('abi_check', abi_check_task, color='BLUE', ext_in='.bin')
t.quiet = True
# allow "waf --abi-check" to force re-checking the ABI
if '--abi-check' in sys.argv:
- Task.always_run(t)
+ t.always_run = True
@after('apply_link')
@feature('abi_check')
topsrc = self.bld.srcnode.abspath()
abi_gen = os.path.join(topsrc, 'buildtools/scripts/abi_gen.sh')
- abi_file = "%s/%s-%s.sigs" % (self.abi_directory, self.name, self.vnum)
+ abi_file = "%s/%s-%s.sigs" % (self.abi_directory, self.version_libname,
+ self.vnum)
tsk = self.create_task('abi_check', self.link_task.outputs[0])
tsk.ABI_FILE = abi_file
def abi_process_file(fname, version, symmap):
'''process one ABI file, adding new symbols to the symmap'''
- f = open(fname, mode='r')
- for line in f:
+ for line in Utils.readf(fname).splitlines():
symname = line.split(":")[0]
if not symname in symmap:
symmap[symname] = version
- f.close()
-def abi_write_vscript(vscript, libname, current_version, versions, symmap, abi_match):
- '''write a vscript file for a library in --version-script format
-
- :param vscript: Path to the vscript file
+
+def abi_write_vscript(f, libname, current_version, versions, symmap, abi_match):
+ """Write a vscript file for a library in --version-script format.
+
+ :param f: File-like object to write to
:param libname: Name of the library, uppercased
:param current_version: Current version
:param versions: Versions to consider
:param symmap: Dictionary mapping symbols -> version
- :param abi_match: List of symbols considered to be public in the current version
- '''
+ :param abi_match: List of symbols considered to be public in the current
+ version
+ """
invmap = {}
for s in symmap:
invmap.setdefault(symmap[s], []).append(s)
- f = open(vscript, mode='w')
last_key = ""
versions = sorted(versions, key=version_key)
for k in versions:
if symver == current_version:
break
f.write("%s {\n" % symver)
- if k in invmap:
- f.write("\tglobal: \n")
+ if k in sorted(invmap.keys()):
+ f.write("\tglobal:\n")
for s in invmap.get(k, []):
f.write("\t\t%s;\n" % s);
f.write("}%s;\n\n" % last_key)
last_key = " %s" % symver
f.write("%s {\n" % current_version)
+ local_abi = filter(lambda x: x[0] == '!', abi_match)
+ global_abi = filter(lambda x: x[0] != '!', abi_match)
f.write("\tglobal:\n")
- for x in abi_match:
- f.write("\t\t%s;\n" % x)
- if abi_match != ["*"]:
- f.write("\tlocal: *;\n")
+ if len(global_abi) > 0:
+ for x in global_abi:
+ f.write("\t\t%s;\n" % x)
+ else:
+ f.write("\t\t*;\n")
+ # Always hide symbols that must be local if exist
+ local_abi.extend(["!_end", "!__bss_start", "!_edata"])
+ f.write("\tlocal:\n")
+ for x in local_abi:
+ f.write("\t\t%s;\n" % x[1:])
+ if global_abi != ["*"]:
+ if len(global_abi) > 0:
+ f.write("\t\t*;\n")
f.write("};\n")
- f.close()
def abi_build_vscript(task):
version = basename[len(task.env.LIBNAME)+1:-len(".sigs")]
versions.append(version)
abi_process_file(fname, version, symmap)
- abi_write_vscript(tgt, task.env.LIBNAME, task.env.VERSION, versions, symmap,
- task.env.ABI_MATCH)
+ f = open(tgt, mode='w')
+ try:
+ abi_write_vscript(f, task.env.LIBNAME, task.env.VERSION, versions,
+ symmap, task.env.ABI_MATCH)
+ finally:
+ f.close()
def ABI_VSCRIPT(bld, libname, abi_directory, version, vscript, abi_match=None):
'''generate a vscript file for our public libraries'''
if abi_directory:
- source = bld.path.ant_glob('%s/%s-[0-9]*.sigs' % (abi_directory, libname))
+ source = bld.path.ant_glob('%s/%s-[0-9]*.sigs' % (abi_directory, libname), flat=True)
def abi_file_key(path):
return version_key(path[:-len(".sigs")].rsplit("-")[-1])
source = sorted(source.split(), key=abi_file_key)