Skip to content
Snippets Groups Projects
Commit 8b72f7d9 authored by Dylan Aïssi's avatar Dylan Aïssi
Browse files

apertis-abi-compare: support packages providing multiple libraries


Signed-off-by: default avatarDylan Aïssi <dylan.aissi@collabora.com>
parent f9097b9f
No related branches found
No related tags found
3 merge requests!44Merge changes from apertis/v2022-updates into apertis/v2022,!38Backport v2022-updates <- v2023pre: Improvement ABI checker script,!30Improve apertis-abi-compare tool
......@@ -15,7 +15,6 @@ on the files installed.
apertis-abi-compare takes as input only a path to a folder containing .deb and
a .dsc files. It will download from apt repository the previous version to
compare ABI/API.
Currently, apertis-abi-compare only handles single library packages.
"""
import argparse
......@@ -46,65 +45,62 @@ def clean_build_deps(builddeps):
def define_xml(pkgs_path, version):
xml_descr = list(pathlib.Path(pkgs_path).glob('**/abi-descriptor.xml'))
xml_descr = list(pathlib.Path(pkgs_path).glob('**/*-abi-descriptor.xml'))
if xml_descr:
if len(xml_descr) > 1:
sys.exit('ERROR: several abi-descriptor.xml detected!\n' +
'ERROR: apertis-abi-compare only works with single library packages')
else:
xml_descr = xml_descr[0]
print(f'INFO: Using XML descriptor: {xml_descr}')
xml_data = xml_descr.read_text()
for x in xml_descr:
print(f'INFO: XML descriptor detected: {x}')
xml_data = x.read_text()
xml_data = xml_data.replace('${VER}', version)
xml_data = xml_data.replace('${PATH}', xml_descr.parts[0])
xml_descr.write_text(xml_data)
xml_data = xml_data.replace('${PATH}', x.parts[0])
x.write_text(xml_data)
else:
print('WARNING: XML descriptor not found')
print('WARNING: Trying to generate an XML descriptor')
xml_descr = os.path.join(pkgs_path, 'autogen_xml_descriptor.xml')
my_headers = list(pathlib.Path(pkgs_path).glob('usr/include/**/*.h'))
my_headers = list(map(str, my_headers))
my_headers = sorted(my_headers)
my_libs = list(pathlib.Path(pkgs_path).glob('**/*.so'))
my_libs = list(map(str, my_libs))
my_libs = sorted(my_libs)
generate_xml(xml_descr, version, my_headers, my_libs)
print(f'INFO: XML descriptor generated: {xml_descr}')
for idx, my_lib in enumerate(my_libs):
xml_gen = os.path.join(pkgs_path, f'autogen_xml_descriptor_{idx}.xml')
my_headers = list(pathlib.Path(pkgs_path).glob('usr/include/**/*.h'))
my_headers = list(map(str, my_headers))
my_headers = sorted(my_headers)
generate_xml(xml_gen, version, my_headers, my_lib)
print(f'INFO: XML descriptor generated: {xml_gen}')
xml_descr.append(xml_gen)
list_lib_names = detect_libnames(pkgs_path)
return xml_descr
return xml_descr, list_lib_names
def generate_xml(xml, version, headers, libs):
def generate_xml(xml, version, headers, lib):
print(f'INFO: Generating {xml}...')
root = ET.Element("ABI_Descriptor")
ET.SubElement(root, "version").text = '\n'+version+'\n'
ET.SubElement(root, "headers").text = '\n'+'\n'.join(headers)+'\n'
ET.SubElement(root, "libs").text = '\n'+'\n'.join(libs)+'\n'
ET.SubElement(root, "libs").text = '\n'+lib+'\n'
tree = ET.ElementTree(root)
ET.indent(tree, space="")
tree.write(xml, encoding="utf-8")
def detect_libname(path):
def detect_libnames(path):
my_lib = list(pathlib.Path(path).glob('**/*.so'))
if len(my_lib) > 1:
print('WARNING: several libraries detected!\n' +
'WARNING: only the first one will be analyzed.')
else:
print('INFO: one library detected!')
my_lib = sorted(my_lib)[0]
my_lib = my_lib.name
my_lib = my_lib.removeprefix("lib").removesuffix(".so")
my_lib = [i.name for i in my_lib]
my_lib = [i.removeprefix("lib") for i in my_lib]
my_lib = [i.removesuffix(".so") for i in my_lib]
return my_lib
def run_abi_checker(lib, xml_old, ver_old, xml_new, ver_new):
print(f'INFO: Running abi-compliance-checker to compare {lib}:')
print(f'INFO: - {ver_old} {xml_old}')
print(f'INFO: - {ver_new} {xml_new}')
print('######################################################')
print(f'INFO: Running abi-compliance-checker to compare lib{lib}.so:')
print(f'INFO: - {ver_old}')
print(f'INFO: -- {xml_old}')
print(f'INFO: - {ver_new}')
print(f'INFO: -- {xml_new}')
print('######################################################')
acc_process = subprocess.run(['/usr/bin/abi-compliance-checker', '-lib', lib,
'-old', xml_old, '-v1', ver_old,
'-new', xml_new, '-v2', ver_new])
......@@ -112,8 +108,32 @@ def run_abi_checker(lib, xml_old, ver_old, xml_new, ver_new):
print('INFO: no ABI breakage detected!')
elif acc_process.returncode == 1:
print('WARNING: ABI breakage detected!')
sys.exit(acc_process.returncode)
return acc_process.returncode
def abi_checker(lib_names_old, xml_descr_old, my_old_ver, lib_names_new, xml_descr_new, my_new_ver):
acc_returncode = 0
for lib in lib_names_new:
my_lib = 'lib'+lib+'.so'
if lib in lib_names_old:
print(f'INFO: {my_lib} detected in both versions')
for xml in xml_descr_new:
xml_data = pathlib.Path(xml).read_text()
if my_lib in xml_data:
xml_new = xml
break
for xml in xml_descr_old:
xml_data = pathlib.Path(xml).read_text()
if my_lib in xml_data:
xml_old = xml
break
rac_returncode = run_abi_checker(lib, xml_old, my_old_ver, xml_new, my_new_ver)
if rac_returncode != 0:
acc_returncode = rac_returncode
else:
print(f'INFO: {my_lib} is not in the old package, no need to run abi-compliance-checker')
return acc_returncode
def main():
parser = argparse.ArgumentParser(
......@@ -171,13 +191,15 @@ def main():
# Extract debs of old version
extract_debs(folder_old_bin, 'pkg_old_extracted')
# Check in xml descriptor is available otherwise generate one
xml_descr_old = define_xml('pkg_old_extracted', my_old_ver)
xml_descr_new = define_xml('pkg_new_extracted', my_new_ver)
# Check if xml descriptor is available otherwise generate one
xml_descr_old, lib_names_old = define_xml('pkg_old_extracted', my_old_ver)
xml_descr_new, lib_names_new = define_xml('pkg_new_extracted', my_new_ver)
lib = detect_libname('pkg_new_extracted')
# Check if library is in both the new and the old packages before running it
acc_returncode = abi_checker(lib_names_old, xml_descr_old, my_old_ver,
lib_names_new, xml_descr_new, my_new_ver)
run_abi_checker(lib, xml_descr_old, my_old_ver, xml_descr_new, my_new_ver)
sys.exit(acc_returncode)
if __name__ == '__main__':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment