-
Notifications
You must be signed in to change notification settings - Fork 255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for building iOS wheels. #2286
base: main
Are you sure you want to change the base?
Conversation
I've clearly got some CI edge cases to clean up - moving to draft status. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wow, nice work with this! 🤩
(after just a glance over the changes...)
The text you have in the PR description - we should add that to the docs somewhere. Perhaps a new page about other platforms... that could include some info about Pyodide too.
First of all, nice work what you are doing with the python support for mobile platforms. I am following most of your steps towards this goal :) I am currently trying to get cibuildwheel running with The project has Since a cross platform build is made for iOS, I would assume that |
Hrm - that's an interesting one. It's not a clear bug in The problem is that cmake is in a weird situation as a dependency. Cython would be in a similar situation. On the one hand, it needs to run as part of the build - so we need to install the macOS wheel, so a macOS binary exists. The virtual environment will advertise itself as a However, an iOS-compatible cmake wheel is a bit of a contradiction... because you won't be able to run cmake on iOS. So it would appear as an iOS-compatible wheel that would break things if you actually added it to an app. If you put a macOS binary into an iOS wheel, it would obviously break. The alternative approach would be to consider build dependencies to be "non cross", and Install build dependencies using the build platform's wheel tag. That means installing the macOS wheels for cmake, so that cmake can run in the build environment. I'm not 100% sure if the PEP 517 interface is literally the boundary that we need to care about here, or if we need an additional setting or control mechanism to allow the installation of build dependencies independent of package/testing dependencies... some more investigation may be required. |
That's a good call - I'll add in a section to the docs to that effect. |
That example is old, you should be using scikit-build-core and https://github.com/pybind/scikit_build_example as the base.
If you already have cmake, then scikit-build-core won't request the
This is tricky; a good counter example is numpy. If you want to run |
That may be true for that specific example, but there are other projects (PyTorch is one notable example) that have a dependency on cmake, cython, or similar "binary tools that must be runnable in the build environment" requirement. However, I'll make a note to add https://github.com/pybind/scikit_build_example as a test case for iOS/Android build tooling.
Pandas looks like a good test case here - it needs both cython (which needs to be a macOS version) and numpy (which needs to be the iOS version). However, I agree that this is fundamentally a gap in PEP 517 itself, and we need an extension of that PEP to cover the cross-compilation case. My off-the-cuff proposal would be to have This would also give an opportunity to formalize what a "cross platform venv" actually means, which what the I guess the bigger question here is whether that discussion needs to precede a PR like this one being merged - i.e., is "can compile numpy and pandas" (which are projects with complex build systems) a prerequisite for adding any iOS/Android support to cibuildwheel. This would admittedly be a big gap, but I question whether "the perfect is the enemy of the good" in this instance. |
@joerick I've restored most of the old examples of GitHub actions configuration, only including the "full" example for the last "deployment" case. I've also split out the platform details into standalone pages. That required a bit of surgery to the MKDocs configuration; I'm not sure if I've landed on the best layout for that new content, but the new content is there - I'm open to suggestions on other ways to structure that content. I've fixed the issue with Linux and Windows CI - it required changing the "test" that is run to do something other than invoking The tests are still failing macOS CI - that appears to be due to this bug in the testbed, which I've got a fix in flight. As soon as that PR is merged, I can publish updated support packages that will include the patch. |
NumPy itself may also need to change to support this, because even if we did install the iOS wheel, we wouldn't be able to import it to call In our Android recipes we worked around this by patching everything that used NumPy to set |
IIRC, this cleanup was possible because of the switch to Meson as a build system. The iOS patch is still on the 1.X branch, not the 2.X branch, but building with Meson was (unsurprisingly) a lot cleaner than the older setuptools build. However - even then, I'm not sure it would be a problem with the way this PR is structured. The cross-env handling means that you can invoke Python code - and it runs as if EDIT: ... as long as the code being executed is pure Python. I'm not sure if this is the case with |
@@ -42,12 +42,15 @@ | |||
sys.executable, | |||
"-m", | |||
"pytest", | |||
"--dist", | |||
"loadgroup", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allows the build to run all the iOS tests on the same machine; see the iOS tests for the reason.
f"--numprocesses={args.num_processes}", | ||
"-x", | ||
"--durations", | ||
"0", | ||
"--timeout=2400", | ||
"test", | ||
"-vv", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generates a lot more output - but when a test fails, it helps to have as much context as possible. It was difficult to diagnose some of the iOS failures with the low verbosity output.
This is now passing CI, and the documentation issues referenced in the earlier pre-review have been addressed, so I think this is ready for a full review. |
|
I'm curious, would it make sense to use the architecture instead of the platform for simulator? So basically split native and simulator architectures? Then "auto" could build all of them? I feel like this would behave more like the other platforms, and still would provide a way to split things up if you needed too. Windows and UNIX architecture names differ already, so it would have precedent. |
Co-authored-by: Matthieu Darbois <[email protected]> Co-authored-by: Joe Rickerby <[email protected]>
| | Linux | macOS | Windows | Linux ARM | macOS ARM | Windows ARM | iOS | | ||
|-----------------|-------|-------|---------|-----------|-----------|-------------|-----| | ||
| GitHub Actions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅² | ✅³ | | ||
| Azure Pipelines | ✅ | ✅ | ✅ | | ✅ | ✅² | | | ||
| Travis CI | ✅ | | ✅ | ✅ | | | | | ||
| AppVeyor | ✅ | ✅ | ✅ | | ✅ | ✅² | | | ||
| CircleCI | ✅ | ✅ | | ✅ | ✅ | | | | ||
| Gitlab CI | ✅ | ✅ | ✅ | ✅¹ | ✅ | | | | ||
| Cirrus CI | ✅ | ✅ | ✅ | ✅ | ✅ | | | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only refers to GitHub Actions supporting building wheels for iOS.
There's probably little reason for other providers not to support this ?
It's probably already at least partially tested i this PR.
|
||
If not listed above, `auto` is the same as `native`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be kept below the table ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what the purpose of this sentence is, because it actually is listed above for all supported platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linux s390x/ppc64le/... for example are not listed in the table.
Adds support for building PEP 730 iOS wheels.
Refs #1960.
tl;dr - for simple packages,
CIBW_PLATFORM=ios cibuildwheel
will produce 3 iOS wheels suitable for use on:As proof, this branch has been use to publish iOS wheels for pyspamsum. These wheels were produced using this Github Actions CI configuration.
A branch adding iOS support on Pillow also exists; this hasn't been submitted for inclusion in Pillow because of the dependency on this (as yet unmerged, unreleased) PR. However, it's a demonstration of a non-trivial Python package building iOS wheels.
The details:
Edited 6 Mar 2025, to reflect most recent changes in
CIBW_PLATFORM
andCIBW_ARCHS
.CIBW_PLATFORM
valuesiOS is effectively 2 platforms - physical devices, and the simulator. While the API for these two platforms are identical, the ABI is not compatible, even when dealing with a device and simulator with the same CPU architecture. For this reason, iOS support a
CIBW_PLATFORM
value ofios
, and 3CIBW_ARCHS
values -arm64_iphoneos
(for ARM64 devices),arm64_iphonesimulator
(for simulators running on ARM64 Macs) andx86_64_iphonesimulator
(for simulators running on Intel simulators). This also allows for configurations to be specified at theios
level, and specialised at theiphoneos
oriphonesimulator
level using aselect
clause in a settings override.Binary distributions
The binaries used to support iOS builds come from the BeeWare Python Apple Support project. It is hoped that in the 3.14 release timeframe, these artefacts will be produced by Python.org itself - this is an topic I'm currently working on. In the meantime, the use of 'unofficial' support packages puts iOS in a similar boat as the Emscripten backend using Pyodide build artefacts.
Cross platform builds
iOS builds are always cross platform builds, as it not possible to run compilers and other build tools "on device". The BeeWare iOS support package includes tooling that can convert any virtual environment into a cross platform virtual environment - that is, an environment that can run binaries on the build machine (macOS), but, if asked, will respond as if it is an iOS machine. This allows
pip
,build
, and other build tools to perform iOS-appropriate behaviour. As a result, an iOS build environment also means downloading and installing CIBW's macOS tools.Build frontends
iOS builds support both the
pip
andbuild
build frontends. In principle, support forbuild[uv]
should be possible, butuv
doesn't currently have support for cross-platform builds, and doesn't have support for iOS (or Android) tags.The build environment
The environment used to run builds does not inherit the full user environment - in particular, PATH is deliberately re-written. This is because UNIX C tooling doesn't do a great job differentiating between "macOS ARM64" and "iOS ARM64" binaries. If (for example) Homebrew is on the path when compilation commands are invoked, it's easy for a macOS version of a library to be linked into the iOS binary, rendering it useless. To prevent this, iOS builds always force PATH to a "known minimal" path, that includes only the bare system utilities, plus cargo (to facilitate Rust builds).
iOS test suites
Running iOS test suites also requires special attention. The iOS test environment can't support running shell scripts, so the entry point must be specified as a completion to
python -m ...
. In addition, the test itself must be run "on device", so the local project directory cannot be used to run tests. As a result, the project must specifytest_sources
as a minimum subset of files that should be copied to the test environment.The test process uses the same testbed used by CPython itself to run the CPython test suite. It is an Xcode project that has been configured to have a single Xcode "XCUnit" test - the result of which is whatever the output of
python -m <CIBW_TEST_COMMAND>
is. This testbed is also included in the BeeWare support package.