diff --git a/newsfragments/6422.fixed.md b/newsfragments/6422.fixed.md new file mode 100644 index 00000000000..9a438dd46ed --- /dev/null +++ b/newsfragments/6422.fixed.md @@ -0,0 +1 @@ +Fix linker errors on PyPy for outdated FFI definitions where PyPy moved from a function to a macro. diff --git a/pyo3-ffi-check/macro/src/lib.rs b/pyo3-ffi-check/macro/src/lib.rs index f18a63bfbd4..0d3afcac282 100644 --- a/pyo3-ffi-check/macro/src/lib.rs +++ b/pyo3-ffi-check/macro/src/lib.rs @@ -334,14 +334,14 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ // should be using rather than implementing inline functions ("PyAnyDict_Check", ""), ("PyAnyDict_CheckExact", ""), - ("PyAnySet_Check", "not(PyPy)"), - ("PyAnySet_CheckExact", "not(PyPy)"), + ("PyAnySet_Check", "any(not(PyPy), Py_3_12)"), + ("PyAnySet_CheckExact", "any(not(PyPy), Py_3_12)"), ("PyAsyncGen_CheckExact", ""), ("PyBool_Check", ""), ("PyByteArray_AS_STRING", ""), ("PyByteArray_GET_SIZE", ""), - ("PyByteArray_Check", "not(PyPy)"), - ("PyByteArray_CheckExact", "not(PyPy)"), + ("PyByteArray_Check", "any(not(PyPy), Py_3_12)"), + ("PyByteArray_CheckExact", "any(not(PyPy), Py_3_12)"), ("PyBytes_AS_STRING", "not(PyPy)"), ("PyBytes_Check", ""), ("PyBytes_CheckExact", ""), @@ -357,8 +357,8 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ ("PyCapsule_CheckExact", ""), ("PyCell_Check", ""), ("PyCode_Check", "not(PyPy)"), - ("PyComplex_Check", "not(PyPy)"), - ("PyComplex_CheckExact", "not(PyPy)"), + ("PyComplex_Check", "any(not(PyPy), Py_3_12)"), + ("PyComplex_CheckExact", "any(not(PyPy), Py_3_12)"), ("PyContext_CheckExact", ""), ("PyContextToken_CheckExact", ""), ("PyContextVar_CheckExact", ""), @@ -407,14 +407,14 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ ("PyExceptionInstance_Class", "not(PyPy)"), ("PyEval_CallObject", "not(Py_3_13)"), ("PyFloat_AS_DOUBLE", "not(PyPy)"), - ("PyFloat_Check", "not(PyPy)"), - ("PyFloat_CheckExact", "not(PyPy)"), + ("PyFloat_Check", "any(not(PyPy), Py_3_12)"), + ("PyFloat_CheckExact", "any(not(PyPy), Py_3_12)"), ("PyFrame_Check", ""), ("PyFrameLocalsProxy_Check", ""), ("PyFrozenDict_Check", ""), ("PyFrozenDict_CheckExact", ""), - ("PyFrozenSet_Check", "not(PyPy)"), - ("PyFrozenSet_CheckExact", "not(PyPy)"), + ("PyFrozenSet_Check", "any(not(PyPy), Py_3_12)"), + ("PyFrozenSet_CheckExact", "any(not(PyPy), Py_3_12)"), ("PyFunction_Check", "not(PyPy)"), ("PyFunction_GET_CODE", "all(not(PyPy), not(GraalPy))"), ("PyFunction_GET_GLOBALS", "all(not(PyPy), not(GraalPy))"), @@ -436,9 +436,9 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ ("PyLong_CheckExact", ""), ("PyMapping_DelItem", ""), ("PyMapping_DelItemString", ""), - ("PyMemoryView_Check", "not(PyPy)"), - ("PyModule_Check", "not(PyPy)"), - ("PyModule_CheckExact", "not(PyPy)"), + ("PyMemoryView_Check", "any(not(PyPy), Py_3_12)"), + ("PyModule_Check", "any(not(PyPy), Py_3_12)"), + ("PyModule_CheckExact", "any(not(PyPy), Py_3_12)"), ("PyModule_Create", ""), ("PyModule_FromDefAndSpec", "not(PyPy)"), ("PyObject_CallMethodNoArgs", ""), @@ -465,8 +465,8 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ ("PySequence_Fast_GET_SIZE", ""), ("PySequence_Fast_ITEMS", ""), ("PySequence_ITEM", "not(PyPy)"), - ("PySet_Check", "not(PyPy)"), - ("PySet_CheckExact", "not(PyPy)"), + ("PySet_Check", "any(not(PyPy), Py_3_12)"), + ("PySet_CheckExact", "any(not(PyPy), Py_3_12)"), ("PySet_GET_SIZE", ""), ("PySlice_Check", ""), ("PySlot_DATA", ""), @@ -489,7 +489,7 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ ("PyTime_FromTimeAndFold", ""), ("PyTimeZone_FromOffset", ""), ("PyTimeZone_FromOffsetAndName", ""), - ("PyTraceBack_Check", "not(PyPy)"), + ("PyTraceBack_Check", "any(not(PyPy), Py_3_12)"), ("PyTuple_Check", ""), ("PyTuple_CheckExact", ""), ("PyTuple_GET_ITEM", ""), @@ -500,7 +500,7 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ ("PyType_FastSubclass", ""), ("PyType_HasFeature", ""), ("PyType_IS_GC", ""), - ("PyType_SUPPORTS_WEAKREFS", "not(Py_3_11)"), + ("PyType_SUPPORTS_WEAKREFS", "any(PyPy, not(Py_3_11))"), ("PyUnicode_1BYTE_DATA", ""), ("PyUnicode_2BYTE_DATA", ""), ("PyUnicode_4BYTE_DATA", ""), @@ -514,18 +514,21 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ ("PyUnicode_IS_READY", ""), ("PyUnicode_KIND", "not(Py_3_14)"), ("PyUnicode_READY", ""), - ("PyWeakref_Check", "not(PyPy)"), - ("PyWeakref_CheckProxy", "not(PyPy)"), - ("PyWeakref_CheckRef", "not(PyPy)"), - ("PyWeakref_CheckRefExact", "not(PyPy)"), + ("PyWeakref_Check", "any(not(PyPy), Py_3_12)"), + ("PyWeakref_CheckProxy", "any(not(PyPy), Py_3_12)"), + ("PyWeakref_CheckRef", "any(not(PyPy), Py_3_12)"), + ("PyWeakref_CheckRefExact", "any(not(PyPy), Py_3_12)"), ("PyVectorcall_NARGS", "not(Py_3_12)"), ("Py_CLEAR", ""), - ("Py_CompileString", "not(Py_3_10)"), + ( + "Py_CompileString", + "any(not(Py_3_10), all(PyPy, not(Py_3_12)))", + ), ("Py_CompileStringFlags", "all(not(PyPy), not(Py_3_13))"), ("Py_DECREF", ""), ("Py_Ellipsis", ""), ("Py_False", ""), - ("Py_GETENV", "not(Py_3_11)"), + ("Py_GETENV", "any(PyPy, not(Py_3_11))"), ("Py_INCREF", ""), ("Py_IS_TYPE", "not(Py_3_15)"), // symbol added for stable abi on 3.15 ("Py_None", ""), @@ -542,8 +545,8 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[ // the same way. ("_PyFunction_CAST", "all(not(PyPy), not(GraalPy))"), ("Py_Is", "not(Py_3_10)"), - ("Py_IsFalse", "not(Py_3_10)"), - ("Py_IsTrue", "not(Py_3_10)"), + ("Py_IsFalse", "any(not(Py_3_10), all(PyPy, not(Py_3_12)))"), + ("Py_IsTrue", "any(not(Py_3_10), all(PyPy, not(Py_3_12)))"), ("Py_IsNone", "not(Py_3_10)"), ]; @@ -642,14 +645,6 @@ pub fn for_all_functions(_input: proc_macro::TokenStream) -> proc_macro::TokenSt } let bindgen_name = get_bindgen_name(function_name, &BINDGEN_FUNCTION_NAMES); - if pyo3_build_config::get().implementation() == PythonImplementation::PyPy { - // 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 - if !BINDGEN_FUNCTION_NAMES.contains(&bindgen_name) { - continue; - } - } let FunctionInfo { modifiers, @@ -696,6 +691,20 @@ pub fn for_all_functions(_input: proc_macro::TokenStream) -> proc_macro::TokenSt variadic: false, } } + ("PyDateTime_IMPORT", Err(FunctionNameMismatch(e))) if e == "PyDateTime_Import" => { + FunctionInfo { + modifiers: quote!(unsafe), + arg_count: 0, + variadic: false, + } + } + ("PyDateTime_Import", Err(FunctionNameMismatch(e))) if e == "PyDateTime_IMPORT" => { + FunctionInfo { + modifiers: quote!(unsafe extern "C"), + arg_count: 0, + variadic: false, + } + } (function_name, Err(FunctionNameMismatch(unexpected))) => { let error_message = format!( "parsed unexpected function declaration for `{function_name}`: {unexpected}", @@ -760,6 +769,13 @@ pub fn for_all_functions(_input: proc_macro::TokenStream) -> proc_macro::TokenSt quote!(#macro_name!(#inline #function_ident, #bindgen_ident, #modifiers (#(#arg_types),* #vararg));), ); } + (None, false) + if pyo3_build_config::get().implementation() == PythonImplementation::PyPy => + { + // Without an explicit macro exclusion, tolerate missing PyPy symbols: + // - For PyO3 inline functions it's probably fine to include anyway + // - For extern symbols - PyPy may add them in a future release + } (None, false) => { // Not in MACRO_EXCLUSIONS, should have a symbol from bindgen let error_message = format!( diff --git a/pyo3-ffi/src/cpython/pydebug.rs b/pyo3-ffi/src/cpython/pydebug.rs index 5b0a899cbb8..8d978690fc5 100644 --- a/pyo3-ffi/src/cpython/pydebug.rs +++ b/pyo3-ffi/src/cpython/pydebug.rs @@ -56,11 +56,11 @@ extern_libpython! { } extern_libpython! { - #[cfg(Py_3_11)] + #[cfg(all(Py_3_11, not(PyPy)))] pub fn Py_GETENV(name: *const c_char) -> *mut c_char; } -#[cfg(not(Py_3_11))] +#[cfg(any(PyPy, not(Py_3_11)))] #[inline(always)] pub unsafe fn Py_GETENV(name: *const c_char) -> *mut c_char { #[allow(deprecated)] diff --git a/pyo3-ffi/src/setobject.rs b/pyo3-ffi/src/setobject.rs index 1d204797c26..e168feb025b 100644 --- a/pyo3-ffi/src/setobject.rs +++ b/pyo3-ffi/src/setobject.rs @@ -30,15 +30,15 @@ extern_libpython! { #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPySet_Size")] pub fn PySet_Size(anyset: *mut PyObject) -> Py_ssize_t; - #[cfg(any(PyPy, RustPython))] + #[cfg(any(all(PyPy, not(Py_3_12)), RustPython))] #[cfg_attr(PyPy, link_name = "PyPyFrozenSet_CheckExact")] pub fn PyFrozenSet_CheckExact(ob: *mut PyObject) -> c_int; - #[cfg(any(PyPy, RustPython))] + #[cfg(any(all(PyPy, not(Py_3_12)), RustPython))] #[cfg_attr(PyPy, link_name = "PyPyFrozenSet_Check")] pub fn PyFrozenSet_Check(ob: *mut PyObject) -> c_int; - #[cfg(any(PyPy, RustPython))] + #[cfg(any(all(PyPy, not(Py_3_12)), RustPython))] #[cfg_attr(PyPy, link_name = "PyPyAnySet_CheckExact")] pub fn PyAnySet_CheckExact(ob: *mut PyObject) -> c_int; @@ -48,26 +48,26 @@ extern_libpython! { #[cfg(RustPython)] pub fn PySet_CheckExact(op: *mut PyObject) -> c_int; - #[cfg(any(PyPy, RustPython))] + #[cfg(any(all(PyPy, not(Py_3_12)), RustPython))] #[cfg_attr(PyPy, link_name = "PyPySet_Check")] pub fn PySet_Check(ob: *mut PyObject) -> c_int; } #[inline] -#[cfg(not(any(PyPy, GraalPy, RustPython)))] +#[cfg(not(any(all(PyPy, not(Py_3_12)), GraalPy, RustPython)))] pub unsafe fn PyFrozenSet_CheckExact(ob: *mut PyObject) -> c_int { (Py_TYPE(ob) == &raw mut PyFrozenSet_Type) as c_int } #[inline] -#[cfg(not(any(PyPy, RustPython)))] +#[cfg(not(any(all(PyPy, not(Py_3_12)), RustPython)))] pub unsafe fn PyFrozenSet_Check(ob: *mut PyObject) -> c_int { (Py_TYPE(ob) == &raw mut PyFrozenSet_Type || PyType_IsSubtype(Py_TYPE(ob), &raw mut PyFrozenSet_Type) != 0) as c_int } #[inline] -#[cfg(not(any(PyPy, RustPython)))] +#[cfg(not(any(all(PyPy, not(Py_3_12)), RustPython)))] pub unsafe fn PyAnySet_CheckExact(ob: *mut PyObject) -> c_int { (Py_TYPE(ob) == &raw mut PySet_Type || Py_TYPE(ob) == &raw mut PyFrozenSet_Type) as c_int } @@ -87,7 +87,7 @@ pub unsafe fn PySet_CheckExact(op: *mut PyObject) -> c_int { } #[inline] -#[cfg(not(any(PyPy, RustPython)))] +#[cfg(not(any(all(PyPy, not(Py_3_12)), RustPython)))] pub unsafe fn PySet_Check(ob: *mut PyObject) -> c_int { (Py_TYPE(ob) == &raw mut PySet_Type || PyType_IsSubtype(Py_TYPE(ob), &raw mut PySet_Type) != 0) as c_int diff --git a/pyo3-ffi/src/traceback.rs b/pyo3-ffi/src/traceback.rs index 806e9ff7f0e..d5c034268bb 100644 --- a/pyo3-ffi/src/traceback.rs +++ b/pyo3-ffi/src/traceback.rs @@ -11,13 +11,13 @@ extern_libpython! { #[cfg_attr(all(PyPy, not(Py_3_12)), link_name = "PyPyTraceBack_Type")] pub static mut PyTraceBack_Type: PyTypeObject; - #[cfg(any(PyPy, RustPython))] + #[cfg(any(all(PyPy, not(Py_3_12)), RustPython))] #[cfg_attr(PyPy, link_name = "PyPyTraceBack_Check")] pub fn PyTraceBack_Check(op: *mut PyObject) -> c_int; } #[inline] -#[cfg(not(any(PyPy, RustPython)))] +#[cfg(not(any(all(PyPy, not(Py_3_12)), RustPython)))] pub unsafe fn PyTraceBack_Check(op: *mut PyObject) -> c_int { Py_IS_TYPE(op, &raw mut PyTraceBack_Type) } diff --git a/pyo3-ffi/src/weakrefobject.rs b/pyo3-ffi/src/weakrefobject.rs index 98161a740fa..a68b2d17cd8 100644 --- a/pyo3-ffi/src/weakrefobject.rs +++ b/pyo3-ffi/src/weakrefobject.rs @@ -17,34 +17,33 @@ extern_libpython! { #[cfg(not(RustPython))] static mut _PyWeakref_CallableProxyType: PyTypeObject; - #[cfg(any(PyPy, RustPython))] + #[cfg(any(all(PyPy, not(Py_3_12)), RustPython))] #[cfg_attr(PyPy, link_name = "PyPyWeakref_CheckRef")] pub fn PyWeakref_CheckRef(op: *mut PyObject) -> c_int; - #[cfg(any(PyPy, RustPython))] + #[cfg(any(all(PyPy, not(Py_3_12)), RustPython))] #[cfg_attr(PyPy, link_name = "PyPyWeakref_CheckRefExact")] pub fn PyWeakref_CheckRefExact(op: *mut PyObject) -> c_int; - #[cfg(any(PyPy, RustPython))] + #[cfg(any(all(PyPy, not(Py_3_12)), RustPython))] #[cfg_attr(PyPy, link_name = "PyPyWeakref_CheckProxy")] pub fn PyWeakref_CheckProxy(op: *mut PyObject) -> c_int; } #[inline] -#[cfg(not(any(PyPy, RustPython)))] -#[cfg(not(RustPython))] +#[cfg(not(any(all(PyPy, not(Py_3_12)), RustPython)))] pub unsafe fn PyWeakref_CheckRef(op: *mut PyObject) -> c_int { PyObject_TypeCheck(op, &raw mut _PyWeakref_RefType) } #[inline] -#[cfg(not(any(PyPy, RustPython)))] +#[cfg(not(any(all(PyPy, not(Py_3_12)), RustPython)))] pub unsafe fn PyWeakref_CheckRefExact(op: *mut PyObject) -> c_int { Py_IS_TYPE(op, &raw mut _PyWeakref_RefType) } #[inline] -#[cfg(not(any(PyPy, RustPython)))] +#[cfg(not(any(all(PyPy, not(Py_3_12)), RustPython)))] pub unsafe fn PyWeakref_CheckProxy(op: *mut PyObject) -> c_int { (Py_IS_TYPE(op, &raw mut _PyWeakref_ProxyType) > 0 || Py_IS_TYPE(op, &raw mut _PyWeakref_CallableProxyType) > 0) as c_int