From 9b2453c72bc839b3b6f1053a5d35f8d340ba2c0c Mon Sep 17 00:00:00 2001 From: Karolina Surma Date: Tue, 13 Jan 2026 12:25:49 +0100 Subject: [PATCH] Explicitly Require expat >= 2.7.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves: RHEL-138666 Co-authored-by: Miro Hrončok --- expat-requires.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++ python3.14.spec | 29 ++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100755 expat-requires.py diff --git a/expat-requires.py b/expat-requires.py new file mode 100755 index 0000000..fe23fa9 --- /dev/null +++ b/expat-requires.py @@ -0,0 +1,50 @@ +import pathlib +import pyexpat +import sys + + +# This will determine the version of currently installed expat +EXPAT_VERSION = pyexpat.EXPAT_VERSION.removeprefix('expat_') +MAJOR, MINOR, PATCH = (int(i) for i in EXPAT_VERSION.split('.')) +EXPAT_COMBINED_VERSION = 10000*MAJOR + 100*MINOR + PATCH + +# For the listed files, we find all XML_COMBINED_VERSION-based #ifs +SRC = pathlib.Path.cwd() +SOURCES = [ + SRC / 'Modules/pyexpat.c', + SRC / 'Modules/clinic/pyexpat.c.h', +] +versions = set() +for source in SOURCES: + for line in source.read_text().splitlines(): + if 'XML_COMBINED_VERSION' not in line: + continue + words = line.split() + if words[0] == '#define': + continue + if len(words) != 4: + continue + if words[0] not in ('#if', '#elif'): + continue + if words[1].startswith('(') and words[-1].endswith(')'): + words[1] = words[1][1:] + words[-1] = words[-1][:-1] + if words[1] == 'XML_COMBINED_VERSION': + version = int(words[3]) + if words[2] == '>': + versions.add(version+1) + continue + if words[2] == '>=': + versions.add(version) + continue + raise ValueError( + 'Unknown line with XML_COMBINED_VERSION, adjust this script:\n\n' + f'{line}' + ) + +# We need the highest satisfiable version used in the #ifs, in x.y.z notation +v = max({v for v in versions if v <= EXPAT_COMBINED_VERSION}) +major, minor_patch = divmod(v, 10000) +minor, patch = divmod(minor_patch, 100) +print(f"{major}.{minor}.{patch}") + diff --git a/python3.14.spec b/python3.14.spec index 24a5069..3afd6ec 100644 --- a/python3.14.spec +++ b/python3.14.spec @@ -49,7 +49,7 @@ URL: https://www.python.org/ #global prerel ... %global upstream_version %{general_version}%{?prerel} Version: %{general_version}%{?prerel:~%{prerel}} -Release: 1%{?dist} +Release: 2%{?dist} License: Python-2.0.1 @@ -341,6 +341,9 @@ Source0: %{url}ftp/python/%{general_version}/Python-%{upstream_version}.tar.xz # Originally written by bkabrda Source8: check-pyc-timestamps.py +# A script that determines the required expat version +Source9: expat-requires.py + # Desktop menu entry for idle3 Source10: idle3.desktop @@ -572,6 +575,20 @@ Recommends: (%{pkgname}-tkinter%{?_isa} if tk%{?_isa}) # The zoneinfo module needs tzdata Requires: tzdata +# The requirement on libexpat is generated, but we need to version it. +# When built with a specific expat version, but installed with an older one, +# we sometimes get: +# ImportError: /usr/lib64/python3.X/lib-dynload/pyexpat.cpython-....so: +# undefined symbol: XML_... +# The pyexpat module has build-time checks for expat version to only use the +# available symbols. However, there is no runtime protection, so when the module +# is later installed with an older expat, it may error due to undefined symbols. +# This breaks many things, including python -m venv. +# We avoid this problem by requiring expat equal or greater than the latest known +# version which introduced new symbols used by Python. +# Other subpackages (like -debug) also need this, but they all depend on -libs. +%global expat_min_version 2.7.2 +Requires: expat%{?_isa} >= %{expat_min_version} %description -n %{pkgname}-libs This package contains runtime libraries for use by Python: @@ -769,6 +786,7 @@ License: %{libs_license} AND Apache-2.0 AND ISC AND LGPL-2.1-only AND MPL-2.0 AN # See the comments in the definition of main -libs subpackage for detailed explanations Provides: bundled(mimalloc) = 2.12 Requires: tzdata +Requires: expat%{?_isa} >= %{expat_min_version} # There are files in the standard library that have python shebang. # We've filtered the automatic requirement out so libs are installable without @@ -1395,6 +1413,12 @@ for Module in %{buildroot}/%{dynload_dir}/*.so ; do esac done +# Check the expat compatibility +expat_found=$(LD_LIBRARY_PATH="%{buildroot}%{_libdir}" PYTHONPATH="%{buildroot}%{pylibdir}" %{buildroot}%{_bindir}/python%{pybasever} %{SOURCE9}) +if [ "${expat_found}" != "%{expat_min_version}" ]; then + echo "Found expat version is different than the declared one, found: ${expat_found}" ; exit 1 +fi + # ====================================================== # Running the upstream test suite @@ -1937,6 +1961,9 @@ CheckPython freethreading # ====================================================== %changelog +* Mon Jan 12 2026 Karolina Surma - 3.14.2-2 +- Explicitly require expat >= 2.7.2 + * Fri Dec 05 2025 Miro Hrončok - 3.14.2-1 - Update to Python 3.14.2