Skip to content
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 cross-compiling on iOS #117

Merged
merged 16 commits into from
Oct 6, 2024

Conversation

freakboy3742
Copy link
Contributor

@freakboy3742 freakboy3742 commented Sep 6, 2024

PEP 730 adds iOS as a Tier 3 supported platform for CPython 3.13. This PR adds the modifications to crossenv to support cross-compiling for iOS devices (ARM64) and iOS Simulators (ARM64 and x86_64). It also includes support for tvOS and watchOS, since the changes are effectively identical.

It also migrates the setup.py file to PEP 621 pyproject.toml format. A pyproject.toml file with a PEP517 configuration is required to avoid warnings (and, in the very near future installation errors); migrating the rest of the configuration was relatively trivial.

These changes have been empirically tested through use in Mobile Forge, which compiles a range of binary packages, for Python 3.9 through 3.13.

There's no additional programmatic tests, because it's not clear if the existing test suite is currently in a working state. I couldn't find any documentation for how to run the test suite; when I take the naïve approach and use pytest to run the test suite locally (on macOS), I get a 100% failure rate; and there's no CI results (that I can find) to compare against. I'm happy to add runtime tests for any of these changes if requested - I just need some guidance on how the test suite is meant to run.

@benfogle
Copy link
Owner

benfogle commented Sep 8, 2024

Wow, this is really neat, thank you. I will start taking a look at it right away.

The existing test suite is unfortunately, as you noticed, partially broken. Some of the tests ended up depending on a combination of Python/setuptools/3rd party modules, which has ended up being far too much of a moving target to maintain. This is something I need to rework.

@freakboy3742
Copy link
Contributor Author

If you've got any general notes/ideas on how the test suite should work (or it's a case of "just get it working, however you do it), I might be able to find some time to work on fixing those issues. However, if you'd prefer to tackle that kind of "core infrastructure" yourself, I'd completely understand.

Copy link
Owner

@benfogle benfogle left a comment

Choose a reason for hiding this comment

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

I'm still checking some of the tests manually to make sure nothing broke. I'm not able to verify the iOS side of things.

crossenv/__init__.py Outdated Show resolved Hide resolved
crossenv/__init__.py Outdated Show resolved Hide resolved
@benfogle
Copy link
Owner

Re: the test suite. It's not terribly broken and can be run manually. I do actually have a local branch to fix things up. Basically it needs:

  • Migrate to GitHub actions
  • Instead of maintaining a toolchain for testing, run the tests in pre-built docker images. There are docker images that would work that either didn't exist when I started the project, or I wasn't aware of them.
  • Don't rely on building 3rd party modules for test purposes. Like bcrypt started using Rust and numpy started using cmake. And setuptools changes too. This is tricky, because testing with setuptools is still a good idea even though it's a moving target.

@freakboy3742
Copy link
Contributor Author

Re: the test suite. It's not terribly broken and can be run manually.

I've had no luck running pytest on the current master branch. I get 100% failures, with every test failing with either:

shutil.ReadError: /Users/rkm/projects/crossenv/tests/prebuilt/prebuilt_musl_arm_aarch64.tar.xz is not a compressed or uncompressed tar file

or

UnboundLocalError: cannot access local variable 'archives' where it is not associated with a value

Looking at the xz file - if I try to unpack it manually, I get an error that it isn't a valid archive "Unrecognised archive format".

@freakboy3742
Copy link
Contributor Author

freakboy3742 commented Sep 10, 2024

I see now from reverse engineering the Azure config that my testing problem is likely the git lfs handling. I'll see if that fixes things...

@freakboy3742
Copy link
Contributor Author

Ok - it's clearly not just lfs; I get binary format errors if I run on an ARM64 macOS laptop. From what I can work out, that's not surprising - the test (and lfs content) seems to involve packaged binaries. My x86_64 Ubuntu 22.04 test machine also fails - there's a handful of test successes (mostly in test_usage), but also a bunch of executable format errors, and a lot of "AssertionError: Could not make crossenv!".

Are you able to provide any high level context for what the test suite is actually doing, and where it should run?

@benfogle
Copy link
Owner

The test suites expect to run on Linux (crossenv has been Linux-only up to now), with qemu-user available via binfmt. On ubuntu, you can install qemu-user-binfmt or qemu-user-static. I run it on Ubuntu 22.04 currently.

Most of these tests will create a temporary crossenv environment (you can poke around in /tmp/pytest-of-$USER to see them) and then run commands in that environment. To make sure that the cross-compiled modules can execute, we use qemu-user to emulate the host-python and load the module. For debugging, I often find it helpful to debug a single test at a time: pytest -k <name_of_test> --pdb. You can also use --trace instead of --pdb to break at the start instead of on failure.

@freakboy3742
Copy link
Contributor Author

The test suites expect to run on Linux (crossenv has been Linux-only up to now), with qemu-user available via binfmt. On ubuntu, you can install qemu-user-binfmt or qemu-user-static. I run it on Ubuntu 22.04 currently.

Most of these tests will create a temporary crossenv environment (you can poke around in /tmp/pytest-of-$USER to see them) and then run commands in that environment. To make sure that the cross-compiled modules can execute, we use qemu-user to emulate the host-python and load the module. For debugging, I often find it helpful to debug a single test at a time: pytest -k <name_of_test> --pdb. You can also use --trace instead of --pdb to break at the start instead of on failure.

Ah - that probably explains it. My Ubuntu 22.04 test box is already being emulated, so QEMU won't work (I can't run the Android emulator on my Ubuntu or Windows test boxes for essentially the same reason).

Using a Docker container to run the tests suite container might avoid those problems - but it might hit the same "emulation inside an emulator" limits. I'll try and see if that's any more successful.

@freakboy3742
Copy link
Contributor Author

@benfogle I've done some more investigation; it looks like the issue isn't QEMU as I thought, but the libraries dynamically linked by the prebuilt environments. Details in #118 where I've got a GitHub Actions CI configuration definition.

@benfogle
Copy link
Owner

benfogle commented Oct 6, 2024

I'm not seeing any breakage manually. What I'm going to do is cut a release off of another PR that just went in and then merge this one. If there is breakage we're not catching, it'll be on the unreleased master branch and hopefully we can fix up CI and then release.

@benfogle benfogle merged commit c801a52 into benfogle:master Oct 6, 2024
1 check failed
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