scripts: include function versions in API definition

In order to auto-generate more of the language binding code, it is
desirable to know what libvirt version an API was introduced in.
We can extract this information from the .syms files and expose
it in the API description

eg instead of

  <function name='virNodeNumOfDevices' file='libvirt-nodedev'
            module='libvirt-nodedev'>

we now have

  <function name='virNodeNumOfDevices' file='libvirt-nodedev'
            module='libvirt-nodedev' version='0.5.0'>

This will benefit this proposal:

  https://gitlab.com/libvirt/libvirt-go-module/-/merge_requests/7

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Tested-by: Victor Toso <victortoso@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2021-09-23 11:40:01 +01:00
parent 4a6d874946
commit e0e0bf6628

View File

@ -2030,8 +2030,9 @@ class CParser:
class docBuilder: class docBuilder:
"""A documentation builder""" """A documentation builder"""
def __init__(self, name, path='.', directories=['.'], includes=[]): def __init__(self, name, syms, path='.', directories=['.'], includes=[]):
self.name = name self.name = name
self.syms = syms
self.path = path self.path = path
self.directories = directories self.directories = directories
if name == "libvirt": if name == "libvirt":
@ -2044,6 +2045,7 @@ class docBuilder:
self.includes = includes + list(admin_included_files.keys()) self.includes = includes + list(admin_included_files.keys())
self.modules = {} self.modules = {}
self.headers = {} self.headers = {}
self.versions = {}
self.idx = index() self.idx = index()
self.xref = {} self.xref = {}
self.index = {} self.index = {}
@ -2114,6 +2116,44 @@ class docBuilder:
self.modules[module] = idx self.modules[module] = idx
self.idx.merge_public(idx) self.idx.merge_public(idx)
def scanVersions(self):
prefix = self.name.upper().replace("-", "_") + "_"
version = None
prevversion = None
with open(self.syms, "r") as syms:
while True:
line = syms.readline()
if not line:
break
line = line.strip()
if line.startswith("#"):
continue
if line == "":
continue
if line.startswith(prefix) and line.endswith(" {"):
version = line[len(prefix):-2]
elif line == "global:":
continue
elif line == "local:":
continue
elif line.startswith("}"):
if prevversion is None:
if line != "};":
raise Exception("Unexpected closing version")
else:
if line != ("} %s%s;" % (prefix, prevversion)):
raise Exception("Unexpected end of version '%s': %s'" % (line, "} " + prefix + version))
prevversion = version
version = None
elif line.endswith(";") and version is not None:
func = line[:-1]
self.versions[func] = version
else:
raise Exception("Unexpected line in syms file: %s" % line)
def scan(self): def scan(self):
for directory in self.directories: for directory in self.directories:
files = glob.glob(directory + "/*.c") files = glob.glob(directory + "/*.c")
@ -2136,6 +2176,7 @@ class docBuilder:
self.headers[file] = None self.headers[file] = None
self.scanHeaders() self.scanHeaders()
self.scanModules() self.scanModules()
self.scanVersions()
def modulename_file(self, file): def modulename_file(self, file):
module = os.path.basename(file) module = os.path.basename(file)
@ -2275,7 +2316,15 @@ class docBuilder:
print("=>", id) print("=>", id)
# NB: this is consumed by a regex in 'getAPIFilenames' in hvsupport.pl # NB: this is consumed by a regex in 'getAPIFilenames' in hvsupport.pl
output.write(" <%s name='%s' file='%s' module='%s'>\n" % (id.type, if id.type == "function":
ver = self.versions[name]
if ver is None:
raise Exception("Missing version for '%s'" % name)
output.write(" <function name='%s' file='%s' module='%s' version='%s'>\n" % (
name, self.modulename_file(id.header),
self.modulename_file(id.module), self.versions[name]))
else:
output.write(" <functype name='%s' file='%s' module='%s'>\n" % (
name, self.modulename_file(id.header), name, self.modulename_file(id.header),
self.modulename_file(id.module))) self.modulename_file(id.module)))
# #
@ -2406,9 +2455,16 @@ class app:
print(msg) print(msg)
def rebuild(self, name, srcdir, builddir): def rebuild(self, name, srcdir, builddir):
if name not in ["libvirt", "libvirt-qemu", "libvirt-lxc", "libvirt-admin"]: syms = {
"libvirt": srcdir + "/../src/libvirt_public.syms",
"libvirt-qemu": srcdir + "/../src/libvirt_qemu.syms",
"libvirt-lxc": srcdir + "/../src/libvirt_lxc.syms",
"libvirt-admin": srcdir + "/../src/admin/libvirt_admin_public.syms",
}
if name not in syms:
self.warning("rebuild() failed, unknown module %s" % name) self.warning("rebuild() failed, unknown module %s" % name)
return None return None
builder = None builder = None
if glob.glob(srcdir + "/../src/libvirt.c") != []: if glob.glob(srcdir + "/../src/libvirt.c") != []:
if not quiet: if not quiet:
@ -2418,7 +2474,7 @@ class app:
srcdir + "/../src/util", srcdir + "/../src/util",
srcdir + "/../include/libvirt", srcdir + "/../include/libvirt",
builddir + "/../include/libvirt"] builddir + "/../include/libvirt"]
builder = docBuilder(name, builddir, dirs, []) builder = docBuilder(name, syms[name], builddir, dirs, [])
else: else:
self.warning("rebuild() failed, unable to guess the module") self.warning("rebuild() failed, unable to guess the module")
return None return None