From b3c8d8d80359dfbabeaf1ece2165f8380b813d33 Mon Sep 17 00:00:00 2001 From: cyphercodes Date: Thu, 2 Jul 2026 06:40:54 +0300 Subject: [PATCH 1/2] Fix abi3t config handling before Python 3.15 --- newsfragments/6180.fixed.md | 1 + pyo3-build-config/src/impl_.rs | 119 +++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 28 deletions(-) create mode 100644 newsfragments/6180.fixed.md diff --git a/newsfragments/6180.fixed.md b/newsfragments/6180.fixed.md new file mode 100644 index 00000000000..d542a9ff0e4 --- /dev/null +++ b/newsfragments/6180.fixed.md @@ -0,0 +1 @@ +Fixed `PYO3_CONFIG_FILE` handling for free-threaded Python versions before 3.15 when `abi3t-py315` is enabled. diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 0a706fcdceb..cbec4599c05 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -102,6 +102,31 @@ fn sanitize_stable_abi_version( } } +fn stable_abi_version_for_target( + implementation: PythonImplementation, + version: PythonVersion, + abi3_version: Option, + abi3t_version: Option, + gil_disabled: bool, +) -> Option { + if matches!( + implementation, + PythonImplementation::PyPy | PythonImplementation::GraalPy + ) { + None + } else if version >= PythonVersion::PY315 { + match gil_disabled { + false => abi3t_version.or(abi3_version), + true => abi3t_version, + } + } else { + match gil_disabled { + false => abi3_version, + true => None, + } + } +} + /// Configuration needed by PyO3 to build for the correct Python implementation. /// /// The version and implementation fields correspond to the interpreter @@ -498,24 +523,13 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED")) _ => panic!("Unknown Py_GIL_DISABLED value"), }; - let stable_abi_version = if !matches!( + let stable_abi_version = stable_abi_version_for_target( implementation, - PythonImplementation::PyPy | PythonImplementation::GraalPy - ) { - if version >= PythonVersion::PY315 { - match gil_disabled { - false => abi3t_version.or(abi3_version), - true => abi3t_version, - } - } else { - match gil_disabled { - false => abi3_version, - true => None, - } - } - } else { - None - }; + version, + abi3_version, + abi3t_version, + gil_disabled, + ); let target_abi = PythonAbi::from_build_env(implementation, version, stable_abi_version, gil_disabled)?; @@ -883,20 +897,19 @@ print("gil_disabled", get_config_var("Py_GIL_DISABLED")) } fn apply_build_env(mut self) -> Result { - let abi3_version = if self.target_abi.kind.is_free_threaded() - || matches!( - self.target_abi.implementation, - PythonImplementation::PyPy | PythonImplementation::GraalPy - ) { - None - } else { - get_abi3_version() - }; + let gil_disabled = self.target_abi.kind().is_free_threaded(); + let stable_abi_version = stable_abi_version_for_target( + self.implementation, + self.version, + exact_stable_abi_version(get_abi3_version()), + exact_stable_abi_version(get_abi3t_version()), + gil_disabled, + ); self.target_abi = PythonAbi::from_build_env( self.implementation, self.version, - exact_stable_abi_version(abi3_version.or(get_abi3t_version())), - self.target_abi.kind().is_free_threaded(), + stable_abi_version, + gil_disabled, )?; Ok(self) } @@ -2797,6 +2810,56 @@ mod tests { ); } + #[test] + fn stable_abi_version_for_target_matches_abi_support() { + let abi3_version = Some(PythonVersion::PY310); + let abi3t_version = Some(PythonVersion::PY315); + + // A free-threaded 3.14 config from PYO3_CONFIG_FILE must remain + // version-specific, even when an abi3t-py315 feature is enabled. + assert_eq!( + stable_abi_version_for_target( + PythonImplementation::CPython, + PythonVersion::PY314, + abi3_version, + abi3t_version, + true, + ), + None + ); + + assert_eq!( + stable_abi_version_for_target( + PythonImplementation::CPython, + PythonVersion::PY314, + abi3_version, + abi3t_version, + false, + ), + abi3_version + ); + assert_eq!( + stable_abi_version_for_target( + PythonImplementation::CPython, + PythonVersion::PY315, + abi3_version, + abi3t_version, + true, + ), + abi3t_version + ); + assert_eq!( + stable_abi_version_for_target( + PythonImplementation::CPython, + PythonVersion::PY315, + abi3_version, + abi3t_version, + false, + ), + abi3t_version + ); + } + #[test] fn abi3_from_old_config_file() { let implementation = PythonImplementation::CPython; From 7474d1340180093e026cc158bfd3ba5958740023 Mon Sep 17 00:00:00 2001 From: cyphercodes Date: Thu, 2 Jul 2026 09:31:53 +0300 Subject: [PATCH 2/2] Add stable ABI target coverage cases --- pyo3-build-config/src/impl_.rs | 40 ++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index cbec4599c05..ec1d74fda65 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -2858,6 +2858,46 @@ mod tests { ), abi3t_version ); + assert_eq!( + stable_abi_version_for_target( + PythonImplementation::CPython, + PythonVersion::PY315, + abi3_version, + None, + true, + ), + None + ); + assert_eq!( + stable_abi_version_for_target( + PythonImplementation::CPython, + PythonVersion::PY315, + abi3_version, + None, + false, + ), + abi3_version + ); + assert_eq!( + stable_abi_version_for_target( + PythonImplementation::PyPy, + PythonVersion::PY315, + abi3_version, + abi3t_version, + false, + ), + None + ); + assert_eq!( + stable_abi_version_for_target( + PythonImplementation::GraalPy, + PythonVersion::PY315, + abi3_version, + abi3t_version, + false, + ), + None + ); } #[test]