Include libpython .so files into scanned files

This commit is contained in:
Lumir Balhar 2026-07-01 14:43:13 +02:00
commit 533e84657e
2 changed files with 31 additions and 15 deletions

View file

@ -30,11 +30,16 @@ if [ ${#SCAN_DIRS[@]} -eq 0 ]; then
exit 1
fi
SCAN_ARGS=("${SCAN_DIRS[@]}")
for f in /usr/lib64/libpython${PYVER}*.so.*; do
[[ -f "$f" && ! -L "$f" ]] && SCAN_ARGS+=("$f")
done
WORK_DIR=$(mktemp -d)
trap 'rm -rf "$WORK_DIR"' EXIT
echo "=== Collecting PR build symbols ==="
python${PYVER} "$SCRIPT_DIR/collect_symbols.py" "${SCAN_DIRS[@]}" > "$WORK_DIR/new.json"
python${PYVER} "$SCRIPT_DIR/collect_symbols.py" "${SCAN_ARGS[@]}" > "$WORK_DIR/new.json"
# Downgrade to the latest stable version in the distribution repos.
# If no older version is available, there is nothing to compare against → skip.
@ -60,7 +65,7 @@ fi
echo ""
echo "=== Collecting stable version symbols ==="
python${PYVER} "$SCRIPT_DIR/collect_symbols.py" "${SCAN_DIRS[@]}" > "$WORK_DIR/old.json"
python${PYVER} "$SCRIPT_DIR/collect_symbols.py" "${SCAN_ARGS[@]}" > "$WORK_DIR/old.json"
echo ""
echo "=== Comparing PR build against stable ==="

View file

@ -1,11 +1,14 @@
#!/usr/bin/env python3
"""
Collect undefined non-boring external symbols from compiled Python extension modules.
Collect undefined non-boring external symbols from compiled Python extension modules
and libpython shared libraries.
Usage: collect_symbols.py <directory> [<directory>...]
Usage: collect_symbols.py <path> [<path>...]
Scans all *.cpython-*.so files found recursively, unions symbols across all
variants of each module (regular/debug/freethreading), and prints JSON to stdout.
Each path may be a directory (scanned recursively for *.cpython-*.so) or a file
(scanned directly; intended for libpython*.so.* passed explicitly from the caller).
Symbols are unioned across all variants of each module (regular/debug/freethreading),
and the result is printed as JSON to stdout.
"""
import json
@ -24,9 +27,11 @@ BORING = re.compile(
def module_name(so: Path) -> str:
# Strip ABI tag (d=debug, t=freethreading, td=both) so variants of the same
# module merge together: _ssl.cpython-314td-x86_64-linux-gnu.so → _ssl
return re.sub(r"\.cpython-\d+[a-z]*-[^.]+\.so$", "", so.name)
# _ssl.cpython-314td-x86_64-linux-gnu.so → _ssl
if m := re.match(r"(.+?)\.cpython-", so.name):
return m.group(1)
# libpython3.14.so.1.0 → libpython3.14
return re.sub(r"\.so.*$", "", so.name)
def external_symbols(so: Path) -> list[str]:
@ -42,12 +47,18 @@ def external_symbols(so: Path) -> list[str]:
modules: dict[str, set[str]] = {}
for path_arg in sys.argv[1:]:
print(f"Scanning: {path_arg}", file=sys.stderr)
for so in sorted(Path(path_arg).rglob("*.cpython-*.so")):
if so.is_symlink():
continue
if syms := external_symbols(so):
modules.setdefault(module_name(so), set()).update(syms)
p = Path(path_arg)
if p.is_file():
print(f"Scanning: {p.name}", file=sys.stderr)
if syms := external_symbols(p):
modules.setdefault(module_name(p), set()).update(syms)
else:
print(f"Scanning: {path_arg}", file=sys.stderr)
for so in sorted(p.rglob("*.cpython-*.so")):
if so.is_symlink():
continue
if syms := external_symbols(so):
modules.setdefault(module_name(so), set()).update(syms)
total_symbols = sum(len(v) for v in modules.values())
print(f"Found {len(modules)} modules, {total_symbols} tracked symbols", file=sys.stderr)