From fef4336e5ffdd796ec3f971d7a6aad2182626991 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Wed, 16 Sep 2026 12:56:05 +0100 Subject: [PATCH 1/5] check static addresses match in `pyo3-ffi-check` --- pyo3-ffi-check/README.md | 2 +- pyo3-ffi-check/macro/src/lib.rs | 106 ++++++++++++++++++--- pyo3-ffi-check/src/main.rs | 25 ++++- pyo3-ffi/src/bytearrayobject.rs | 2 +- pyo3-ffi/src/bytesobject.rs | 2 +- pyo3-ffi/src/complexobject.rs | 2 +- pyo3-ffi/src/cpython/cellobject.rs | 1 + pyo3-ffi/src/cpython/funcobject.rs | 4 +- pyo3-ffi/src/cpython/pydebug.rs | 6 +- pyo3-ffi/src/cpython/pyframe.rs | 1 + pyo3-ffi/src/descrobject.rs | 14 +-- pyo3-ffi/src/dictobject.rs | 4 +- pyo3-ffi/src/enumobject.rs | 1 + pyo3-ffi/src/floatobject.rs | 2 +- pyo3-ffi/src/genericaliasobject.rs | 1 + pyo3-ffi/src/listobject.rs | 2 +- pyo3-ffi/src/memoryobject.rs | 2 +- pyo3-ffi/src/methodobject.rs | 2 +- pyo3-ffi/src/moduleobject.rs | 2 +- pyo3-ffi/src/object.rs | 6 +- pyo3-ffi/src/pycapsule.rs | 2 +- pyo3-ffi/src/pyerrors.rs | 143 +++++++++++++++-------------- pyo3-ffi/src/pylifecycle.rs | 1 + pyo3-ffi/src/rangeobject.rs | 2 +- pyo3-ffi/src/setobject.rs | 4 +- pyo3-ffi/src/sliceobject.rs | 2 +- pyo3-ffi/src/structseq.rs | 1 + pyo3-ffi/src/traceback.rs | 2 +- pyo3-ffi/src/tupleobject.rs | 2 +- pyo3-ffi/src/unicodeobject.rs | 2 +- 30 files changed, 229 insertions(+), 119 deletions(-) diff --git a/pyo3-ffi-check/README.md b/pyo3-ffi-check/README.md index ced60dceb6e..b0dba29f341 100644 --- a/pyo3-ffi-check/README.md +++ b/pyo3-ffi-check/README.md @@ -2,6 +2,6 @@ This is a simple program which compares ffi definitions from `pyo3-ffi` against those produced by `bindgen`. -If any differ in size, these are printed to stdout and a the process will exit nonzero. +It checks type layouts, function signatures, and the addresses of functions and statics. Any differences are printed to stdout and the process exits nonzero. The main purpose of this program is to be run as part of PyO3's continuous integration pipeline to catch possible errors in PyO3's ffi definitions. diff --git a/pyo3-ffi-check/macro/src/lib.rs b/pyo3-ffi-check/macro/src/lib.rs index 6a786daa1b1..f18a63bfbd4 100644 --- a/pyo3-ffi-check/macro/src/lib.rs +++ b/pyo3-ffi-check/macro/src/lib.rs @@ -19,6 +19,11 @@ const PY_3_12: PythonVersion = PythonVersion { minor: 12, }; +const PY_3_11: PythonVersion = PythonVersion { + major: 3, + minor: 11, +}; + /// Macro which expands to multiple macro calls, one per pyo3-ffi struct. #[proc_macro] pub fn for_all_structs(input: proc_macro::TokenStream) -> proc_macro::TokenStream { @@ -70,15 +75,20 @@ pub fn for_all_structs(input: proc_macro::TokenStream) -> proc_macro::TokenStrea static DOC_DIR: LazyLock = LazyLock::new(|| PathBuf::from(env::var_os("PYO3_FFI_CHECK_DOC_DIR").unwrap())); -static BINDGEN_FUNCTION_NAMES: LazyLock> = LazyLock::new(|| { - // parse all the function names from the bindgen index file +static BINDGEN_FUNCTION_NAMES: LazyLock> = + LazyLock::new(|| get_bindgen_names("fn")); + +static BINDGEN_STATIC_NAMES: LazyLock> = + LazyLock::new(|| get_bindgen_names("static")); + +fn get_bindgen_names(kind: &str) -> HashSet { + // Parse names from the bindgen index file. let index_file = DOC_DIR.join("bindgen/index.html"); - // the functions are in `a` elements with class "fn", and the full path is in the - // `title` attribute + // The full path is in the `title` attribute of each item's link. let html = fs::read_to_string(index_file).unwrap(); let html = scraper::Html::parse_document(&html); - let selector = scraper::Selector::parse("a.fn").unwrap(); + let selector = scraper::Selector::parse(&format!("a.{kind}")).unwrap(); html.select(&selector) .map(|el| { @@ -91,7 +101,81 @@ static BINDGEN_FUNCTION_NAMES: LazyLock> = LazyLock::new(|| { .to_string() }) .collect() -}); +} + +fn get_bindgen_name(name: &str, names: &HashSet) -> String { + if pyo3_build_config::get().implementation() == PythonImplementation::PyPy + && (name.starts_with("Py") || name.starts_with("_Py")) + { + let prefixed_name = name.replacen("Py", "PyPy", 1); + if names.contains(&prefixed_name) { + return prefixed_name; + } + } + name.to_owned() +} + +/// Macro which expands to multiple macro calls, one per pyo3-ffi static. +#[proc_macro] +pub fn for_all_statics(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let macro_name = match get_macro_name_from_input("for_all_statics", input) { + Ok(name) => name, + Err(err) => return err.into(), + }; + + let statics_glob = format!("{}/pyo3_ffi/static.*.html", DOC_DIR.display()); + let mut output = TokenStream::new(); + + for entry in glob::glob(&statics_glob).expect("Failed to read glob pattern") { + let entry = entry.unwrap(); + let file_name = entry.file_name().unwrap().to_string_lossy().into_owned(); + let static_name = file_name + .strip_prefix("static.") + .unwrap() + .strip_suffix(".html") + .unwrap(); + + if static_name == "PyStructSequence_UnnamedField" + && pyo3_build_config::get().target_abi().version() < PY_3_11 + { + // Not marked PyAPI_DATA (and thus not exported reliably) before Python 3.11. + // https://github.com/python/cpython/issues/88386 + continue; + } + + let is_pypy = pyo3_build_config::get().implementation() == PythonImplementation::PyPy; + if is_pypy && static_name == "PySuper_Type" { + // PyPy declares this in its headers but does not export it. + continue; + } + + // PyPy uses a macro to define these aliases as the same static; CPython has three + // separate statics + let bindgen_name = get_bindgen_name( + if is_pypy + && matches!( + static_name, + "PyExc_EnvironmentError" | "PyExc_IOError" | "PyExc_WindowsError" + ) + { + "PyExc_OSError" + } else { + static_name + }, + &BINDGEN_STATIC_NAMES, + ); + if is_pypy && !BINDGEN_STATIC_NAMES.contains(&bindgen_name) { + // As with functions, PyPy may not yet offer all of the declared symbols. + continue; + } + + let static_ident = Ident::new(static_name, Span::call_site()); + let bindgen_ident = Ident::new(&bindgen_name, Span::call_site()); + output.extend(quote!(#macro_name!(#static_ident, #bindgen_ident);)); + } + + output.into() +} /// Macro which expands to multiple macro calls, one per field in a pyo3-ffi /// struct. @@ -557,16 +641,8 @@ pub fn for_all_functions(_input: proc_macro::TokenStream) -> proc_macro::TokenSt continue; } - let mut bindgen_name = function_name.to_owned(); + let bindgen_name = get_bindgen_name(function_name, &BINDGEN_FUNCTION_NAMES); if pyo3_build_config::get().implementation() == PythonImplementation::PyPy { - // For PyPy, some functions are prefixed with "PyPy", we check whether the - // bindgen name contains the prefixed name and use that if it does. - if function_name.starts_with("Py") || function_name.starts_with("_Py") { - let prefixed_name = function_name.replacen("Py", "PyPy", 1); - if BINDGEN_FUNCTION_NAMES.contains(&prefixed_name) { - bindgen_name = prefixed_name; - } - } // If the function doesn't exist in PyPy, for now we don't care: // - For PyO3 inline functions it's probably fine to include anyway // - For extern symbols - PyPy may add them in a future release diff --git a/pyo3-ffi-check/src/main.rs b/pyo3-ffi-check/src/main.rs index 9e42045ec28..5cd0f85efeb 100644 --- a/pyo3-ffi-check/src/main.rs +++ b/pyo3-ffi-check/src/main.rs @@ -1,4 +1,7 @@ -use std::{ffi::CStr, process::exit}; +use std::{ + ffi::{c_void, CStr}, + process::exit, +}; use pyo3_ffi_check_definitions::{bindgen as bindings, pyo3_ffi}; @@ -201,6 +204,26 @@ fn main() { pyo3_ffi_check_macro::for_all_functions!(check_function); + macro_rules! check_static { + ($name:ident, $bindgen_name:ident) => {{ + #[allow(deprecated)] + let pyo3_ffi_ptr = (&raw const pyo3_ffi::$name).cast::(); + let bindgen_ptr = (&raw const bindings::$bindgen_name).cast::(); + + if pyo3_ffi_ptr != bindgen_ptr { + failed = true; + println!( + "error: static address of {} differs between pyo3_ffi ({:p}) and bindgen ({:p})", + stringify!($name), + pyo3_ffi_ptr, + bindgen_ptr + ); + } + }}; + } + + pyo3_ffi_check_macro::for_all_statics!(check_static); + if failed { exit(1); } else { diff --git a/pyo3-ffi/src/bytearrayobject.rs b/pyo3-ffi/src/bytearrayobject.rs index 9304d3ac4b4..5bce28e4512 100644 --- a/pyo3-ffi/src/bytearrayobject.rs +++ b/pyo3-ffi/src/bytearrayobject.rs @@ -4,7 +4,7 @@ use core::ffi::{c_char, c_int}; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyByteArray_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyByteArray_Type")] pub static mut PyByteArray_Type: PyTypeObject; pub static mut PyByteArrayIter_Type: PyTypeObject; diff --git a/pyo3-ffi/src/bytesobject.rs b/pyo3-ffi/src/bytesobject.rs index 12348c540f2..7e2b2ecb2cd 100644 --- a/pyo3-ffi/src/bytesobject.rs +++ b/pyo3-ffi/src/bytesobject.rs @@ -4,7 +4,7 @@ use core::ffi::{c_char, c_int}; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyBytes_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyBytes_Type")] pub static mut PyBytes_Type: PyTypeObject; pub static mut PyBytesIter_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/complexobject.rs b/pyo3-ffi/src/complexobject.rs index 88f0cfcddfc..f04dfbe7c67 100644 --- a/pyo3-ffi/src/complexobject.rs +++ b/pyo3-ffi/src/complexobject.rs @@ -3,7 +3,7 @@ use core::ffi::{c_double, c_int}; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyComplex_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyComplex_Type")] pub static mut PyComplex_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/cpython/cellobject.rs b/pyo3-ffi/src/cpython/cellobject.rs index 628bfa399af..3b9e2da484f 100644 --- a/pyo3-ffi/src/cpython/cellobject.rs +++ b/pyo3-ffi/src/cpython/cellobject.rs @@ -12,6 +12,7 @@ extern_libpython! { pub fn PyCell_New(o: *mut PyObject) -> *mut PyObject; pub fn PyCell_Get(o: *mut PyObject) -> *mut PyObject; pub fn PyCell_Set(o: *mut PyObject, val: *mut PyObject) -> c_int; + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyCell_Type")] pub static mut PyCell_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/cpython/funcobject.rs b/pyo3-ffi/src/cpython/funcobject.rs index 683a03dfc7c..5a9f49dc1ea 100644 --- a/pyo3-ffi/src/cpython/funcobject.rs +++ b/pyo3-ffi/src/cpython/funcobject.rs @@ -59,7 +59,7 @@ pub struct PyFunctionObject { } extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyFunction_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyFunction_Type")] pub static mut PyFunction_Type: crate::PyTypeObject; } @@ -143,7 +143,9 @@ pub unsafe fn PyFunction_GET_ANNOTATIONS(func: *mut PyObject) -> *mut PyObject { } extern_libpython! { + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyClassMethod_Type")] pub static mut PyClassMethod_Type: crate::PyTypeObject; + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyStaticMethod_Type")] pub static mut PyStaticMethod_Type: crate::PyTypeObject; #[cfg_attr(PyPy, link_name = "PyPyClassMethod_New")] diff --git a/pyo3-ffi/src/cpython/pydebug.rs b/pyo3-ffi/src/cpython/pydebug.rs index 389c4ea9ef3..ed6be81b6bc 100644 --- a/pyo3-ffi/src/cpython/pydebug.rs +++ b/pyo3-ffi/src/cpython/pydebug.rs @@ -9,6 +9,7 @@ extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPy_VerboseFlag")] pub static mut Py_VerboseFlag: c_int; #[deprecated(note = "Python 3.12")] + #[cfg_attr(PyPy, link_name = "PyPy_QuietFlag")] pub static mut Py_QuietFlag: c_int; #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_InteractiveFlag")] @@ -26,9 +27,6 @@ extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPy_BytesWarningFlag")] pub static mut Py_BytesWarningFlag: c_int; #[deprecated(note = "Python 3.12")] - #[cfg_attr(PyPy, link_name = "PyPy_UseClassExceptionsFlag")] - pub static mut Py_UseClassExceptionsFlag: c_int; - #[deprecated(note = "Python 3.12")] #[cfg_attr(PyPy, link_name = "PyPy_FrozenFlag")] pub static mut Py_FrozenFlag: c_int; #[deprecated(note = "Python 3.12")] @@ -41,10 +39,12 @@ extern_libpython! { #[cfg_attr(PyPy, link_name = "PyPy_NoUserSiteDirectory")] pub static mut Py_NoUserSiteDirectory: c_int; #[deprecated(note = "Python 3.12")] + #[cfg_attr(PyPy, link_name = "PyPy_UnbufferedStdioFlag")] pub static mut Py_UnbufferedStdioFlag: c_int; #[cfg_attr(PyPy, link_name = "PyPy_HashRandomizationFlag")] pub static mut Py_HashRandomizationFlag: c_int; #[deprecated(note = "Python 3.12")] + #[cfg_attr(PyPy, link_name = "PyPy_IsolatedFlag")] pub static mut Py_IsolatedFlag: c_int; #[cfg(windows)] #[deprecated(note = "Python 3.12")] diff --git a/pyo3-ffi/src/cpython/pyframe.rs b/pyo3-ffi/src/cpython/pyframe.rs index 09c64fd8d0f..e72c2265cb2 100644 --- a/pyo3-ffi/src/cpython/pyframe.rs +++ b/pyo3-ffi/src/cpython/pyframe.rs @@ -20,6 +20,7 @@ pub const PyUnstable_EXECUTABLE_KIND_METHOD_DESCRIPTOR: c_int = 4; pub const PyUnstable_EXECUTABLE_KINDS: c_int = 5; extern_libpython! { + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyFrame_Type")] pub static mut PyFrame_Type: PyTypeObject; #[cfg(Py_3_13)] diff --git a/pyo3-ffi/src/descrobject.rs b/pyo3-ffi/src/descrobject.rs index 23f8cbc272a..17ad25fabce 100644 --- a/pyo3-ffi/src/descrobject.rs +++ b/pyo3-ffi/src/descrobject.rs @@ -37,19 +37,19 @@ impl Default for PyGetSetDef { #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyClassMethodDescr_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyClassMethodDescr_Type")] pub static mut PyClassMethodDescr_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "PyPyGetSetDescr_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyGetSetDescr_Type")] pub static mut PyGetSetDescr_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "PyPyMemberDescr_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyMemberDescr_Type")] pub static mut PyMemberDescr_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "PyPyMethodDescr_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyMethodDescr_Type")] pub static mut PyMethodDescr_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "PyPyWrapperDescr_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyWrapperDescr_Type")] pub static mut PyWrapperDescr_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "PyPyDictProxy_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyDictProxy_Type")] pub static mut PyDictProxy_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "PyPyProperty_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyProperty_Type")] pub static mut PyProperty_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/dictobject.rs b/pyo3-ffi/src/dictobject.rs index 34ce94518d2..d85afa40fdf 100644 --- a/pyo3-ffi/src/dictobject.rs +++ b/pyo3-ffi/src/dictobject.rs @@ -4,7 +4,7 @@ use core::ffi::{c_char, c_int}; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyDict_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyDict_Type")] pub static mut PyDict_Type: PyTypeObject; } @@ -97,7 +97,9 @@ extern_libpython! { #[cfg(not(RustPython))] extern_libpython! { + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyDictKeys_Type")] pub static mut PyDictKeys_Type: PyTypeObject; + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyDictValues_Type")] pub static mut PyDictValues_Type: PyTypeObject; pub static mut PyDictItems_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/enumobject.rs b/pyo3-ffi/src/enumobject.rs index cd2ba09c14d..80d6686e55e 100644 --- a/pyo3-ffi/src/enumobject.rs +++ b/pyo3-ffi/src/enumobject.rs @@ -2,5 +2,6 @@ use crate::object::PyTypeObject; extern_libpython! { pub static mut PyEnum_Type: PyTypeObject; + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyReversed_Type")] pub static mut PyReversed_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/floatobject.rs b/pyo3-ffi/src/floatobject.rs index 59c43985690..e245344894e 100644 --- a/pyo3-ffi/src/floatobject.rs +++ b/pyo3-ffi/src/floatobject.rs @@ -7,7 +7,7 @@ opaque_struct!(pub PyFloatObject); extern_libpython! { #[cfg(not(RustPython))] - #[cfg_attr(PyPy, link_name = "PyPyFloat_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyFloat_Type")] pub static mut PyFloat_Type: PyTypeObject; #[cfg(RustPython)] diff --git a/pyo3-ffi/src/genericaliasobject.rs b/pyo3-ffi/src/genericaliasobject.rs index deab56be608..987cf57462e 100644 --- a/pyo3-ffi/src/genericaliasobject.rs +++ b/pyo3-ffi/src/genericaliasobject.rs @@ -7,5 +7,6 @@ extern_libpython! { pub fn Py_GenericAlias(origin: *mut PyObject, args: *mut PyObject) -> *mut PyObject; #[cfg(not(RustPython))] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPy_GenericAliasType")] pub static mut Py_GenericAliasType: PyTypeObject; } diff --git a/pyo3-ffi/src/listobject.rs b/pyo3-ffi/src/listobject.rs index 4a6526d0193..a43991dafe6 100644 --- a/pyo3-ffi/src/listobject.rs +++ b/pyo3-ffi/src/listobject.rs @@ -4,7 +4,7 @@ use core::ffi::c_int; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyList_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyList_Type")] pub static mut PyList_Type: PyTypeObject; pub static mut PyListIter_Type: PyTypeObject; pub static mut PyListRevIter_Type: PyTypeObject; diff --git a/pyo3-ffi/src/memoryobject.rs b/pyo3-ffi/src/memoryobject.rs index a78f45c58d3..35b4ac605f7 100644 --- a/pyo3-ffi/src/memoryobject.rs +++ b/pyo3-ffi/src/memoryobject.rs @@ -6,7 +6,7 @@ use core::ffi::{c_char, c_int}; extern_libpython! { #[cfg(not(RustPython))] - #[cfg_attr(PyPy, link_name = "PyPyMemoryView_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyMemoryView_Type")] pub static mut PyMemoryView_Type: PyTypeObject; #[cfg(RustPython)] diff --git a/pyo3-ffi/src/methodobject.rs b/pyo3-ffi/src/methodobject.rs index 8fe4942bda8..2b014a3e53a 100644 --- a/pyo3-ffi/src/methodobject.rs +++ b/pyo3-ffi/src/methodobject.rs @@ -19,7 +19,7 @@ pub struct PyCFunctionObject { extern_libpython! { #[cfg(not(RustPython))] - #[cfg_attr(PyPy, link_name = "PyPyCFunction_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyCFunction_Type")] pub static mut PyCFunction_Type: PyTypeObject; #[cfg(RustPython)] diff --git a/pyo3-ffi/src/moduleobject.rs b/pyo3-ffi/src/moduleobject.rs index 89ee1f301ca..5029a82d534 100644 --- a/pyo3-ffi/src/moduleobject.rs +++ b/pyo3-ffi/src/moduleobject.rs @@ -11,7 +11,7 @@ use core::ffi::{c_char, c_int, c_void}; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyModule_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyModule_Type")] pub static mut PyModule_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 06b710e68f2..64dba2f87fe 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -225,9 +225,9 @@ extern_libpython! { #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyLong_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyLong_Type")] pub static mut PyLong_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "PyPyBool_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyBool_Type")] pub static mut PyBool_Type: PyTypeObject; } @@ -420,7 +420,7 @@ pub unsafe fn PyObject_TypeCheck(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_ extern_libpython! { /// built-in 'type' #[cfg(not(RustPython))] - #[cfg_attr(PyPy, link_name = "PyPyType_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyType_Type")] pub static mut PyType_Type: PyTypeObject; /// built-in 'object' #[cfg(not(RustPython))] diff --git a/pyo3-ffi/src/pycapsule.rs b/pyo3-ffi/src/pycapsule.rs index 2cc464cbc47..b7767a568bc 100644 --- a/pyo3-ffi/src/pycapsule.rs +++ b/pyo3-ffi/src/pycapsule.rs @@ -3,7 +3,7 @@ use core::ffi::{c_char, c_int, c_void}; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyCapsule_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyCapsule_Type")] pub static mut PyCapsule_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/pyerrors.rs b/pyo3-ffi/src/pyerrors.rs index edc51310d68..ae64433b72e 100644 --- a/pyo3-ffi/src/pyerrors.rs +++ b/pyo3-ffi/src/pyerrors.rs @@ -127,154 +127,155 @@ pub unsafe fn PyUnicodeDecodeError_Create( } extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyExc_BaseException")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_BaseException")] pub static mut PyExc_BaseException: *mut PyObject; #[cfg(Py_3_11)] - #[cfg_attr(PyPy, link_name = "PyPyExc_BaseExceptionGroup")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_BaseExceptionGroup")] pub static mut PyExc_BaseExceptionGroup: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_Exception")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_Exception")] pub static mut PyExc_Exception: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_StopAsyncIteration")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_StopAsyncIteration")] pub static mut PyExc_StopAsyncIteration: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_StopIteration")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_StopIteration")] pub static mut PyExc_StopIteration: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_GeneratorExit")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_GeneratorExit")] pub static mut PyExc_GeneratorExit: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ArithmeticError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ArithmeticError")] pub static mut PyExc_ArithmeticError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_LookupError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_LookupError")] pub static mut PyExc_LookupError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_AssertionError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_AssertionError")] pub static mut PyExc_AssertionError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_AttributeError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_AttributeError")] pub static mut PyExc_AttributeError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_BufferError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_BufferError")] pub static mut PyExc_BufferError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_EOFError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_EOFError")] pub static mut PyExc_EOFError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_FloatingPointError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_FloatingPointError")] pub static mut PyExc_FloatingPointError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_OSError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_OSError")] pub static mut PyExc_OSError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ImportError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ImportError")] pub static mut PyExc_ImportError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ModuleNotFoundError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ModuleNotFoundError")] pub static mut PyExc_ModuleNotFoundError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_IndexError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_IndexError")] pub static mut PyExc_IndexError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_KeyError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_KeyError")] pub static mut PyExc_KeyError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_KeyboardInterrupt")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_KeyboardInterrupt")] pub static mut PyExc_KeyboardInterrupt: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_MemoryError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_MemoryError")] pub static mut PyExc_MemoryError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_NameError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_NameError")] pub static mut PyExc_NameError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_OverflowError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_OverflowError")] pub static mut PyExc_OverflowError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_RuntimeError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_RuntimeError")] pub static mut PyExc_RuntimeError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_RecursionError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_RecursionError")] pub static mut PyExc_RecursionError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_NotImplementedError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_NotImplementedError")] pub static mut PyExc_NotImplementedError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_SyntaxError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_SyntaxError")] pub static mut PyExc_SyntaxError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_IndentationError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_IndentationError")] pub static mut PyExc_IndentationError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_TabError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_TabError")] pub static mut PyExc_TabError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ReferenceError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ReferenceError")] pub static mut PyExc_ReferenceError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_SystemError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_SystemError")] pub static mut PyExc_SystemError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_SystemExit")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_SystemExit")] pub static mut PyExc_SystemExit: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_TypeError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_TypeError")] pub static mut PyExc_TypeError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_UnboundLocalError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_UnboundLocalError")] pub static mut PyExc_UnboundLocalError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_UnicodeError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_UnicodeError")] pub static mut PyExc_UnicodeError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_UnicodeEncodeError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_UnicodeEncodeError")] pub static mut PyExc_UnicodeEncodeError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_UnicodeDecodeError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_UnicodeDecodeError")] pub static mut PyExc_UnicodeDecodeError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_UnicodeTranslateError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_UnicodeTranslateError")] pub static mut PyExc_UnicodeTranslateError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ValueError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ValueError")] pub static mut PyExc_ValueError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ZeroDivisionError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ZeroDivisionError")] pub static mut PyExc_ZeroDivisionError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_BlockingIOError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_BlockingIOError")] pub static mut PyExc_BlockingIOError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_BrokenPipeError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_BrokenPipeError")] pub static mut PyExc_BrokenPipeError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ChildProcessError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ChildProcessError")] pub static mut PyExc_ChildProcessError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ConnectionError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ConnectionError")] pub static mut PyExc_ConnectionError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ConnectionAbortedError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ConnectionAbortedError")] pub static mut PyExc_ConnectionAbortedError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ConnectionRefusedError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ConnectionRefusedError")] pub static mut PyExc_ConnectionRefusedError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ConnectionResetError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ConnectionResetError")] pub static mut PyExc_ConnectionResetError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_FileExistsError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_FileExistsError")] pub static mut PyExc_FileExistsError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_FileNotFoundError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_FileNotFoundError")] pub static mut PyExc_FileNotFoundError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_InterruptedError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_InterruptedError")] pub static mut PyExc_InterruptedError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_IsADirectoryError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_IsADirectoryError")] pub static mut PyExc_IsADirectoryError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_NotADirectoryError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_NotADirectoryError")] pub static mut PyExc_NotADirectoryError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_PermissionError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_PermissionError")] pub static mut PyExc_PermissionError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ProcessLookupError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ProcessLookupError")] pub static mut PyExc_ProcessLookupError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_TimeoutError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_TimeoutError")] pub static mut PyExc_TimeoutError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_OSError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_OSError")] + #[cfg_attr(all(PyPy, Py_3_12), link_name = "PyExc_OSError")] pub static mut PyExc_EnvironmentError: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_OSError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_OSError")] + #[cfg_attr(all(PyPy, Py_3_12), link_name = "PyExc_OSError")] pub static mut PyExc_IOError: *mut PyObject; #[cfg(windows)] - #[cfg_attr(PyPy, link_name = "PyPyExc_OSError")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_OSError")] + #[cfg_attr(all(PyPy, Py_3_12), link_name = "PyExc_OSError")] pub static mut PyExc_WindowsError: *mut PyObject; - pub static mut PyExc_RecursionErrorInst: *mut PyObject; - /* Predefined warning categories */ - #[cfg_attr(PyPy, link_name = "PyPyExc_Warning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_Warning")] pub static mut PyExc_Warning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_UserWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_UserWarning")] pub static mut PyExc_UserWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_DeprecationWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_DeprecationWarning")] pub static mut PyExc_DeprecationWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_PendingDeprecationWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_PendingDeprecationWarning")] pub static mut PyExc_PendingDeprecationWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_SyntaxWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_SyntaxWarning")] pub static mut PyExc_SyntaxWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_RuntimeWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_RuntimeWarning")] pub static mut PyExc_RuntimeWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_FutureWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_FutureWarning")] pub static mut PyExc_FutureWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ImportWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ImportWarning")] pub static mut PyExc_ImportWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_UnicodeWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_UnicodeWarning")] pub static mut PyExc_UnicodeWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_BytesWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_BytesWarning")] pub static mut PyExc_BytesWarning: *mut PyObject; - #[cfg_attr(PyPy, link_name = "PyPyExc_ResourceWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_ResourceWarning")] pub static mut PyExc_ResourceWarning: *mut PyObject; #[cfg(Py_3_10)] - #[cfg_attr(PyPy, link_name = "PyPyExc_EncodingWarning")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_EncodingWarning")] pub static mut PyExc_EncodingWarning: *mut PyObject; } diff --git a/pyo3-ffi/src/pylifecycle.rs b/pyo3-ffi/src/pylifecycle.rs index b3bbdffab7a..84daae097cb 100644 --- a/pyo3-ffi/src/pylifecycle.rs +++ b/pyo3-ffi/src/pylifecycle.rs @@ -99,6 +99,7 @@ extern_libpython! { pub fn PyOS_setsig(arg1: c_int, arg2: PyOS_sighandler_t) -> PyOS_sighandler_t; #[cfg(Py_3_11)] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPy_Version")] pub static Py_Version: core::ffi::c_ulong; #[cfg(Py_3_13)] diff --git a/pyo3-ffi/src/rangeobject.rs b/pyo3-ffi/src/rangeobject.rs index ffecd07eb32..dd0fc3e8800 100644 --- a/pyo3-ffi/src/rangeobject.rs +++ b/pyo3-ffi/src/rangeobject.rs @@ -3,7 +3,7 @@ use core::ffi::c_int; extern_libpython! { #[cfg(not(RustPython))] - #[cfg_attr(PyPy, link_name = "PyPyRange_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyRange_Type")] pub static mut PyRange_Type: PyTypeObject; #[cfg(not(RustPython))] pub static mut PyRangeIter_Type: PyTypeObject; diff --git a/pyo3-ffi/src/setobject.rs b/pyo3-ffi/src/setobject.rs index 8b1efbb1e0a..1d204797c26 100644 --- a/pyo3-ffi/src/setobject.rs +++ b/pyo3-ffi/src/setobject.rs @@ -4,9 +4,9 @@ use core::ffi::c_int; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPySet_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPySet_Type")] pub static mut PySet_Type: PyTypeObject; - #[cfg_attr(PyPy, link_name = "PyPyFrozenSet_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyFrozenSet_Type")] pub static mut PyFrozenSet_Type: PyTypeObject; pub static mut PySetIter_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/sliceobject.rs b/pyo3-ffi/src/sliceobject.rs index 4321b689f11..9fdf6e50225 100644 --- a/pyo3-ffi/src/sliceobject.rs +++ b/pyo3-ffi/src/sliceobject.rs @@ -37,7 +37,7 @@ pub struct PySliceObject { #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPySlice_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPySlice_Type")] pub static mut PySlice_Type: PyTypeObject; pub static mut PyEllipsis_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/structseq.rs b/pyo3-ffi/src/structseq.rs index b6ff0a6cf11..523e92b2e60 100644 --- a/pyo3-ffi/src/structseq.rs +++ b/pyo3-ffi/src/structseq.rs @@ -21,6 +21,7 @@ pub struct PyStructSequence_Desc { extern_libpython! { #[cfg(any(Py_3_11, not(Py_LIMITED_API)))] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyStructSequence_UnnamedField")] pub static PyStructSequence_UnnamedField: *const c_char; } diff --git a/pyo3-ffi/src/traceback.rs b/pyo3-ffi/src/traceback.rs index e5868f00217..806e9ff7f0e 100644 --- a/pyo3-ffi/src/traceback.rs +++ b/pyo3-ffi/src/traceback.rs @@ -8,7 +8,7 @@ extern_libpython! { pub fn PyTraceBack_Print(arg1: *mut PyObject, arg2: *mut PyObject) -> c_int; #[cfg(not(RustPython))] - #[cfg_attr(PyPy, link_name = "PyPyTraceBack_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyTraceBack_Type")] pub static mut PyTraceBack_Type: PyTypeObject; #[cfg(any(PyPy, RustPython))] diff --git a/pyo3-ffi/src/tupleobject.rs b/pyo3-ffi/src/tupleobject.rs index 8a3c678243c..0b8b2e1eadf 100644 --- a/pyo3-ffi/src/tupleobject.rs +++ b/pyo3-ffi/src/tupleobject.rs @@ -4,7 +4,7 @@ use core::ffi::c_int; #[cfg(not(RustPython))] extern_libpython! { - #[cfg_attr(PyPy, link_name = "PyPyTuple_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyTuple_Type")] pub static mut PyTuple_Type: PyTypeObject; pub static mut PyTupleIter_Type: PyTypeObject; } diff --git a/pyo3-ffi/src/unicodeobject.rs b/pyo3-ffi/src/unicodeobject.rs index 08c550a3a14..77ab2b0b359 100644 --- a/pyo3-ffi/src/unicodeobject.rs +++ b/pyo3-ffi/src/unicodeobject.rs @@ -9,7 +9,7 @@ pub type Py_UCS1 = u8; extern_libpython! { #[cfg(not(RustPython))] - #[cfg_attr(PyPy, link_name = "PyPyUnicode_Type")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyUnicode_Type")] pub static mut PyUnicode_Type: PyTypeObject; #[cfg(not(RustPython))] pub static mut PyUnicodeIter_Type: PyTypeObject; From a6c894e44b297e7e92291c8d65d88147e90e80bb Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Wed, 16 Sep 2026 12:58:25 +0100 Subject: [PATCH 2/5] newsfragments --- newsfragments/6421.fixed.md | 1 + newsfragments/6421.removed.md | 1 + 2 files changed, 2 insertions(+) create mode 100644 newsfragments/6421.fixed.md create mode 100644 newsfragments/6421.removed.md diff --git a/newsfragments/6421.fixed.md b/newsfragments/6421.fixed.md new file mode 100644 index 00000000000..fece7a15765 --- /dev/null +++ b/newsfragments/6421.fixed.md @@ -0,0 +1 @@ +Fix many unresolved data symbols when linking for PyPy due to incorrect link names in `pyo3-ffi`. diff --git a/newsfragments/6421.removed.md b/newsfragments/6421.removed.md new file mode 100644 index 00000000000..b3740a11308 --- /dev/null +++ b/newsfragments/6421.removed.md @@ -0,0 +1 @@ +Remove FFI definitions `PyExc_RecursionErrorInst` and `Py_UseClassExceptionsFlag` (not present in supported Python versions). From 7e2aee53bd9d451e19c83a5a8e7f05f967964b57 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Wed, 16 Sep 2026 13:10:40 +0100 Subject: [PATCH 3/5] fix private symbols --- pyo3-ffi/src/abstract_.rs | 2 +- pyo3-ffi/src/boolobject.rs | 4 ++-- pyo3-ffi/src/cpython/pystate.rs | 1 + pyo3-ffi/src/object.rs | 4 ++-- pyo3-ffi/src/objimpl.rs | 8 ++++---- pyo3-ffi/src/sliceobject.rs | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/pyo3-ffi/src/abstract_.rs b/pyo3-ffi/src/abstract_.rs index c99c2cba1cf..2d0ac415b1d 100644 --- a/pyo3-ffi/src/abstract_.rs +++ b/pyo3-ffi/src/abstract_.rs @@ -55,7 +55,7 @@ extern_libpython! { ) -> *mut PyObject; #[cfg(all(PyPy, not(Py_3_13)))] // called internally in PyUnicodeDecodeError_Create on PyPy - #[cfg_attr(PyPy, link_name = "_PyPyObject_CallFunction_SizeT")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPyObject_CallFunction_SizeT")] pub(crate) fn _PyObject_CallFunction_SizeT( callable_object: *mut PyObject, format: *const c_char, diff --git a/pyo3-ffi/src/boolobject.rs b/pyo3-ffi/src/boolobject.rs index ccdf1cf188d..f1beddd3a97 100644 --- a/pyo3-ffi/src/boolobject.rs +++ b/pyo3-ffi/src/boolobject.rs @@ -14,10 +14,10 @@ extern_libpython! { pub fn PyBool_Check(op: *mut PyObject) -> c_int; #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] - #[cfg_attr(PyPy, link_name = "_PyPy_FalseStruct")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPy_FalseStruct")] static mut _Py_FalseStruct: PyLongObject; #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] - #[cfg_attr(PyPy, link_name = "_PyPy_TrueStruct")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPy_TrueStruct")] static mut _Py_TrueStruct: PyLongObject; #[cfg(GraalPy)] diff --git a/pyo3-ffi/src/cpython/pystate.rs b/pyo3-ffi/src/cpython/pystate.rs index 727c4a479be..4f7385ade75 100644 --- a/pyo3-ffi/src/cpython/pystate.rs +++ b/pyo3-ffi/src/cpython/pystate.rs @@ -66,6 +66,7 @@ extern_libpython! { pub fn PyThreadState_GetUnchecked() -> *mut PyThreadState; #[cfg(not(Py_3_13))] + #[cfg_attr(PyPy, link_name = "_PyPyThreadState_UncheckedGet")] pub(crate) fn _PyThreadState_UncheckedGet() -> *mut PyThreadState; #[cfg(Py_3_11)] diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 64dba2f87fe..40578b244d1 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -651,7 +651,7 @@ extern_libpython! { pub fn Py_GetConstantBorrowed(constant_id: c_uint) -> *mut PyObject; #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] - #[cfg_attr(PyPy, link_name = "_PyPy_NoneStruct")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPy_NoneStruct")] static mut _Py_NoneStruct: PyObject; #[cfg(GraalPy)] @@ -679,7 +679,7 @@ pub unsafe fn Py_IsNone(x: *mut PyObject) -> c_int { extern_libpython! { #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] - #[cfg_attr(PyPy, link_name = "_PyPy_NotImplementedStruct")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPy_NotImplementedStruct")] static mut _Py_NotImplementedStruct: PyObject; #[cfg(GraalPy)] diff --git a/pyo3-ffi/src/objimpl.rs b/pyo3-ffi/src/objimpl.rs index 1f62f2ef94a..eb60e42782a 100644 --- a/pyo3-ffi/src/objimpl.rs +++ b/pyo3-ffi/src/objimpl.rs @@ -32,9 +32,9 @@ extern_libpython! { // skipped PyObject_INIT // skipped PyObject_INIT_VAR - #[cfg_attr(PyPy, link_name = "_PyPyObject_New")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPyObject_New")] fn _PyObject_New(typeobj: *mut PyTypeObject) -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "_PyPyObject_NewVar")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPyObject_NewVar")] fn _PyObject_NewVar(typeobj: *mut PyTypeObject, n: Py_ssize_t) -> *mut PyVarObject; } @@ -91,9 +91,9 @@ pub unsafe fn PyObject_GC_Resize(op: *mut PyObject, n: Py_ssize_t) -> *mut T } extern_libpython! { - #[cfg_attr(PyPy, link_name = "_PyPyObject_GC_New")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPyObject_GC_New")] fn _PyObject_GC_New(typeobj: *mut PyTypeObject) -> *mut PyObject; - #[cfg_attr(PyPy, link_name = "_PyPyObject_GC_NewVar")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPyObject_GC_NewVar")] fn _PyObject_GC_NewVar(typeobj: *mut PyTypeObject, n: Py_ssize_t) -> *mut PyVarObject; #[cfg(not(PyPy))] diff --git a/pyo3-ffi/src/sliceobject.rs b/pyo3-ffi/src/sliceobject.rs index 9fdf6e50225..2a30e82e054 100644 --- a/pyo3-ffi/src/sliceobject.rs +++ b/pyo3-ffi/src/sliceobject.rs @@ -4,7 +4,7 @@ use core::ffi::c_int; extern_libpython! { #[cfg(all(not(GraalPy), not(all(Py_3_13, Py_LIMITED_API))))] - #[cfg_attr(PyPy, link_name = "_PyPy_EllipsisObject")] + #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "_PyPy_EllipsisObject")] static mut _Py_EllipsisObject: PyObject; #[cfg(GraalPy)] From b4a87f782906859f986b5a7132c9855d88908fe1 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Wed, 16 Sep 2026 13:11:02 +0100 Subject: [PATCH 4/5] fmt --- pyo3-ffi/src/pyerrors.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyo3-ffi/src/pyerrors.rs b/pyo3-ffi/src/pyerrors.rs index ae64433b72e..11f13a09a84 100644 --- a/pyo3-ffi/src/pyerrors.rs +++ b/pyo3-ffi/src/pyerrors.rs @@ -258,7 +258,10 @@ extern_libpython! { pub static mut PyExc_UserWarning: *mut PyObject; #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_DeprecationWarning")] pub static mut PyExc_DeprecationWarning: *mut PyObject; - #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_PendingDeprecationWarning")] + #[cfg_attr( + all(PyPy, not(Py_3_12)), + link_name = "PyPyExc_PendingDeprecationWarning" + )] pub static mut PyExc_PendingDeprecationWarning: *mut PyObject; #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyExc_SyntaxWarning")] pub static mut PyExc_SyntaxWarning: *mut PyObject; From 32edbab5a00fe6bf5ca750bbcba3dfcd1af289c5 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Wed, 16 Sep 2026 13:57:57 +0100 Subject: [PATCH 5/5] fix windows-only pypy symbol --- pyo3-ffi/src/cpython/pydebug.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pyo3-ffi/src/cpython/pydebug.rs b/pyo3-ffi/src/cpython/pydebug.rs index ed6be81b6bc..5b0a899cbb8 100644 --- a/pyo3-ffi/src/cpython/pydebug.rs +++ b/pyo3-ffi/src/cpython/pydebug.rs @@ -51,6 +51,7 @@ extern_libpython! { pub static mut Py_LegacyWindowsFSEncodingFlag: c_int; #[cfg(windows)] #[deprecated(note = "Python 3.12")] + #[cfg_attr(PyPy, link_name = "PyPy_LegacyWindowsStdioFlag")] pub static mut Py_LegacyWindowsStdioFlag: c_int; }