1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
#!/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 argparse
import xml.etree.ElementTree as ET
XMLNS = "{http://www.gtk.org/introspection/core/1.0}"
XMLNS_C = "{http://www.gtk.org/introspection/c/1.0}"
def parse_version(ver):
return tuple(map(int, ver.split(".")))
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 = {}
self.overrides = {}
def _add_node(self, node):
identifier = node.attrib[XMLNS_C + "identifier"]
introspectable = int(node.get("introspectable", 1))
version = node.get("version", None)
if introspectable and not version:
print("No version for", identifier)
sys.exit(1)
if not version:
return None
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
# 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 parse_version(version_tmp) < parse_version(
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 parse_version(version_tmp) < parse_version(
version_lowest
):
version_lowest = version_tmp
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"]
# finally add the get_type symbol
version = self.overrides.get(type_name, version_lowest)
if version:
self.releases[version].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__":
parser = argparse.ArgumentParser()
parser.add_argument(
"-r", "--override", action="append", nargs=2, metavar=("symbol", "version")
)
args, argv = parser.parse_known_args()
if len(argv) != 3:
usage(1)
ld = LdVersionScript(library_name=argv[0])
if args.override:
for override_symbol, override_version in args.override:
ld.overrides[override_symbol] = override_version
ld.import_gir(argv[1])
open(argv[2], "w").write(ld.render())
|