summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2020-02-14 15:58:26 +0000
committerRichard Hughes <richard@hughsie.com>2020-02-20 09:30:28 +0000
commit3ee71729cf44bdd6d4956a1aad47ea5214cd61f9 (patch)
tree6b517de2049b2efb3a11f075ad98e8a04e9d5f1c /contrib
parent942b3b78e0ebf97a88634928d872905eef62f27c (diff)
downloadgusb-3ee71729cf44bdd6d4956a1aad47ea5214cd61f9.tar.gz
Validate the exported symbol list during check
This is the same script used by fwupd, and would have caught both recent issues with the exported symbol versions being incorrect.
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/generate-version-script.py118
1 files changed, 118 insertions, 0 deletions
diff --git a/contrib/generate-version-script.py b/contrib/generate-version-script.py
new file mode 100755
index 0000000..408199f
--- /dev/null
+++ b/contrib/generate-version-script.py
@@ -0,0 +1,118 @@
+#!/usr/bin/python3
+# pylint: disable=invalid-name,missing-docstring
+#
+# Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
+#
+# SPDX-License-Identifier: LGPL-2.1+
+
+import sys
+import xml.etree.ElementTree as ET
+
+from pkg_resources import parse_version
+
+XMLNS = '{http://www.gtk.org/introspection/core/1.0}'
+XMLNS_C = '{http://www.gtk.org/introspection/c/1.0}'
+
+def usage(return_code):
+ """ print usage and exit with the supplied return code """
+ if return_code == 0:
+ out = sys.stdout
+ else:
+ out = sys.stderr
+ out.write("usage: %s <NAME> <INPUT> <OUTPUT>\n" % sys.argv[0])
+ sys.exit(return_code)
+
+class LdVersionScript:
+ """ Rasterize some text """
+
+ def __init__(self, library_name):
+ self.library_name = library_name
+ self.releases = {}
+
+ def _add_node(self, node):
+ identifier = node.attrib[XMLNS_C + 'identifier']
+ if 'version' not in node.attrib:
+ print('No version for', identifier)
+ sys.exit(1)
+ version = node.attrib['version']
+ if version not in self.releases:
+ self.releases[version] = []
+ release = self.releases[version]
+ if identifier not in release:
+ release.append(identifier)
+ return version
+
+ def _add_cls(self, cls):
+
+ # add all class functions
+ for node in cls.findall(XMLNS + 'function'):
+ self._add_node(node)
+
+ # choose the lowest version method for the _get_type symbol
+ version_lowest = None
+ if '{http://www.gtk.org/introspection/glib/1.0}get-type' not in cls.attrib:
+ return
+ type_name = cls.attrib['{http://www.gtk.org/introspection/glib/1.0}get-type']
+
+ # add all class methods
+ for node in cls.findall(XMLNS + 'method'):
+ version_tmp = self._add_node(node)
+ if version_tmp:
+ if not version_lowest or version_tmp < version_lowest:
+ version_lowest = version_tmp
+
+ # add the constructor
+ for node in cls.findall(XMLNS + 'constructor'):
+ version_tmp = self._add_node(node)
+ if version_tmp:
+ if not version_lowest or version_tmp < version_lowest:
+ version_lowest = version_tmp
+
+ # finally add the get_type symbol
+ if version_lowest:
+ self.releases[version_lowest].append(type_name)
+
+ def import_gir(self, filename):
+ tree = ET.parse(filename)
+ root = tree.getroot()
+ for ns in root.findall(XMLNS + 'namespace'):
+ for node in ns.findall(XMLNS + 'function'):
+ self._add_node(node)
+ for cls in ns.findall(XMLNS + 'record'):
+ self._add_cls(cls)
+ for cls in ns.findall(XMLNS + 'class'):
+ self._add_cls(cls)
+
+ def render(self):
+
+ # get a sorted list of all the versions
+ versions = []
+ for version in self.releases:
+ versions.append(version)
+
+ # output the version data to a file
+ verout = '# generated automatically, do not edit!\n'
+ oldversion = None
+ for version in sorted(versions, key=parse_version):
+ symbols = sorted(self.releases[version])
+ verout += '\n%s_%s {\n' % (self.library_name, version)
+ verout += ' global:\n'
+ for symbol in symbols:
+ verout += ' %s;\n' % symbol
+ verout += ' local: *;\n'
+ if oldversion:
+ verout += '} %s_%s;\n' % (self.library_name, oldversion)
+ else:
+ verout += '};\n'
+ oldversion = version
+ return verout
+
+if __name__ == '__main__':
+ if {'-?', '--help', '--usage'}.intersection(set(sys.argv)):
+ usage(0)
+ if len(sys.argv) != 4:
+ usage(1)
+
+ ld = LdVersionScript(library_name=sys.argv[1])
+ ld.import_gir(sys.argv[2])
+ open(sys.argv[3], 'w').write(ld.render())