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: 0 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ jobs:
build:
continue-on-error: ${{ endsWith(inputs.python-version, '-dev') || contains(fromJSON('["beta", "nightly"]'), inputs.rust) }}
runs-on: ${{ inputs.os }}
if: ${{ !(startsWith(inputs.python-version, 'graalpy') && startsWith(inputs.os, 'windows')) }}
steps:
- uses: actions/checkout@v7.0.1
with:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,8 @@ jobs:
"3.15-dev",
"3.15t-dev",
"pypy3.11",
"graalpy25.0",
"graalpy25.2", # 3.12
"graalpy25.3", # 3.13
]
platform:
[
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ check-cfg = [
#
# maybe in the future this list will not be necessary, see
# internals.rust-lang.org/t/support-renames-with-link-name-kind-raw-dylib/24415
'cfg(pyo3_dll, values("python3", "python3_d", "python3t", "python3t_d", "python38", "python38_d", "python39", "python39_d", "python310", "python310_d", "python311", "python311_d", "python312", "python312_d", "python313", "python313_d", "python313t", "python313t_d", "python314", "python314_d", "python314t", "python314t_d", "python315", "python315_d", "python315t", "python315t_d", "python316", "python316_d", "python316t", "python316t_d", "libpypy3.11-c", "libpypy3.12-c"))',
'cfg(pyo3_dll, values("python3", "python3_d", "python3t", "python3t_d", "python38", "python38_d", "python39", "python39_d", "python310", "python310_d", "python311", "python311_d", "python312", "python312_d", "python313", "python313_d", "python313t", "python313t_d", "python314", "python314_d", "python314t", "python314t_d", "python315", "python315_d", "python315t", "python315t_d", "python316", "python316_d", "python316t", "python316t_d", "libpypy3.11-c", "libpypy3.12-c", "python-native"))',
]


Expand Down
1 change: 1 addition & 0 deletions newsfragments/6406.packaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support GraalPy on Windows.
3 changes: 3 additions & 0 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1494,6 +1494,9 @@ def _check_raw_dylib_macro(session: nox.Session):
):
expected_dlls.add(f"libpypy3.{minor}-c")

# GraalPy DLL (python-native.dll)
expected_dlls.add("python-native")

# Parse the DLL name list in the extern_libpython!(@impl ...) invocation
lib_rs = (PYO3_DIR / "pyo3-ffi" / "src" / "impl_" / "macros.rs").read_text()
found_dlls = set(re.findall(r'"((?:python(?!XY)|libpypy)[^"]+)"', lib_rs))
Expand Down
19 changes: 10 additions & 9 deletions pyo3-build-config/src/impl_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2396,15 +2396,6 @@ fn default_lib_name_for_target(abi: PythonAbi, target: &Triple) -> String {
}

fn default_lib_name_windows(abi: PythonAbi, mingw: bool, debug: bool) -> Result<String> {
// mingw formats lib names like unix, and uses a "lib" prefix. We could let the linker
// handle "lib" prefix, but that means the `raw-dylib` name is incorrect (where the
// "lib" prefix is not automatically added).
if mingw {
let mut lib_name = default_lib_name_unix(abi, true, None)?;
lib_name.insert_str(0, "lib");
return Ok(lib_name);
}

if abi.implementation.is_pypy() {
// PyPy on Windows ships `libpypy3.X-c.dll` (e.g. `libpypy3.11-c.dll`),
// not CPython's `pythonXY.dll`. With raw-dylib linking we need the real
Expand All @@ -2413,6 +2404,16 @@ fn default_lib_name_windows(abi: PythonAbi, mingw: bool, debug: bool) -> Result<
"libpypy{}.{}-c",
abi.version.major, abi.version.minor
))
} else if abi.implementation == PythonImplementation::GraalPy {
// Similar for GraalPy on Windows, which ships `python-native.dll`
Ok("python-native".to_string())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This also changes the library name when PYO3_USE_RAW_DYLIB=0. When my AI model tested, it broke graalpy because the library name is e.g. python312.lib but the build script requests python-native.lib anyway. I think this is correct only for PYO3_USE_RAW_DYLIB=1.

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.

xref #6410 (comment) - I guess it's the other side of the same hack, where a clause would be needed in that hack to also account for GraalPy.

I guess that means that only one of these PRs will merge successfully because #6410 introduces proper ffi-check for both modes of PYO3_USE_RAW_DYLIB.

I'll have a go at solving the full refactor properly, perhaps after merging #6410 but before merging here? Merging #6410 will unblock the rest of the expanded ffi-check testing in #6389

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.

This seems to be ok for now, so I'm going to merge this to unblock the patch release as I think it'll be an edge case, but I've made a note to do the full refactor (ideally before 0.30). Please forgive 🙏

} else if mingw {
// mingw formats lib names like unix, and uses a "lib" prefix. We could let the linker
// handle "lib" prefix, but that means the `raw-dylib` name is incorrect (where the
// "lib" prefix is not automatically added).
let mut lib_name = default_lib_name_unix(abi, true, None)?;
lib_name.insert_str(0, "lib");
Ok(lib_name)
} else if debug && abi.version < PythonVersion::PY310 {
// CPython bug: linking against python3_d.dll raises error
// https://github.com/python/cpython/issues/101614
Expand Down
4 changes: 4 additions & 0 deletions pyo3-ffi-check/definitions/wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
#include "datetime.h"
#include "frameobject.h"
#include "structmember.h"

// no marshal.h in GraalPy
#ifndef GRAALVM_PYTHON
#include "marshal.h"
#endif
20 changes: 19 additions & 1 deletion pyo3-ffi-check/macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ pub fn for_all_structs(input: proc_macro::TokenStream) -> proc_macro::TokenStrea
continue;
}

if pyo3_build_config::get().target_abi().implementation() == PythonImplementation::GraalPy
&& (struct_name == "PyFunctionObject" || struct_name == "PySliceObject")
{
// GraalPy wants these types to be opaque, we skip them
continue;
}

let struct_ident = Ident::new(struct_name, Span::call_site());
output.extend(quote!(#macro_name!(#struct_ident);));
}
Expand Down Expand Up @@ -263,6 +270,17 @@ pub fn for_all_fields(input: proc_macro::TokenStream) -> proc_macro::TokenStream
// bindgen picked `__bindgen_anon_1` as the field name for the anonymous union containing ob_refcnt,
// PyO3 uses ob_refcnt directly
all_fields.remove("__bindgen_anon_1");
} else if struct_name == "PyVarObject"
&& pyo3_build_config::get().target_abi().implementation() == PythonImplementation::GraalPy
{
// ob_size not present in GraalPy
all_fields.remove("ob_size");
} else if pyo3_build_config::get().target_abi().implementation()
== PythonImplementation::GraalPy
&& (struct_name == "PyFunctionObject" || struct_name == "PySliceObject")
{
// GraalPy wants these types to be opaque, we skip them
return TokenStream::new().into();
}

let mut output = TokenStream::new();
Expand Down Expand Up @@ -533,7 +551,7 @@ const MACRO_EXCLUSIONS: &[(&str, &str)] = &[
("Py_IS_TYPE", "not(Py_3_15)"), // symbol added for stable abi on 3.15
("Py_None", ""),
("Py_NotImplemented", ""),
("Py_REFCNT", "not(Py_3_14)"),
("Py_REFCNT", "all(not(Py_3_14), not(GraalPy))"),
("Py_SIZE", "not(Py_3_15)"), // symbol added for stable abi on 3.15
("Py_True", ""),
("Py_TYPE", "not(Py_3_14)"),
Expand Down
4 changes: 3 additions & 1 deletion pyo3-ffi/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,12 @@ fn ensure_target_pointer_width(interpreter_config: &InterpreterConfig) -> Result
/// (see https://internals.rust-lang.org/t/support-renames-with-link-name-kind-raw-dylib/24415)
/// so if the lib name is not one of the known subset, we must fall back to full linking.
fn lib_name_is_known_for_raw_dylib(lib_name: &str) -> bool {
// pyo3_dll cfg for raw-dylib linking on Windows
if matches!(
lib_name,
// pyo3_dll cfg for raw-dylib linking on Windows
"python3" | "python3_d" | "python3t" | "python3t_d"
// GraalPy DLL name
| "python-native"
) {
return true;
}
Expand Down
2 changes: 2 additions & 0 deletions pyo3-ffi/src/cpython/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub(crate) mod listobject;
#[cfg(Py_3_13)]
pub(crate) mod lock;
pub(crate) mod longobject;
#[cfg(not(GraalPy))]
pub(crate) mod marshal;
#[cfg(not(PyPy))]
pub(crate) mod methodobject;
Expand Down Expand Up @@ -77,6 +78,7 @@ pub use self::listobject::*;
#[cfg(Py_3_13)]
pub use self::lock::*;
pub use self::longobject::*;
#[cfg(not(GraalPy))]
pub use self::marshal::*;
#[cfg(not(PyPy))]
pub use self::methodobject::*;
Expand Down
2 changes: 1 addition & 1 deletion pyo3-ffi/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ pub unsafe fn PyDateTime_DELTA_GET_MICROSECONDS(o: *mut PyObject) -> c_int {
// but copying them seems suboptimal
#[inline]
#[cfg(GraalPy)]
pub unsafe fn _get_attr(obj: *mut PyObject, field: &core::ffi::CStr) -> c_int {
unsafe fn _get_attr(obj: *mut PyObject, field: &core::ffi::CStr) -> c_int {
let result = PyObject_GetAttrString(obj, field.as_ptr());
Py_DecRef(result); // the original macros are borrowing
if PyLong_Check(result) == 1 {
Expand Down
2 changes: 2 additions & 0 deletions pyo3-ffi/src/impl_/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ macro_rules! extern_libpython {
// PyPy (DLL is libpypy3.X-c.dll, not pythonXY.dll)
"libpypy3.11-c",
"libpypy3.12-c",
// GraalPy DLL
"python-native",
);
};
// Internal: generate cfg_attr for each DLL name. One of these will be selected
Expand Down
2 changes: 1 addition & 1 deletion pyo3-ffi/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ pub struct PyVarObject {
pub ob_size: Py_ssize_t,
// On GraalPy the field is physically there, but not always populated. We hide it to prevent accidental misuse
#[cfg(GraalPy)]
pub _ob_size_graalpy: Py_ssize_t,
_ob_size_graalpy: Py_ssize_t,
}

#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/marshal.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg(not(Py_LIMITED_API))]
#![cfg(not(any(Py_LIMITED_API, GraalPy)))]

//! Support for the Python `marshal` format.

Expand Down
Loading