Skip to content

Build for Python up to (and including) 3.14#38

Open
schlegelp wants to merge 7 commits intoclbarnes:masterfrom
schlegelp:master
Open

Build for Python up to (and including) 3.14#38
schlegelp wants to merge 7 commits intoclbarnes:masterfrom
schlegelp:master

Conversation

@schlegelp
Copy link
Copy Markdown

Hi Chris! I had a crack at trying to get ncollpyde to compile for newer Python versions. It builds fine on my local machine and tests are passing.

Copy link
Copy Markdown
Owner

@clbarnes clbarnes left a comment

Choose a reason for hiding this comment

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

Thanks for the comprehensive updates! I had a couple of questions and will raise some issues for myself to do some more modernisation, but mainly looks good.

I will likely have a bit more time for research-related tooling soon, starting a new job on Monday :)

Comment thread Cargo.toml Outdated
Comment thread .cargo/config.toml
Comment on lines +1 to +11
[target.aarch64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]

[target.x86_64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Do you know what these flags do? Are they required by some particular dependency?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I admit that I had to ask Claude for this because the compiler crashed with some cryptic (for me) linking issues. This was the summary of what it did:

The problem was that on macOS, when building a Python extension module (cdylib), the linker by default requires all symbols to be resolved at link time. However, PyO3 extension modules need Python symbols (like _PyBytes_AsString, _PyErr_Fetch, etc.) that will only be available when the module is loaded by Python at runtime.

The solution is to configure the Rust linker to use -undefined dynamic_lookup, which tells the linker to allow undefined symbols and resolve them dynamically at runtime.

I created a config.toml file with the appropriate linker flags for both ARM64 (Apple Silicon) and x86_64 macOS architectures. Your project should now compile successfully!

Copy link
Copy Markdown
Owner

@clbarnes clbarnes Nov 6, 2025

Choose a reason for hiding this comment

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

OK! I'm developing on macs now so can have more of a play myself. I suppose we should continue to support x64 macs, it was only 2023 that the last ones were discontinued...

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Looks like this is the issue: https://pyo3.rs/v0.27.1/building-and-distribution.html?highlight=macos#macos . From the sounds of it, maturin should in theory handle those compiler arguments itself, but maybe installing via pip skips that or something. I'll have more of a fiddle.

Comment thread .github/workflows/ci.yaml Outdated
@schlegelp
Copy link
Copy Markdown
Author

Just to add: would be nice if there were also wheels for free-threaded Python versions (3.13t and 3.14t). I just tried on my machine and it seems to build fine.

Building aside: are there any potential issues (race conditions, etc) on the implementation side?

@clbarnes
Copy link
Copy Markdown
Owner

clbarnes commented Nov 6, 2025

I don't think the rust side depends on the GIL much because it basically just copies the numpy arrays to build the TriMesh struct and then python can't touch it.

Looks like most of the test failures are just because the requirements.txt uses an ancient numpy version. I have a branch which builds on this PR to modernise a few bits of metadata.

For me, it's building fine without the .cargo/config.toml arguments (even just using pip). I wonder if they were related to the blas feature?

@schlegelp
Copy link
Copy Markdown
Author

I don't think the rust side depends on the GIL much because it basically just copies the numpy arrays to build the TriMesh struct and then python can't touch it.

Nice! I just had a crack at this for navis-fastcore and it seems to come down to two things:

  1. Use #[pymodule(gil_used = false)] for PyO3 0.27 (in 0.28 this is on by default)
  2. Tell maturin explicitly to build against normal and free-threaded Python: maturin build --release --interpreter 3.12 3.13t 3.14t

@clbarnes
Copy link
Copy Markdown
Owner

I've got pretty much everything working on https://github.com/clbarnes/ncollpyde/actions/runs/19476555610 ... except python 3.14. Looks like there's some transitive dependency (manifold3d) which doesn't have wheels for 3.14 yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants