Skip to content

Commit e61dffe

Browse files
clementperonclaudefreakboy3742
authored andcommitted
pythongh-156109: Allow static, non-framework iOS builds (python#156110)
Allows a static build of iOS for users that want to build and embed a libPython into an iOS binary. This configuration can't use shared modules or binary wheels, but it can be useful under some circumstances, so there's no reason to explicitly exclude it. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Russell Keith-Magee <russell@keith-magee.com>
1 parent 878d8f0 commit e61dffe

6 files changed

Lines changed: 216 additions & 101 deletions

File tree

‎Doc/using/configure.rst‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,6 +1342,16 @@ See :source:`Platforms/Apple/iOS/README.md`.
13421342

13431343
Specify the name for the framework (default: ``Python``).
13441344

1345+
An iOS build configured without ``--enable-framework`` produces a static
1346+
``libpython``, for embedding directly in an app binary. Such a build cannot
1347+
load extension modules at runtime, and so does not support binary wheels; it
1348+
requires ``MODULE_BUILDTYPE=static`` and :option:`--disable-test-modules`, and
1349+
rejects :option:`--enable-shared`. See
1350+
:source:`Platforms/Apple/iOS/README.md` for the full list of limitations.
1351+
1352+
.. versionadded:: 3.16
1353+
iOS builds may be configured without a framework.
1354+
13451355

13461356
Cross Compiling Options
13471357
-----------------------

‎Doc/using/ios.rst‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,13 @@ should ensure these stub binaries are on your path.
142142
Installing Python on iOS
143143
========================
144144

145+
The official iOS release artefact is a framework build, distributed as an
146+
``XCFramework``; this is the configuration described in the rest of this
147+
document, and the only one that supports binary extension modules. Static
148+
builds, where ``libpython`` and every extension module are linked directly into
149+
the app binary, are also possible, with limitations; see
150+
:source:`Platforms/Apple/iOS/README.md` for details.
151+
145152
Tools for building iOS apps
146153
---------------------------
147154

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
iOS builds may now be configured without a framework, producing a static
2+
``libpython`` for embedding in an app binary. Such a build cannot load extension
3+
modules at runtime, and requires ``MODULE_BUILDTYPE=static`` and
4+
``--disable-test-modules`` to be requested explicitly. A shared iOS build must
5+
still be a framework build.

‎Platforms/Apple/iOS/README.md‎

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,13 @@ Python build for a single framework, the following options are available.
9090
installed. If `DIR` is not specified, the framework will be installed into
9191
a subdirectory of the `iOS/Frameworks` folder.
9292

93-
This argument *must* be provided when configuring iOS builds. iOS does not
94-
support non-framework builds.
93+
This argument is required for any iOS build that will be distributed, and
94+
for any build that needs to load binary extension modules.
95+
96+
Omitting it builds a static `libpython` for embedding directly in an app
97+
binary, instead of a `Python.framework`. That configuration comes with
98+
significant restrictions; see [Building a static
99+
Python](#building-a-static-python) below.
95100

96101
* `--with-framework-name=NAME`
97102

@@ -113,9 +118,11 @@ framework to contain non-library content, so the iOS build will produce a
113118
The `lib` folder will be needed at runtime to support the Python library.
114119

115120
If you want to use Python in a real iOS project, you need to produce multiple
116-
`Python.framework` builds, one for each ABI and architecture. iOS builds of
117-
Python *must* be constructed as framework builds. To support this, you must
118-
provide the `--enable-framework` flag when configuring the build. The build
121+
`Python.framework` builds, one for each ABI and architecture. Unless you are
122+
statically linking Python into your app (see [Building a static
123+
Python](#building-a-static-python) below), iOS builds of Python *must* be
124+
constructed as framework builds. To support this, you must provide the
125+
`--enable-framework` flag when configuring the build. The build
119126
also requires the use of cross-compilation. The minimal commands for building
120127
Python for the ARM64 iOS simulator will look something like:
121128
```
@@ -216,6 +223,68 @@ target, provide the version number as part of the `--host` argument - for
216223
example, `--host=arm64-apple-ios15.4-simulator` would compile an ARM64
217224
simulator build with a deployment target of 15.4.
218225

226+
### Building a static Python
227+
228+
The official iOS release artefact is a framework build. However, if you are
229+
embedding Python in an app that links `libpython` at compile time, you can
230+
instead build a static `libpython3.x.a`, and link that archive directly into
231+
your app binary.
232+
233+
The App Store requirement that binary modules be packaged as signed frameworks
234+
does not apply to a static build, because a static build loads nothing at
235+
runtime; but for the same reason, this configuration cannot use *any* binary
236+
module that isn't compiled into the app binary. The restrictions that follow
237+
from that must be opted into explicitly at configure time:
238+
239+
* `MODULE_BUILDTYPE=static` is required. There is no framework for a shared
240+
extension module to link against, so every extension module, including the
241+
ones in the standard library, must be linked into `libpython`.
242+
243+
* `--disable-test-modules` is required. Some test modules must be compiled as
244+
shared libraries (see `Modules/Setup.stdlib.in`), so they cannot be built in
245+
this configuration at all.
246+
247+
A non-framework build is selected by omitting `--enable-framework`;
248+
`--disable-framework` is accepted as an explicit spelling of the same thing.
249+
250+
The minimal commands for a static build targeting ARM64 iOS devices are then:
251+
```
252+
export PATH="$(pwd)/Platforms/Apple/iOS/Resources/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
253+
./configure \
254+
--prefix=/path/to/install/dir \
255+
--disable-test-modules \
256+
MODULE_BUILDTYPE=static \
257+
--host=arm64-apple-ios \
258+
--build=arm64-apple-darwin \
259+
--with-build-python=/path/to/python.exe
260+
make
261+
make install
262+
```
263+
This produces a `libpython3.x.a` containing the interpreter and the standard
264+
library's extension modules; `make install` installs that archive, along with
265+
the standard library's Python source, into the location given by `--prefix`.
266+
Unlike a framework build, `--prefix` is not set for you, so specify it
267+
explicitly - otherwise `libpython` will be installed into `/usr/local`.
268+
269+
#### Limitations of a static build
270+
271+
* **Binary wheels cannot be used.** There is no `libpython` dylib for a
272+
third-party extension module to link against, and a static Python has nothing
273+
to `dlopen` in any case. Pure Python wheels work as normal; any package with a
274+
C extension must be compiled into the app binary alongside `libpython`.
275+
276+
* **The standard library's extension modules are not loadable modules.** They
277+
live in the archive, not in `.framework` bundles in the app's `Frameworks`
278+
folder, so the packaging described in
279+
[Using Python on iOS](https://docs.python.org/3/using/ios.html) does not apply
280+
to them.
281+
282+
* **The test suite cannot be run as-is**, as the test modules are not built.
283+
284+
* This configuration is not covered by the `Platforms/Apple` build script, nor
285+
by CPython's CI. It is not the configuration used to produce official
286+
releases.
287+
219288
## Testing Python on iOS
220289

221290
### Testing a multi-architecture framework

‎configure‎

Lines changed: 62 additions & 48 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)