-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
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
Modifications to support iOS as a cross-compilation target #67858
Comments
Proposal: iOS should be a supported platform for Python development. The attached patch is a first pass at a patch to achieve this. It is a single patch against Python 3.4.2 sources, and requires no pre- or post-configure modifications. Supporting iOS requires multiple builds - one for each of the hardware platforms that iOS supports (x86_64 simulator, ARMv7 and ARM64). These separate builds must then be merged into a single "fat" framework. The patch contains an iOS directory with a "meta" Makefile that manages this build-and-merge process. See the README in the iOS directory for details on usage. The patch also introduces a new 'ios' platform type. A sample XCode project for an iOS app is also provided as part of the patch. iOS/README contains a couple of other notes about the build and the approach taken. There are some known problems/limitations with this patch:
So - the patch isn't ready for commit to trunk. I'm presenting it for the purposes of getting feedback on the broad approach while I continue to resolve the known issues. |
Russell, just checking before I change the issue title: do you mean supporting iOS as a cross-compilation target? "Development" is ambiguous here, as you could mean development *of* CPython, rather than *in* Python, and I assume development *for* iOS largely takes place on x86_64 Mac OS X, Windows and Linux systems. Slavek, Robert - assuming my understanding of the change is correct, I think would be a very interesting CPython enhancement from a Fedora Workstation perspective. |
As a cross-compilation target. From a first quick look at it, it appears the patch requires a current Mac OS X system to build for iOS; the necessary standard build tools and SDKs for iOS are only available on OS X. These are the same build tools used for OS X builds. We already support universal builds for multiple architectures on OS X directly in one pass; unfortunately, the iOS builds require two different SDKs, one for running on the OS X-based simulator and one for the native platform archs which, I assume, is why Russell has gone for the separate builds for each arch and lipo-ed them together. I don't have an opinion yet about the use of the Setup.local configurations rather than modifying setup.py. I appreciate trying to keep the changes for a patch like this as isolated as possible. But, long term, that might not be the best approach assuming there is eventually agreement to fully support iOS as a standard platform (via cross-compilation). The bulk of the patch is the new version of libffi; presumably that will eventually be released upstream in the standard version of libffi so that having a separate copy wouldn't be required? In any case, as a work-in-progress, the patch is certainly nicely done. |
Nick: you are correct - these are changes to support iOS as a cross-compilation target, so you can run your Python code on an iOS device. Apologies for the confusion in nomenclature. Ned: You're correct that the build needs to be run on an OS/X machine, and needs to be done in multiple passes because of the need for multiple SDKs. I've taken the approach of using Setup.local for two reasons. Firstly, iOS requires a "fully embedded" Python, because Apple doesn't approve of the use of dynamic loading in apps. Setup.local was the best way I found to force modules to be statically linked into the main library. Secondly, because of the nature of the end-deployment, I imagine it's inevitable that serious end-users will want to customise their Python build for specific applications. AppStore submission rules prohibit running code that wasn't shipped with the app (i.e., Apple won't let you do an end-run around their app approval processes), so the set of modules you're actually using will be a known quantity. Since a "full" iOS Python build is 34MB or so, much of that bulk will be for binary support of modules that you aren't using, providing an easily configurable way to prune out unused modules from the built product seemed like a useful facility. There's also the issue of providing support for the standard library modules (like SSL) that have dependencies that can't be easily provided or specified out-of-the-box. If there's a better/more palatable approach than using Setup.local, I'm happy to look into it. The libffi code is a direct copy from the current (as of a week or so ago) libffi trunk. There have been some bug fixes applied since 3.2.1 was released in november that are necessary to support ctypes on ARM64 (but, as I flagged in my original comment, introduces bugs for ARMv7). The libffi repo suggests the next version will be 4.0, but I have no idea when that will be finalised. I'm currently trying to get their release plans confirmed. As with OS/X libffi support, the source code needs to be generated, rather than just "./configure && make"'d. That said, the libffi_darwin code could be re-used, as the x86_64 components are the same for Darwin as the iOS simulator. |
Ack, much to consider. Adding doko as I believe he has been most closely following developments with libffi releases. |
A thought, primarily as a note to myself for further investigation: the current OS X framework build support and, to a lesser extent, universal build support have added a fair amount of special-case cruft to the build process, primarily in configure.ac and the main Makefile. Over the years, the build tools have evolved and gotten smarter (and more general) about SDK support and arch support using xcrun, as they were generalized to support iOS vs OS X builds. But, if it is necessary to do separate compile/link steps to support iOS framework builds because of the multiple SDKs, it *might* make sense to integrate those into the main Makefile and to isolate the framework build steps (for both OS X and iOS) to be more of an add-on step. The potential positive impact might be to simplify the current main Makefile and configure.ac by centralizing much of the framework build specific steps scattered throughout the Makefile *and* it could also simplify and speed up the iOS builds by not duplicating the platform-independent build steps. It might even be a useful abstraction for other non-Apple multiple-arch or cross-compilation builds. Another factor to consider is support for building third-party extension modules standalone as opposed to building as part of the interpreter itself. It would be nice to be able to just use the traditional Distutils-based process for third-party extension modules. For OS X universal builds, we get that essentially for free because of the tool chain support for multiple archs. To do it automatically across multiple SDKs would require adding smarts to Distutils to do multiple compile/links and lipo merges. |
Also remember that being a supported platform requires buildbots. If I'm reading this right that means two: one for the simulator build, and one that actually runs on the device (once the run-the-test issues is solved). I'm not sure what would need to be done to buildbot to support the scenario of building on one platform and running the tests on another after copying the binary, but I'm sure there must be some way to do it...buildbot is written in Python after all :) And I'm sure that capability will be useful for more than just iOS...with Android we can probably run buildbot on the device eventually, but being able to test a cross compile build there as well will be helpful (once there is one). |
Understood that buildbots are required. The subject has come up a couple of times on mobile-sig - however, I haven't got a good answer for exactly what this means in practice. Does build hardware need to be delivered to a specific build farm location, or can it just run in my home office? Does it need to be running 24/7, or just guarantee that at least X builds per week, or Y% of all builds are tested? In terms of physical specifications - at a minimum, at least two iDevices will be required (an ARMv7 device, like a 5th Gen iPod, and an ARM64 device, like an iPhone 5S), tethered to a Mac that runs the simulator. In terms of execution - there's definitely ways to remote-control the deployment and execution of apps, so I imagine buildbot integration is in the realm of the possible. Android will have similar requirements, but Android also has an emulator which would allow testing without the existence of a physical device, which would provide an alternative approach. |
Rather than trying to do something ourselves on the mobile testing front, we may want to instead explore the free-for-open-source-project offering from Sauce Labs: https://saucelabs.com/opensauce/ Adapting that to run the CPython self-tests as an "app" might be interesting, but they're PyCon sponsors, so they may be amenable to helping to get that work properly if we need to ask for their help. Getting that set up would also potentially be a useful tool for ensuring PSF web services are working correctly across multiple browsers and client devices. (I'd actually like to get us to the point of being able to do continuous deployment of those services some day) |
(Some work on the Buildbot site would still be required, but it would be triggering a Sauce Labs run rather than managing the mobile hardware directly) |
Nick: Finding a way to get on-device test results is next on my TODO list, once I've got the patch up to date for trunk. FYI - Updating to trunk is currently blocking on bpo-22625 (which was introduced by the fix for bpo-22359). I had thought about using a mobile testing farm "as a service", but I didn't know Sauce Labs had one. I'll keep that in mind when I get around to working on the test suite. |
The Sauce labs option may render this obsolete, but to answer your question, Russell: our buildbot fleet is distributed in many people's offices, basements, and occasionally colo racks. The buildbot needs to be on-line 24/7, but it "calls out" and does not need any inbound ports open. See https://wiki.python.org/moin/BuildBot for the currently available documentation about setting up a buildbot for our fleet. |
Russell, we talked a bit about this topic at the Python Language Summit today (after watching your excellent video). I think there was general agreement there that having iOS support would be "a good thing" along with the recognition that the requirements for support of a mobile platform like iOS differ in some significant ways from most traditional platforms that Python has supported. I agreed to shepherd this issue. I have some initial thoughts but will write up something more detailed shortly. |
not reviewing everything, but
|
Hi Matthias:
|
Here's an updated patch that integrates some of the feedback that has been received so far. Notable changes:
The versions in setup.py are probably more reliable (as they're the ones actually used for most platforms), but you need to have a working Python to access them. However, at the "post-configure" point, you don't have a working Python, so there's a bootstrapping problem. I've refactored the Setup.ios-* definitions so that there's less duplication. There's now a Setup.embedded that contains the common build instructions for all the modules without platform-specific build instructions. Setup.ios-* just contains the platform-specific build instructions (in much the same way as setup.py has configure_ctypes_darwin). To work around this completely, we'd need to either introduce the need for a bootstrap Python so that a post-configure setup could access the build instructions contained in setup.py, or massively refactor the process of building modules so that there was a set of build instructions that both makesetup and setup.py could use. |
This new patch (20150504.diff) adds support for running the Python test suite The new patch is standalone, and contains everything in the previous patch. An XCode project (Tools/iOS-test) has been added to the source tree; this project contains bootstrap C code to start and run the full Python regression test suite. There's also a new target in the iOS/Makefile meta-buildfile - "make test" - which will compile a debug version of the Python framework, and install it into the iOS-test project. Getting the test suite to run has revealed one major limitation of the iOS platform - system calls like fork, exec*, and spawn* don't work. The OS calls *exist* at an API level - but if you use them, they either crash, or they lock up the device while you wait for a subprocess that will never execute. This makes sense considering the platform itself - there's no such thing as a "background process" in iOS; background tasks are very heavily sandboxed. A number of other minor problems have been identified as a result of running the full test suite; they have been addressed in the patch. The test suite still has 5 failures on the simulator. I'm investigating the cause of these failures. There's a couple of more failures on a physical device - 13 failures in total. These device-specific failures appear to be largely due to ctypes problems and a permissions issue with os.mkdir. If you run the test suite in XCode as a debug binary, the debugger will stop whenever a SIGPIPE, SIGINT, SIGXFSZ, SIGUSR1 or SIGUSR2 signal is raised. You can just hit continue in the debugger, and the test will continue. To work around this, you need to run the following debugger commands before the first signal is raised: process handle SIGPIPE -n true -p true -s false I've been doing this by setting a breakpoint in the main.c method; I'm investigating other ways to automate this. |
Another patch update - the code now passes the full Python test suite on the iOS simulator. There are still a couple of failures on device; as before, these appear to be due to ctypes problems and a permissions issue with os.mkdir. |
Another update - this time, there are only 4 failing tests on device, all related to ctypes issues. The sample Xcode project and iOS-test harness have been modified, simplifying the project layout, and using Apple-preferred directories for resources when deployed to device. |
Another update - the issue with libffi has been resolved, so there is now only need for a single copy of libffi_ios sources. This directory could potentially be merged with the libffi_osx sources, except that libffi no longer supports PowerPC as a compilation target for OS/X builds (and neither does Apple). If PowerPC can be dropped from the list of supported platforms, libffi for OS X can be updated to the current trunk sources. |
Mac OS X 10.5 was the last version to support PowerPC architectures, and according to https://en.wikipedia.org/wiki/Mac_OS_X_Leopard#Release_history, the final version of that was 10.5.8, released in August 2009. While we don't have a section in https://www.python.org/dev/peps/pep-0011/ spelling out our support policy for Mac OS X the way we do for Windows, Ned is still making dual architecture binaries available for 2.7.x and 3.5.x as seen at https://www.python.org/downloads/release/python-2711/ and https://www.python.org/downloads/release/python-351/ |
I've done my best to rebase Freakboy's patch onto 3.6-dev. The attached applies cleanly, but the testsuite goes into an infinite loop. It's a start at least. At a guess the problem is in Lib/test/libregrtest/ or Lib/test/regrtest.py where the patch changes sys.exit() calls to return statements. I took the liberty of filtering out whitespace & other cosmetic changes that were in 20151221.diff. |
Alex - The usual cause for that problem isn't regrtest (at least, not directly). The cause is one of the tests in the suite spawning a subprocess. Due to the way the test harness works, when the test suite forks/spawns a subprocess (e.g., to run a network server or a multiprocess worker), the fork causes the a second version of the test suite to start, rather than starting the server subprocess. I've attached a patch for 3.5.1. This includes a patch to work around bpo-22625; the patch is definitely suboptimal, but it lets a build come to completion. What is really needed (as requested on python-dev) is some help working out how to fix bpo-22625 properly. |
Are you aware of Pythonista? I have no affiliation, but I'm a fan of the app and the community surrounding it. See http://omz-software.com/pythonista/ for details. I'm sure communication with the developer of the app could yield some useful insights. |
Yes - I'm aware of Pythonista; the author of that app contracted me to develop the 3.5 patch that is attached to this ticket :-) |
Ok, great! On Fri, Jun 3, 2016 at 7:34 AM Luke Taylor <luke@deentaylor.com> wrote:
|
Russell, this is excellent work!!!! I am truly amazed that within a couple of hours I had Python built and running for the iOS simulator this is a feat I didn't think was possible. Perspective on me I am very familiar with Linux, C, and Python but know very little about iOS and XCode keep that in mind when reviewing my comments. MacOS: 10.12.2 I applied your last patch file name 20160217.diff. The first issue I ran into was clock_settime() is unavailable in iOS so I went into timemodule.c line 164 and commented out the line: Next I think a more serious problem was with Python/random.c line 92 "Python/random.c:92:19: error: implicit declaration of function 'getentropy' is invalid in C99 [-Werror,-Wimplicit-function-declaration]" So I did the same thing as above commented out the lines with the getentropy function and added a line of res = 0. Who needs entropy anyway? I wonder if this problem is related to bpo-29057 (http://bugs.python.org/issue29057). Next in your README file you list a file called main.c when the actual code is main.m. Next main.m was not compiling with Xcode so I replaced with this line after looking at your Python-iOS-template project on GitHub, as I am not qualified to make these types of changes: -line 31 was not compiling so I replaced: -line 54 had a similar error so I replaced: -line 56 had a similar error so I replaced with this line: -line 89 comment it out to remove the assertion failure, I am not sure what I didn't want to blindly attach a diff as I don't understand the Apple lingo but I wanted to provide feedback in the hope that it helps get this patch committed so iOS becomes a target for CPython in the near future. Thanks! |
For those interested, I've started tracking these patches on Github: https://github.com/freakboy3742/cpython The 3.4, 3.5 and 3.6 branches are tested and compile as of the time of this comment; the master branch has also been updated, in preparation for the release of 3.7. I haven't submitted pull requests because there are still some issues that Ned raised in discussions at PyCon US. |
After discussion with @freakboy3742, we agreed that much has changed since this issue was opened and so it makes most sense to close this issue in favor of a new one, with PRs targeted for 3.13, that reflect the current approaches and changes needed in cpython, for the most part, simpler changes. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: