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
|
#!/usr/bin/env python3
#
# SPDX-FileCopyrightText: 2025 Kienan Stewart <kstewart@efficios.com>
# SPDX-License-Identifier: GPL-2.0-only
#
"""
Generate a representation of the ABI for the built liblttng-ctl library, and
diff against the stored copy, if any.
"""
import os
import pathlib
import shutil
import subprocess
import sys
import tempfile
test_utils_import_path = pathlib.Path(__file__).absolute().parents[3] / "utils"
sys.path.append(str(test_utils_import_path))
import lttngtest
def get_machine():
p = subprocess.Popen(["gcc", "-dumpmachine"], stdout=subprocess.PIPE)
p.wait()
if p.returncode != 0:
return ""
return p.stdout.read().decode("utf-8").strip()
def test_abi_diff(tap, test_env):
if not shutil.which("abidw") or not shutil.which("abidiff"):
tap.skip("abidw and abidiff are not available")
return
if not shutil.which("gcc"):
tap.skip("gcc is not available")
return
machine = get_machine()
if not machine:
tap.skip(
"Couldn't determine machine triplet from gcc (got '{}')".format(machine)
)
return
lttngctl_path = (
pathlib.Path(test_env._project_root) / "src/lib/lttng-ctl/.libs/liblttng-ctl.so"
)
lttngctl_version = os.readlink(str(lttngctl_path)).split(".", 2)[-1]
tap.diagnostic("Discovered liblttng-ctl version '{}'".format(lttngctl_version))
abi_path = pathlib.Path(
test_env._project_root
) / "src/lib/lttng-ctl/abi_ref/{}/{}/abi.xml".format(lttngctl_version, machine)
headers_dir = pathlib.Path(test_env._project_root) / "include"
if not lttngctl_path.exists():
tap.skip("'{}' does not exist".format(str(lttngctl_path)))
return
if not abi_path.exists():
tap.skip("'{}' does not exist".format(str(abi_path)))
return
abi_tmp = tempfile.NamedTemporaryFile()
abidw_command = [
"abidw",
"--drop-undefined-syms",
"--drop-private-types",
"--headers-dir",
str(headers_dir),
str(lttngctl_path),
]
tap.diagnostic("Generation command: `{}`".format(" ".join(abidw_command)))
abidw = subprocess.Popen(
abidw_command,
stdout=abi_tmp.file,
stderr=subprocess.PIPE,
)
abidw.wait()
if abidw.returncode != 0:
tap.diagnostic(abidw.stderr.read().decode("utf-8"))
tap.fail(
"Failed to produce XML representation of current ABI, returncode '{}'".format(
abidw.returncode
)
)
return
abidiff_command = ["abidiff", str(abi_path), str(abi_tmp.name)]
tap.diagnostic("Diff command: `{}`".format(" ".join(abidiff_command)))
abidiff = subprocess.Popen(
abidiff_command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
abidiff.wait()
message = "No ABI changes detected"
success = True
if abidiff.returncode & 8 == 8:
success = False
message = "Breaking ABI changes detected"
elif abidiff.returncode & 4 == 4:
message = "ABI changes changes detected"
elif abidiff.returncode != 0:
success = False
message = "Error running abidiff, return code '{}'".format(abidiff.returncode)
tap.diagnostic("ABI diff output:\n{}".format(abidiff.stdout.read().decode("utf-8")))
tap.test(success, message)
tap = lttngtest.TapGenerator(1)
with lttngtest.test_environment(
log=tap.diagnostic, with_relayd=False, with_sessiond=False
) as test_env:
test_abi_diff(tap, test_env)
sys.exit(0 if tap.is_successful else 1)
|