build: specify -Wformat as a prerequisite of -Wformat-security
[samba.git] / buildtools / wafsamba / samba_abi.py
index c51e08c290e109a80a1c00e69fe4f93925020ded..196b468f5b35f096f34dfa6e454f38e00a84ccbe 100644 (file)
@@ -15,8 +15,9 @@ version_key = lambda x: map(int, x.split("."))
 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)
 
@@ -49,13 +50,15 @@ def parse_sigs(sigs, abi_match):
         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])
@@ -109,7 +112,7 @@ def abi_check_task(self):
             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 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\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')
@@ -134,7 +137,8 @@ def abi_check(self):
     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
@@ -144,29 +148,28 @@ def abi_check(self):
 
 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:
@@ -174,20 +177,28 @@ def abi_write_vscript(vscript, libname, current_version, versions, symmap, abi_m
         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 len(global_abi) > 0:
+        for x in global_abi:
+            f.write("\t\t%s;\n" % x)
+    else:
+        f.write("\t\t*;\n")
     if abi_match != ["*"]:
-        f.write("\tlocal: *;\n")
+        f.write("\tlocal:\n")
+        for x in local_abi:
+            f.write("\t\t%s;\n" % x[1:])
+        if len(global_abi) > 0:
+            f.write("\t\t*;\n")
     f.write("};\n")
-    f.close()
 
 
 def abi_build_vscript(task):
@@ -203,14 +214,18 @@ 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)