FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

gh-156109: Allow static, non-framework iOS builds by clementperon · Pull Request #156110 · python/cpython · GitHub

/ cpython Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .ac  (1) .md  (1) .rst  (3) No extension  (1) All 4 file types selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
15 changes: 15 additions & 0 deletions Doc/using/configure.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -1338,6 +1338,21 @@ See :source:`Platforms/Apple/iOS/README.md`.
Create a Python.framework. Unlike macOS, the *INSTALLDIR* argument
specifying the installation path is mandatory.

.. option:: --disable-framework

Build a static ``libpython`` for embedding directly in an app binary,
instead of a ``Python.framework``. An iOS build that specifies neither
``--enable-framework`` nor ``--disable-framework`` is an error.

A static build cannot load extension modules at runtime, and so does not
support binary wheels. Every restriction that follows from this must be
opted into explicitly: ``--disable-framework`` also requires
``--disable-shared``, ``MODULE_BUILDTYPE=static`` and
:option:`--disable-test-modules`. See
:source:`Platforms/Apple/iOS/README.md` for the full list of limitations.

.. versionadded:: 3.16

.. option:: --with-framework-name=FRAMEWORK

Specify the name for the framework (default: ``Python``).
Expand Down
7 changes: 7 additions & 0 deletions Doc/using/ios.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ should ensure these stub binaries are on your path.
Installing Python on iOS
========================

The official iOS release artefact is a framework build, distributed as an
``XCFramework``; this is the configuration described in the rest of this
document, and the only one that supports binary extension modules. Static
builds, where ``libpython`` and every extension module are linked directly into
the app binary, are also possible, with limitations; see
:source:`Platforms/Apple/iOS/README.md` for details.

Tools for building iOS apps
---------------------------

Expand Down
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
iOS builds may now be configured with ``--disable-framework``, producing a
static ``libpython`` for embedding in an app binary. This configuration cannot
load extension modules at runtime, and requires ``--disable-shared``,
``MODULE_BUILDTYPE=static`` and ``--disable-test-modules`` to be requested
explicitly. A shared iOS build must still be a framework build.
83 changes: 78 additions & 5 deletions Platforms/Apple/iOS/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,15 @@ Python build for a single framework, the following options are available.
installed. If `DIR` is not specified, the framework will be installed into
a subdirectory of the `iOS/Frameworks` folder.

This argument *must* be provided when configuring iOS builds. iOS does not
support non-framework builds.
Either this argument or `--disable-framework` *must* be provided when
configuring iOS builds; there is no default.

* `--disable-framework`

Build a static `libpython` for embedding directly in an app binary, instead
of a `Python.framework`. This configuration comes with significant
restrictions, each of which must be opted into explicitly; see [Building a
static Python](#building-a-static-python) below.

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

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

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

### Building a static Python

The official iOS release artefact is a framework build. However, if you are
embedding Python in an app that links `libpython` at compile time, you can
instead build a static `libpython3.x.a`, and link that archive directly into
your app binary.

The App Store requirement that binary modules be packaged as signed frameworks
does not apply to a static build, because a static build loads nothing at
runtime; but for the same reason, this configuration cannot use *any* binary
module that isn't compiled into the app binary. Every restriction that follows
from that must be opted into explicitly at configure time:

* `--disable-framework` selects a non-framework build. It is an error to
provide neither `--enable-framework` nor `--disable-framework`.

* `--disable-shared` is required. A shared iOS build must be a framework
build, as an iOS app can only load a signed framework, never a bare dylib.

* `MODULE_BUILDTYPE=static` is required. There is no framework for a shared
extension module to link against, so every extension module - including the
ones in the standard library - must be linked into `libpython`.

* `--disable-test-modules` is required. Some test modules must be compiled as
shared libraries (see `Modules/Setup.stdlib.in`), so they cannot be built in
this configuration at all.

The minimal commands for a static build targeting ARM64 iOS devices are then:
```
export PATH="$(pwd)/Platforms/Apple/iOS/Resources/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
./configure \
--disable-framework \
--disable-shared \
--disable-test-modules \
MODULE_BUILDTYPE=static \
--host=arm64-apple-ios \
--build=arm64-apple-darwin \
--with-build-python=/path/to/python.exe
make
make install
```
This produces a `libpython3.x.a` containing the interpreter and the standard
library's extension modules; `make install` installs that archive, along with
the standard library's Python source, into the location given by `--prefix`.

#### Limitations of a static build

* **Binary wheels cannot be used.** There is no `libpython` dylib for a
third-party extension module to link against, and a static Python has nothing
to `dlopen` in any case. Pure Python wheels work as normal; any package with a
C extension must be compiled into the app binary alongside `libpython`.

* **The standard library's extension modules are not loadable modules.** They
live in the archive, not in `.framework` bundles in the app's `Frameworks`
folder, so the packaging described in
[Using Python on iOS](https://docs.python.org/3/using/ios.html) does not apply
to them.

* **The test suite cannot be run as-is**, as the test modules are not built.

* This configuration is not covered by the `Platforms/Apple` build script, nor
by CPython's CI. It is not the configuration used to produce official
releases.

## Testing Python on iOS

### Testing a multi-architecture framework
Expand Down
32 changes: 27 additions & 5 deletions configure

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 26 additions & 5 deletions configure.ac
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,6 @@ AC_ARG_ENABLE([framework],
case $enableval in
no)
case $ac_sys_system in
iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;;
*)
PYTHONFRAMEWORK=
PYTHONFRAMEWORKDIR=no-framework
Expand Down Expand Up @@ -689,7 +688,7 @@ AC_ARG_ENABLE([framework],
esac
],[
case $ac_sys_system in
iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;;
iOS) AC_MSG_ERROR([iOS builds must use --enable-framework, or --disable-framework with --disable-shared to build a static libpython]) ;;
*)
PYTHONFRAMEWORK=
PYTHONFRAMEWORKDIR=no-framework
Expand Down Expand Up @@ -1695,6 +1694,10 @@ else # shared is disabled
fi
AC_MSG_RESULT([$LDLIBRARY])

if test "$ac_sys_system" = "iOS" && test "$PY_ENABLE_SHARED" = 1 && test -z "$PYTHONFRAMEWORK"; then
AC_MSG_ERROR([iOS builds must use --enable-framework, or --disable-framework with --disable-shared to build a static libpython])
fi

# HOSTRUNNER - Program to run CPython for the host platform
AC_MSG_CHECKING([HOSTRUNNER])
if test -z "$HOSTRUNNER"
Expand Down Expand Up @@ -3836,7 +3839,11 @@ then
fi
LINKFORSHARED="$LINKFORSHARED"
elif test $ac_sys_system = "iOS"; then
LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"

if test "$enable_framework"; then
LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
fi
fi
;;
OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";;
Expand Down Expand Up @@ -6761,8 +6768,9 @@ if test "$PY_ENABLE_SHARED" = "1" && ( test -n "$ANDROID_API_LEVEL" || test "$MA
LIBPYTHON="-lpython${VERSION}${ABIFLAGS}"
fi

# On iOS the shared libraries must be linked with the Python framework
if test "$ac_sys_system" = "iOS"; then
# On iOS the shared libraries must be linked with the Python framework, when one
# is being built
if test "$ac_sys_system" = "iOS" && test "$enable_framework"; then
MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)"
fi

Expand Down Expand Up @@ -8391,6 +8399,19 @@ AS_CASE([$host_cpu],
)
AC_SUBST([MODULE_BUILDTYPE])

dnl A non-framework iOS build is statically linked into the app binary. It has
dnl no framework for extension modules to link against, and cannot load them at
dnl runtime, so every extension module must be linked into libpython, and the
dnl test modules that must be built as shared libraries cannot be built at all
dnl (see Modules/Setup.stdlib.in). Each of those restrictions must be opted
dnl into explicitly.
AS_IF([test "$ac_sys_system" = "iOS" && test -z "$PYTHONFRAMEWORK"], [
AS_IF([test "$MODULE_BUILDTYPE" != "static"],
[AC_MSG_ERROR([non-framework iOS builds cannot build shared extension modules; configure with MODULE_BUILDTYPE=static])])
AS_IF([test "$TEST_MODULES" != "no"],
[AC_MSG_ERROR([non-framework iOS builds cannot build the shared test modules; configure with --disable-test-modules])])
])

dnl _MODULE_BLOCK_ADD([VAR], [VALUE])
dnl internal: adds $1=quote($2) to MODULE_BLOCK
AC_DEFUN([_MODULE_BLOCK_ADD], [AS_VAR_APPEND([MODULE_BLOCK], ["$1=_AS_QUOTE([$2])$as_nl"])])
Expand Down
Loading

Back | FazBrowse Home | New Git URL