Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions newsfragments/6422.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix linker errors on PyPy for outdated FFI definitions where PyPy moved from a function to a macro.
82 changes: 49 additions & 33 deletions pyo3-ffi-check/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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", ""),
Expand All @@ -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", ""),
Expand Down Expand Up @@ -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))"),
Expand All @@ -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", ""),
Expand All @@ -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", ""),
Expand All @@ -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", ""),
Expand All @@ -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", ""),
Expand All @@ -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", ""),
Expand All @@ -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)"),
];

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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}",
Expand Down Expand Up @@ -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!(
Expand Down
4 changes: 2 additions & 2 deletions pyo3-ffi/src/cpython/pydebug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
16 changes: 8 additions & 8 deletions pyo3-ffi/src/setobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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))]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Their goal is to be abi3 compatible right? Will this be compatible?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so, yes, this is moving towards consistency with the CPython declaration on PyPy 3.12 (i.e. there is no such symbol, just a macro)

#[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
}
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions pyo3-ffi/src/traceback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
13 changes: 6 additions & 7 deletions pyo3-ffi/src/weakrefobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading