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..ec1d74fda65 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,96 @@ 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 + ); + 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] fn abi3_from_old_config_file() { let implementation = PythonImplementation::CPython;