gh-114099: Add configure and Makefile targets to support iOS compilation. (GH-115390)

This commit is contained in:
Russell Keith-Magee 2024-02-26 09:21:10 +08:00 committed by GitHub
parent e921f09c8a
commit bee7bb3310
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 851 additions and 106 deletions

1
.gitignore vendored
View File

@ -69,6 +69,7 @@ Lib/test/data/*
/_bootstrap_python
/Makefile
/Makefile.pre
iOS/Resources/Info.plist
Mac/Makefile
Mac/PythonLauncher/Info.plist
Mac/PythonLauncher/Makefile

View File

@ -912,6 +912,21 @@ $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \
$(LN) -fsn Versions/Current/$(PYTHONFRAMEWORK) $(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)
$(LN) -fsn Versions/Current/Resources $(PYTHONFRAMEWORKDIR)/Resources
# This rule is for iOS, which requires an annoyingly just slighly different
# format for frameworks to macOS. It *doesn't* use a versioned framework, and
# the Info.plist must be in the root of the framework.
$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK): \
$(LIBRARY) \
$(RESSRCDIR)/Info.plist
$(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)
$(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \
-all_load $(LIBRARY) \
-install_name $(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/$(PYTHONFRAMEWORK) \
-compatibility_version $(VERSION) \
-current_version $(VERSION) \
-framework CoreFoundation $(LIBS);
$(INSTALL_DATA) $(RESSRCDIR)/Info.plist $(PYTHONFRAMEWORKDIR)/Info.plist
# This rule builds the Cygwin Python DLL and import library if configured
# for a shared core library; otherwise, this rule is a noop.
$(DLLLIBRARY) libpython$(LDVERSION).dll.a: $(LIBRARY_OBJS)
@ -2607,10 +2622,11 @@ frameworkinstall: install
# only have to cater for the structural bits of the framework.
.PHONY: frameworkinstallframework
frameworkinstallframework: frameworkinstallstructure install frameworkinstallmaclib
frameworkinstallframework: @FRAMEWORKINSTALLFIRST@ install frameworkinstallmaclib
.PHONY: frameworkinstallstructure
frameworkinstallstructure: $(LDLIBRARY)
# macOS uses a versioned frameworks structure that includes a full install
.PHONY: frameworkinstallversionedstructure
frameworkinstallversionedstructure: $(LDLIBRARY)
@if test "$(PYTHONFRAMEWORKDIR)" = no-framework; then \
echo Not configured with --enable-framework; \
exit 1; \
@ -2631,6 +2647,27 @@ frameworkinstallstructure: $(LDLIBRARY)
$(LN) -fsn Versions/Current/Resources $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Resources
$(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY)
# iOS/tvOS/watchOS uses a non-versioned framework with Info.plist in the
# framework root, no .lproj data, and only stub compilation assistance binaries
.PHONY: frameworkinstallunversionedstructure
frameworkinstallunversionedstructure: $(LDLIBRARY)
@if test "$(PYTHONFRAMEWORKDIR)" = no-framework; then \
echo Not configured with --enable-framework; \
exit 1; \
else true; \
fi
if test -d $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include; then \
echo "Clearing stale header symlink directory"; \
rm -rf $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include; \
fi
$(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)
sed 's/%VERSION%/'"`$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Info.plist
$(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY)
$(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(BINDIR)
for file in $(srcdir)/$(RESSRCDIR)/bin/* ; do \
$(INSTALL) -m $(EXEMODE) $$file $(DESTDIR)$(BINDIR); \
done
# This installs Mac/Lib into the framework
# Install a number of symlinks to keep software that expects a normal unix
# install (which includes python-config) happy.
@ -2671,6 +2708,19 @@ frameworkaltinstallunixtools:
frameworkinstallextras:
cd Mac && $(MAKE) installextras DESTDIR="$(DESTDIR)"
# On iOS, bin/lib can't live inside the framework; include needs to be called
# "Headers", but *must* be in the framework, and *not* include the `python3.X`
# subdirectory. The install has put these folders in the same folder as
# Python.framework; Move the headers to their final framework-compatible home.
.PHONY: frameworkinstallmobileheaders
frameworkinstallmobileheaders:
if test -d $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers; then \
echo "Removing old framework headers"; \
rm -rf $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers; \
fi
mv "$(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include/python$(VERSION)" "$(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers"
$(LN) -fs "../$(PYTHONFRAMEWORKDIR)/Headers" "$(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include/python$(VERSION)"
# Build the toplevel Makefile
Makefile.pre: $(srcdir)/Makefile.pre.in config.status
CONFIG_FILES=Makefile.pre CONFIG_HEADERS= ./config.status

View File

@ -0,0 +1,2 @@
Makefile targets were added to support compiling an iOS-compatible framework
build.

View File

@ -233,7 +233,22 @@ PLATFORM_TRIPLET=i386-gnu
# error unknown platform triplet
# endif
#elif defined(__APPLE__)
# include "TargetConditionals.h"
# if TARGET_OS_IOS
# if TARGET_OS_SIMULATOR
# if __x86_64__
PLATFORM_TRIPLET=x86_64-iphonesimulator
# else
PLATFORM_TRIPLET=arm64-iphonesimulator
# endif
# else
PLATFORM_TRIPLET=arm64-iphoneos
# endif
# elif TARGET_OS_OSX
PLATFORM_TRIPLET=darwin
# else
# error unknown Apple platform
# endif
#elif defined(__VXWORKS__)
PLATFORM_TRIPLET=vxworks
#elif defined(__wasm32__)

5
config.sub vendored
View File

@ -4,6 +4,7 @@
# shellcheck disable=SC2006,SC2268 # see below for rationale
# Patched 2024-02-03 to include support for arm64_32 and iOS/tvOS/watchOS simulators
timestamp='2024-01-01'
# This file is free software; you can redistribute it and/or modify it
@ -1127,7 +1128,7 @@ case $cpu-$vendor in
xscale-* | xscalee[bl]-*)
cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
;;
arm64-* | aarch64le-*)
arm64-* | aarch64le-* | arm64_32-*)
cpu=aarch64
;;
@ -1866,6 +1867,8 @@ case $kernel-$os-$obj in
;;
*-eabi*- | *-gnueabi*-)
;;
ios*-simulator- | tvos*-simulator- | watchos*-simulator- )
;;
none--*)
# None (no kernel, i.e. freestanding / bare metal),
# can be paired with an machine code file format

207
configure generated vendored
View File

@ -970,6 +970,7 @@ LDFLAGS
CFLAGS
CC
HAS_XCRUN
IOS_DEPLOYMENT_TARGET
EXPORT_MACOSX_DEPLOYMENT_TARGET
CONFIGURE_MACOSX_DEPLOYMENT_TARGET
_PYTHON_HOST_PLATFORM
@ -4029,6 +4030,9 @@ then
*-*-cygwin*)
ac_sys_system=Cygwin
;;
*-apple-ios*)
ac_sys_system=iOS
;;
*-*-vxworks*)
ac_sys_system=VxWorks
;;
@ -4194,10 +4198,18 @@ then :
enableval=$enable_framework;
case $enableval in
yes)
if test "$ac_sys_system" = "iOS"; then
as_fn_error $? "iOS builds must provide an explicit path for --enable-framework" "$LINENO" 5
fi
enableval=/Library/Frameworks
esac
case $enableval in
no)
if test "$ac_sys_system" = "iOS"; then
as_fn_error $? "iOS builds must use --enable-framework=<install path>" "$LINENO" 5
fi
PYTHONFRAMEWORK=
PYTHONFRAMEWORKDIR=no-framework
PYTHONFRAMEWORKPREFIX=
@ -4221,11 +4233,11 @@ then :
*)
PYTHONFRAMEWORKPREFIX="${enableval}"
PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR
FRAMEWORKINSTALLFIRST="frameworkinstallstructure"
FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure "
case $ac_sys_system in #(
Darwin) :
FRAMEWORKINSTALLFIRST="frameworkinstallversionedstructure"
FRAMEWORKALTINSTALLFIRST="frameworkinstallversionedstructure "
FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools"
FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools"
FRAMEWORKPYTHONW="frameworkpythonw"
@ -4287,6 +4299,21 @@ then :
ac_config_files="$ac_config_files Mac/Resources/app/Info.plist"
;;
iOS) :
FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
FRAMEWORKPYTHONW=
INSTALLTARGETS="libinstall inclinstall sharedinstall"
prefix=$PYTHONFRAMEWORKPREFIX
PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
RESSRCDIR=iOS/Resources
ac_config_files="$ac_config_files iOS/Resources/Info.plist"
;;
*)
as_fn_error $? "Unknown platform for framework build" "$LINENO" 5
@ -4296,6 +4323,10 @@ then :
else $as_nop
if test "$ac_sys_system" = "iOS"; then
as_fn_error $? "iOS builds must use --enable-framework=<install path>" "$LINENO" 5
fi
PYTHONFRAMEWORK=
PYTHONFRAMEWORKDIR=no-framework
PYTHONFRAMEWORKPREFIX=
@ -4353,6 +4384,23 @@ if test "$cross_compiling" = yes; then
*-*-cygwin*)
_host_ident=
;;
*-apple-ios*)
_host_os=`echo $host | cut -d '-' -f3`
_host_device=`echo $host | cut -d '-' -f4`
_host_device=${_host_device:=os}
IOS_DEPLOYMENT_TARGET=${_host_os:3}
IOS_DEPLOYMENT_TARGET=${IOS_DEPLOYMENT_TARGET:=12.0}
case "$host_cpu" in
aarch64)
_host_ident=${IOS_DEPLOYMENT_TARGET}-arm64-iphone${_host_device}
;;
*)
_host_ident=${IOS_DEPLOYMENT_TARGET}-$host_cpu-iphone${_host_device}
;;
esac
;;
*-*-vxworks*)
_host_ident=$host_cpu
;;
@ -4431,6 +4479,9 @@ printf "%s\n" "#define _BSD_SOURCE 1" >>confdefs.h
define_xopen_source=no;;
Darwin/[12][0-9].*)
define_xopen_source=no;;
# On iOS, defining _POSIX_C_SOURCE also disables platform specific features.
iOS/*)
define_xopen_source=no;;
# On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
# defining NI_NUMERICHOST.
QNX/6.3.2)
@ -4525,6 +4576,17 @@ case $host in #(
;;
esac
case $ac_sys_system in #(
iOS) :
as_fn_append CFLAGS " -mios-version-min=${IOS_DEPLOYMENT_TARGET}"
as_fn_append LDFLAGS " -mios-version-min=${IOS_DEPLOYMENT_TARGET}"
;; #(
*) :
;;
esac
if test "$ac_sys_system" = "Darwin"
then
# Extract the first word of "xcrun", so it can be a program name with args.
@ -6787,6 +6849,8 @@ printf %s "checking for multiarch... " >&6; }
case $ac_sys_system in #(
Darwin*) :
MULTIARCH="" ;; #(
iOS) :
MULTIARCH="" ;; #(
FreeBSD*) :
MULTIARCH="" ;; #(
*) :
@ -6807,6 +6871,8 @@ fi
printf "%s\n" "$MULTIARCH" >&6; }
case $ac_sys_system in #(
iOS) :
SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #(
*) :
SOABI_PLATFORM=$PLATFORM_TRIPLET
;;
@ -6852,6 +6918,10 @@ case $host/$ac_cv_cc_name in #(
PY_SUPPORT_TIER=3 ;; #(
x86_64-*-freebsd*/clang) :
PY_SUPPORT_TIER=3 ;; #(
aarch64-apple-ios*-simulator/clang) :
PY_SUPPORT_TIER=3 ;; #(
aarch64-apple-ios*/clang) :
PY_SUPPORT_TIER=3 ;; #(
*) :
PY_SUPPORT_TIER=0
;;
@ -7307,12 +7377,15 @@ printf %s "checking LDLIBRARY... " >&6; }
# will find it with a -framework option). For this reason there is an
# extra variable BLDLIBRARY against which Python and the extension
# modules are linked, BLDLIBRARY. This is normally the same as
# LDLIBRARY, but empty for MacOSX framework builds.
# LDLIBRARY, but empty for MacOSX framework builds. iOS does the same,
# but uses a non-versioned framework layout.
if test "$enable_framework"
then
case $ac_sys_system in
Darwin)
LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';;
iOS)
LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';;
*)
as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;;
esac
@ -7371,6 +7444,9 @@ printf "%s\n" "#define Py_ENABLE_SHARED 1" >>confdefs.h
BLDLIBRARY='-L. -lpython$(LDVERSION)'
RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}
;;
iOS)
LDLIBRARY='libpython$(LDVERSION).dylib'
;;
AIX*)
LDLIBRARY='libpython$(LDVERSION).so'
RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}}
@ -12624,6 +12700,7 @@ if test -z "$SHLIB_SUFFIX"; then
esac
;;
CYGWIN*) SHLIB_SUFFIX=.dll;;
iOS) SHLIB_SUFFIX=.dylib;;
*) SHLIB_SUFFIX=.so;;
esac
fi
@ -12706,6 +12783,11 @@ then
BLDSHARED="$LDSHARED"
fi
;;
iOS/*)
LDSHARED='$(CC) -dynamiclib -F . -framework Python'
LDCXXSHARED='$(CXX) -dynamiclib -F . -framework Python'
BLDSHARED="$LDSHARED"
;;
Emscripten|WASI)
LDSHARED='$(CC) -shared'
LDCXXSHARED='$(CXX) -shared';;
@ -12834,7 +12916,7 @@ then
Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";;
Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";;
# -u libsys_s pulls in all symbols in libsys
Darwin/*)
Darwin/*|iOS/*)
LINKFORSHARED="$extra_undefs -framework CoreFoundation"
# Issue #18075: the default maximum stack size (8MBytes) is too
@ -12847,17 +12929,21 @@ then
stack_size="4000000" # 64 MB
fi
LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"
printf "%s\n" "#define THREAD_STACK_SIZE 0x$stack_size" >>confdefs.h
if test "$enable_framework"
then
if test $ac_sys_system = "Darwin"; then
LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"
if test "$enable_framework"; then
LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
fi
LINKFORSHARED="$LINKFORSHARED";;
LINKFORSHARED="$LINKFORSHARED"
elif test $ac_sys_system = "iOS"; then
LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
fi
;;
OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";;
SCO_SV*) LINKFORSHARED="-Wl,-Bexport";;
ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";;
@ -14244,6 +14330,10 @@ then :
case $ac_sys_system in #(
Darwin) :
ctypes_malloc_closure=yes
;; #(
iOS) :
ctypes_malloc_closure=yes
;; #(
sunos5) :
@ -17499,12 +17589,6 @@ if test "x$ac_cv_func_getegid" = xyes
then :
printf "%s\n" "#define HAVE_GETEGID 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
if test "x$ac_cv_func_getentropy" = xyes
then :
printf "%s\n" "#define HAVE_GETENTROPY 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "geteuid" "ac_cv_func_geteuid"
if test "x$ac_cv_func_geteuid" = xyes
@ -17547,12 +17631,6 @@ if test "x$ac_cv_func_getgrouplist" = xyes
then :
printf "%s\n" "#define HAVE_GETGROUPLIST 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups"
if test "x$ac_cv_func_getgroups" = xyes
then :
printf "%s\n" "#define HAVE_GETGROUPS 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "gethostname" "ac_cv_func_gethostname"
if test "x$ac_cv_func_gethostname" = xyes
@ -18279,12 +18357,6 @@ if test "x$ac_cv_func_sysconf" = xyes
then :
printf "%s\n" "#define HAVE_SYSCONF 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "system" "ac_cv_func_system"
if test "x$ac_cv_func_system" = xyes
then :
printf "%s\n" "#define HAVE_SYSTEM 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "tcgetpgrp" "ac_cv_func_tcgetpgrp"
if test "x$ac_cv_func_tcgetpgrp" = xyes
@ -18463,6 +18535,32 @@ fi
fi
# iOS defines some system methods that can be linked (so they are
# found by configure), but either raise a compilation error (because the
# header definition prevents usage - autoconf doesn't use the headers), or
# raise an error if used at runtime. Force these symbols off.
if test "$ac_sys_system" != "iOS" ; then
ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
if test "x$ac_cv_func_getentropy" = xyes
then :
printf "%s\n" "#define HAVE_GETENTROPY 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "getgroups" "ac_cv_func_getgroups"
if test "x$ac_cv_func_getgroups" = xyes
then :
printf "%s\n" "#define HAVE_GETGROUPS 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "system" "ac_cv_func_system"
if test "x$ac_cv_func_system" = xyes
then :
printf "%s\n" "#define HAVE_SYSTEM 1" >>confdefs.h
fi
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
if test ${ac_cv_c_undeclared_builtin_options+y}
@ -21758,6 +21856,10 @@ fi
done
# On iOS, clock_settime can be linked (so it is found by
# configure), but it raises a runtime error if used because apps can't change
# the clock. Force the symbol off.
if test "$ac_sys_system" != "iOS" ; then
for ac_func in clock_settime
do :
@ -21815,6 +21917,7 @@ fi
fi
done
fi
for ac_func in clock_nanosleep
@ -23963,16 +24066,23 @@ LDVERSION='$(VERSION)$(ABIFLAGS)'
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDVERSION" >&5
printf "%s\n" "$LDVERSION" >&6; }
# On Android and Cygwin the shared libraries must be linked with libpython.
# Configure the flags and dependencies used when compiling shared modules
MODULE_DEPS_SHARED='$(MODULE_DEPS_STATIC) $(EXPORTSYMS)'
MODULE_LDFLAGS=''
# On Android and Cygwin the shared libraries must be linked with libpython.
if test "$PY_ENABLE_SHARED" = "1" && ( test -n "$ANDROID_API_LEVEL" || test "$MACHDEP" = "cygwin"); then
MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(LDLIBRARY)"
MODULE_LDFLAGS="\$(BLDLIBRARY)"
fi
# On iOS the shared libraries must be linked with the Python framework
if test "$ac_sys_system" == "iOS"; then
MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)"
fi
BINLIBDEST='$(LIBDIR)/python$(VERSION)'
@ -26702,7 +26812,11 @@ CPPFLAGS=$ac_save_cppflags
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5
printf "%s\n" "$as_me: checking for device files" >&6;}
if test "x$cross_compiling" = xyes; then
if test "$ac_sys_system" = "iOS" ; then
ac_cv_file__dev_ptmx=no
ac_cv_file__dev_ptc=no
else
if test "x$cross_compiling" = xyes; then
if test "${ac_cv_file__dev_ptmx+set}" != set; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5
printf %s "checking for /dev/ptmx... " >&6; }
@ -26717,9 +26831,9 @@ printf %s "checking for /dev/ptc... " >&6; }
printf "%s\n" "not set" >&6; }
as_fn_error $? "set ac_cv_file__dev_ptc to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5
fi
fi
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5
printf %s "checking for /dev/ptmx... " >&6; }
if test ${ac_cv_file__dev_ptmx+y}
then :
@ -26740,12 +26854,12 @@ then :
fi
if test "x$ac_cv_file__dev_ptmx" = xyes; then
if test "x$ac_cv_file__dev_ptmx" = xyes; then
printf "%s\n" "#define HAVE_DEV_PTMX 1" >>confdefs.h
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5
printf %s "checking for /dev/ptc... " >&6; }
if test ${ac_cv_file__dev_ptc+y}
then :
@ -26766,10 +26880,11 @@ then :
fi
if test "x$ac_cv_file__dev_ptc" = xyes; then
if test "x$ac_cv_file__dev_ptc" = xyes; then
printf "%s\n" "#define HAVE_DEV_PTC 1" >>confdefs.h
fi
fi
if test $ac_sys_system = Darwin
@ -28154,6 +28269,27 @@ case $ac_sys_system in #(
py_cv_module_grp=n/a
;; #(
Darwin) :
;; #(
iOS) :
py_cv_module__curses=n/a
py_cv_module__curses_panel=n/a
py_cv_module__gdbm=n/a
py_cv_module__multiprocessing=n/a
py_cv_module__posixshmem=n/a
py_cv_module__posixsubprocess=n/a
py_cv_module__scproxy=n/a
py_cv_module__tkinter=n/a
py_cv_module_grp=n/a
py_cv_module_nis=n/a
py_cv_module_readline=n/a
py_cv_module_pwd=n/a
py_cv_module_spwd=n/a
py_cv_module_syslog=n/a
py_cv_module_=n/a
;; #(
CYGWIN*) :
@ -31766,6 +31902,7 @@ do
"Mac/PythonLauncher/Makefile") CONFIG_FILES="$CONFIG_FILES Mac/PythonLauncher/Makefile" ;;
"Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;;
"Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;;
"iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;;
"Makefile.pre") CONFIG_FILES="$CONFIG_FILES Makefile.pre" ;;
"Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;;
"Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;;

View File

@ -327,6 +327,9 @@ then
*-*-cygwin*)
ac_sys_system=Cygwin
;;
*-apple-ios*)
ac_sys_system=iOS
;;
*-*-vxworks*)
ac_sys_system=VxWorks
;;
@ -484,10 +487,18 @@ AC_ARG_ENABLE([framework],
[
case $enableval in
yes)
if test "$ac_sys_system" = "iOS"; then
AC_MSG_ERROR([iOS builds must provide an explicit path for --enable-framework])
fi
enableval=/Library/Frameworks
esac
case $enableval in
no)
if test "$ac_sys_system" = "iOS"; then
AC_MSG_ERROR([iOS builds must use --enable-framework=<install path>])
fi
PYTHONFRAMEWORK=
PYTHONFRAMEWORKDIR=no-framework
PYTHONFRAMEWORKPREFIX=
@ -511,11 +522,11 @@ AC_ARG_ENABLE([framework],
*)
PYTHONFRAMEWORKPREFIX="${enableval}"
PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR
FRAMEWORKINSTALLFIRST="frameworkinstallstructure"
FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure "
case $ac_sys_system in #(
Darwin) :
FRAMEWORKINSTALLFIRST="frameworkinstallversionedstructure"
FRAMEWORKALTINSTALLFIRST="frameworkinstallversionedstructure "
FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools"
FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools"
FRAMEWORKPYTHONW="frameworkpythonw"
@ -574,12 +585,30 @@ AC_ARG_ENABLE([framework],
AC_CONFIG_FILES([Mac/Resources/framework/Info.plist])
AC_CONFIG_FILES([Mac/Resources/app/Info.plist])
;;
iOS) :
FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
FRAMEWORKPYTHONW=
INSTALLTARGETS="libinstall inclinstall sharedinstall"
prefix=$PYTHONFRAMEWORKPREFIX
PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
RESSRCDIR=iOS/Resources
AC_CONFIG_FILES([iOS/Resources/Info.plist])
;;
*)
AC_MSG_ERROR([Unknown platform for framework build])
;;
esac
esac
],[
if test "$ac_sys_system" = "iOS"; then
AC_MSG_ERROR([iOS builds must use --enable-framework=<install path>])
fi
PYTHONFRAMEWORK=
PYTHONFRAMEWORKDIR=no-framework
PYTHONFRAMEWORKPREFIX=
@ -634,6 +663,24 @@ if test "$cross_compiling" = yes; then
*-*-cygwin*)
_host_ident=
;;
*-apple-ios*)
_host_os=`echo $host | cut -d '-' -f3`
_host_device=`echo $host | cut -d '-' -f4`
_host_device=${_host_device:=os}
dnl IOS_DEPLOYMENT_TARGET is the minimum supported iOS version
IOS_DEPLOYMENT_TARGET=${_host_os:3}
IOS_DEPLOYMENT_TARGET=${IOS_DEPLOYMENT_TARGET:=12.0}
case "$host_cpu" in
aarch64)
_host_ident=${IOS_DEPLOYMENT_TARGET}-arm64-iphone${_host_device}
;;
*)
_host_ident=${IOS_DEPLOYMENT_TARGET}-$host_cpu-iphone${_host_device}
;;
esac
;;
*-*-vxworks*)
_host_ident=$host_cpu
;;
@ -711,6 +758,9 @@ case $ac_sys_system/$ac_sys_release in
define_xopen_source=no;;
Darwin/@<:@[12]@:>@@<:@0-9@:>@.*)
define_xopen_source=no;;
# On iOS, defining _POSIX_C_SOURCE also disables platform specific features.
iOS/*)
define_xopen_source=no;;
# On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
# defining NI_NUMERICHOST.
QNX/6.3.2)
@ -801,6 +851,15 @@ AS_CASE([$host],
],
)
dnl Add the compiler flag for the iOS minimum supported OS version.
AS_CASE([$ac_sys_system],
[iOS], [
AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IOS_DEPLOYMENT_TARGET}"])
AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IOS_DEPLOYMENT_TARGET}"])
AC_SUBST([IOS_DEPLOYMENT_TARGET])
],
)
if test "$ac_sys_system" = "Darwin"
then
dnl look for SDKROOT
@ -967,6 +1026,7 @@ dnl platforms.
AC_MSG_CHECKING([for multiarch])
AS_CASE([$ac_sys_system],
[Darwin*], [MULTIARCH=""],
[iOS], [MULTIARCH=""],
[FreeBSD*], [MULTIARCH=""],
[MULTIARCH=$($CC --print-multiarch 2>/dev/null)]
)
@ -988,6 +1048,7 @@ dnl will have multiple sysconfig modules (one for each CPU architecture), but
dnl use a single "fat" binary at runtime. SOABI_PLATFORM is the component of
dnl the PLATFORM_TRIPLET that will be used in binary module extensions.
AS_CASE([$ac_sys_system],
[iOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`],
[SOABI_PLATFORM=$PLATFORM_TRIPLET]
)
@ -1019,6 +1080,8 @@ AS_CASE([$host/$ac_cv_cc_name],
[powerpc64le-*-linux-gnu/clang], [PY_SUPPORT_TIER=3], dnl Linux on PPC64 little endian, glibc, clang
[s390x-*-linux-gnu/gcc], [PY_SUPPORT_TIER=3], dnl Linux on 64bit s390x (big endian), glibc, gcc
[x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64
[aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64
[aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64
[PY_SUPPORT_TIER=0]
)
@ -1337,12 +1400,15 @@ AC_MSG_CHECKING([LDLIBRARY])
# will find it with a -framework option). For this reason there is an
# extra variable BLDLIBRARY against which Python and the extension
# modules are linked, BLDLIBRARY. This is normally the same as
# LDLIBRARY, but empty for MacOSX framework builds.
# LDLIBRARY, but empty for MacOSX framework builds. iOS does the same,
# but uses a non-versioned framework layout.
if test "$enable_framework"
then
case $ac_sys_system in
Darwin)
LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';;
iOS)
LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';;
*)
AC_MSG_ERROR([Unknown platform for framework build]);;
esac
@ -1400,6 +1466,9 @@ if test $enable_shared = "yes"; then
BLDLIBRARY='-L. -lpython$(LDVERSION)'
RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}
;;
iOS)
LDLIBRARY='libpython$(LDVERSION).dylib'
;;
AIX*)
LDLIBRARY='libpython$(LDVERSION).so'
RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}}
@ -3167,6 +3236,7 @@ if test -z "$SHLIB_SUFFIX"; then
esac
;;
CYGWIN*) SHLIB_SUFFIX=.dll;;
iOS) SHLIB_SUFFIX=.dylib;;
*) SHLIB_SUFFIX=.so;;
esac
fi
@ -3247,6 +3317,11 @@ then
BLDSHARED="$LDSHARED"
fi
;;
iOS/*)
LDSHARED='$(CC) -dynamiclib -F . -framework Python'
LDCXXSHARED='$(CXX) -dynamiclib -F . -framework Python'
BLDSHARED="$LDSHARED"
;;
Emscripten|WASI)
LDSHARED='$(CC) -shared'
LDCXXSHARED='$(CXX) -shared';;
@ -3366,7 +3441,7 @@ then
Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";;
Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";;
# -u libsys_s pulls in all symbols in libsys
Darwin/*)
Darwin/*|iOS/*)
LINKFORSHARED="$extra_undefs -framework CoreFoundation"
# Issue #18075: the default maximum stack size (8MBytes) is too
@ -3379,17 +3454,21 @@ then
stack_size="4000000" # 64 MB
fi
LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"
AC_DEFINE_UNQUOTED([THREAD_STACK_SIZE],
[0x$stack_size],
[Custom thread stack size depending on chosen sanitizer runtimes.])
if test "$enable_framework"
then
if test $ac_sys_system = "Darwin"; then
LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED"
if test "$enable_framework"; then
LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
fi
LINKFORSHARED="$LINKFORSHARED";;
LINKFORSHARED="$LINKFORSHARED"
elif test $ac_sys_system = "iOS"; then
LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
fi
;;
OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";;
SCO_SV*) LINKFORSHARED="-Wl,-Bexport";;
ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";;
@ -3763,6 +3842,9 @@ AS_VAR_IF([have_libffi], [yes], [
dnl when do we need USING_APPLE_OS_LIBFFI?
ctypes_malloc_closure=yes
],
[iOS], [
ctypes_malloc_closure=yes
],
[sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])]
)
AS_VAR_IF([ctypes_malloc_closure], [yes], [
@ -4829,8 +4911,8 @@ AC_CHECK_FUNCS([ \
copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \
faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \
fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \
gai_strerror getegid getentropy geteuid getgid getgrent getgrgid getgrgid_r \
getgrnam_r getgrouplist getgroups gethostname getitimer getloadavg getlogin \
gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \
getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \
getpeername getpgid getpid getppid getpriority _getpty \
getpwent getpwnam_r getpwuid getpwuid_r getresgid getresuid getrusage getsid getspent \
getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \
@ -4847,7 +4929,7 @@ AC_CHECK_FUNCS([ \
setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \
sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \
sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \
sysconf system tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \
tmpnam tmpnam_r truncate ttyname umask uname unlinkat unlockpt utimensat utimes vfork \
wait wait3 wait4 waitid waitpid wcscoll wcsftime wcsxfrm wmemcmp writev \
])
@ -4859,6 +4941,14 @@ if test "$MACHDEP" != linux; then
AC_CHECK_FUNCS([lchmod])
fi
# iOS defines some system methods that can be linked (so they are
# found by configure), but either raise a compilation error (because the
# header definition prevents usage - autoconf doesn't use the headers), or
# raise an error if used at runtime. Force these symbols off.
if test "$ac_sys_system" != "iOS" ; then
AC_CHECK_FUNCS([getentropy getgroups system])
fi
AC_CHECK_DECL([dirfd],
[AC_DEFINE([HAVE_DIRFD], [1],
[Define if you have the 'dirfd' function or macro.])],
@ -5159,11 +5249,16 @@ AC_CHECK_FUNCS([clock_getres], [], [
])
])
AC_CHECK_FUNCS([clock_settime], [], [
# On iOS, clock_settime can be linked (so it is found by
# configure), but it raises a runtime error if used because apps can't change
# the clock. Force the symbol off.
if test "$ac_sys_system" != "iOS" ; then
AC_CHECK_FUNCS([clock_settime], [], [
AC_CHECK_LIB([rt], [clock_settime], [
AC_DEFINE([HAVE_CLOCK_SETTIME], [1])
])
])
])
fi
AC_CHECK_FUNCS([clock_nanosleep], [], [
AC_CHECK_LIB([rt], [clock_nanosleep], [
@ -5885,16 +5980,23 @@ AC_MSG_CHECKING([LDVERSION])
LDVERSION='$(VERSION)$(ABIFLAGS)'
AC_MSG_RESULT([$LDVERSION])
# On Android and Cygwin the shared libraries must be linked with libpython.
# Configure the flags and dependencies used when compiling shared modules
AC_SUBST([MODULE_DEPS_SHARED])
AC_SUBST([MODULE_LDFLAGS])
MODULE_DEPS_SHARED='$(MODULE_DEPS_STATIC) $(EXPORTSYMS)'
MODULE_LDFLAGS=''
# On Android and Cygwin the shared libraries must be linked with libpython.
if test "$PY_ENABLE_SHARED" = "1" && ( test -n "$ANDROID_API_LEVEL" || test "$MACHDEP" = "cygwin"); then
MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(LDLIBRARY)"
MODULE_LDFLAGS="\$(BLDLIBRARY)"
fi
# On iOS the shared libraries must be linked with the Python framework
if test "$ac_sys_system" == "iOS"; then
MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)"
fi
AC_SUBST([BINLIBDEST])
BINLIBDEST='$(LIBDIR)/python$(VERSION)'
@ -6520,7 +6622,13 @@ CPPFLAGS=$ac_save_cppflags
AC_MSG_NOTICE([checking for device files])
dnl NOTE: Inform user how to proceed with files when cross compiling.
if test "x$cross_compiling" = xyes; then
dnl iOS cross-compile builds are predictable; they won't ever
dnl have /dev/ptmx or /dev/ptc, so we can set them explicitly.
if test "$ac_sys_system" = "iOS" ; then
ac_cv_file__dev_ptmx=no
ac_cv_file__dev_ptc=no
else
if test "x$cross_compiling" = xyes; then
if test "${ac_cv_file__dev_ptmx+set}" != set; then
AC_MSG_CHECKING([for /dev/ptmx])
AC_MSG_RESULT([not set])
@ -6531,17 +6639,18 @@ if test "x$cross_compiling" = xyes; then
AC_MSG_RESULT([not set])
AC_MSG_ERROR([set ac_cv_file__dev_ptc to yes/no in your CONFIG_SITE file when cross compiling])
fi
fi
fi
AC_CHECK_FILE([/dev/ptmx], [], [])
if test "x$ac_cv_file__dev_ptmx" = xyes; then
AC_CHECK_FILE([/dev/ptmx], [], [])
if test "x$ac_cv_file__dev_ptmx" = xyes; then
AC_DEFINE([HAVE_DEV_PTMX], [1],
[Define to 1 if you have the /dev/ptmx device file.])
fi
AC_CHECK_FILE([/dev/ptc], [], [])
if test "x$ac_cv_file__dev_ptc" = xyes; then
fi
AC_CHECK_FILE([/dev/ptc], [], [])
if test "x$ac_cv_file__dev_ptc" = xyes; then
AC_DEFINE([HAVE_DEV_PTC], [1],
[Define to 1 if you have the /dev/ptc device file.])
fi
fi
if test $ac_sys_system = Darwin
@ -7181,6 +7290,28 @@ AS_CASE([$ac_sys_system],
[VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])],
dnl The _scproxy module is available on macOS
[Darwin], [],
[iOS], [
dnl subprocess and multiprocessing are not supported (no fork syscall).
dnl curses and tkinter user interface are not available.
dnl gdbm and nis aren't available
dnl Stub implementations are provided for pwd, grp etc APIs
PY_STDLIB_MOD_SET_NA(
[_curses],
[_curses_panel],
[_gdbm],
[_multiprocessing],
[_posixshmem],
[_posixsubprocess],
[_scproxy],
[_tkinter],
[grp],
[nis],
[readline],
[pwd],
[spwd],
[syslog],
)
],
[CYGWIN*], [PY_STDLIB_MOD_SET_NA([_scproxy])],
[QNX*], [PY_STDLIB_MOD_SET_NA([_scproxy])],
[FreeBSD*], [PY_STDLIB_MOD_SET_NA([_scproxy])],

321
iOS/README.rst Normal file
View File

@ -0,0 +1,321 @@
====================
Python on iOS README
====================
:Authors:
Russell Keith-Magee (2023-11)
This document provides a quick overview of some iOS specific features in the
Python distribution.
These instructions are only needed if you're planning to compile Python for iOS
yourself. Most users should *not* need to do this. If you're looking to
experiment with writing an iOS app in Python, tools such as `BeeWare's Briefcase
<https://briefcase.readthedocs.io>`__ and `Kivy's Buildozer
<https://buildozer.readthedocs.io>`__ will provide a much more approachable
user experience.
Compilers for building on iOS
=============================
Building for iOS requires the use of Apple's Xcode tooling. It is strongly
recommended that you use the most recent stable release of Xcode. This will
require the use of the most (or second-most) recently released macOS version,
as Apple does not maintain Xcode for older macOS versions. The Xcode Command
Line Tools are not sufficient for iOS development; you need a *full* Xcode
install.
If you want to run your code on the iOS simulator, you'll also need to install
an iOS Simulator Platform. You should be prompted to select an iOS Simulator
Platform when you first run Xcode. Alternatively, you can add an iOS Simulator
Platform by selecting an open the Platforms tab of the Xcode Settings panel.
iOS specific arguments to configure
===================================
* ``--enable-framework=DIR``
This argument specifies the location where the Python.framework will be
installed. This argument is required for all iOS builds; a directory *must*
be specified.
* ``--with-framework-name=NAME``
Specify the name for the Python framework; defaults to ``Python``.
Building Python on iOS
======================
ABIs and Architectures
----------------------
iOS apps can be deployed on physical devices, and on the iOS simulator. Although
the API used on these devices is identical, the ABI is different - you need to
link against different libraries for an iOS device build (``iphoneos``) or an
iOS simulator build (``iphonesimulator``).
Apple uses the ``XCframework`` format to allow specifying a single dependency
that supports multiple ABIs. An ``XCframework`` is a wrapper around multiple
ABI-specific frameworks that share a common API.
iOS can also support different CPU architectures within each ABI. At present,
there is only a single supported architecture on physical devices - ARM64.
However, the *simulator* supports 2 architectures - ARM64 (for running on Apple
Silicon machines), and x86_64 (for running on older Intel-based machines).
To support multiple CPU architectures on a single platform, Apple uses a "fat
binary" format - a single physical file that contains support for multiple
architectures. It is possible to compile and use a "thin" single architecture
version of a binary for testing purposes; however, the "thin" binary will not be
portable to machines using other architectures.
Building a single-architecture framework
----------------------------------------
The Python build system will create a ``Python.framework`` that supports a
*single* ABI with a *single* architecture. Unlike macOS, iOS does not allow a
framework to contain non-library content, so the iOS build will produce a
``bin`` and ``lib`` folder in the same output folder as ``Python.framework``.
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
also requires the use of cross-compilation. The minimal commands for building
Python for the ARM64 iOS simulator will look something like::
$ export PATH="`pwd`/iOS/Resources/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin"
$ ./configure \
AR=arm64-apple-ios-simulator-ar \
CC=arm64-apple-ios-simulator-clang \
CPP=arm64-apple-ios-simulator-cpp \
CXX=arm64-apple-ios-simulator-clang \
--enable-framework=/path/to/install \
--host=arm64-apple-ios-simulator \
--build=arm64-apple-darwin \
--with-build-python=/path/to/python.exe
$ make
$ make install
In this invocation:
* ``iOS/Resources/bin`` has been added to the path, providing some shims for the
compilers and linkers needed by the build. Xcode requires the use of ``xcrun``
to invoke compiler tooling. However, if ``xcrun`` is pre-evaluated and the
result passed to ``configure``, these results can embed user- and
version-specific paths into the sysconfig data, which limits the portability
of the compiled Python. Alternatively, if ``xcrun`` is used *as* the compiler,
it requires that compiler variables like ``CC`` include spaces, which can
cause significant problems with many C configuration systems which assume that
``CC`` will be a single executable.
To work around this problem, the ``iOS/Resources/bin`` folder contains some
wrapper scripts that present as simple compilers and linkers, but wrap
underlying calls to ``xcrun``. This allows configure to use a ``CC``
definition without spaces, and without user- or version-specific paths, while
retaining the ability to adapt to the local Xcode install. These scripts are
included in the ``bin`` directory of an iOS install.
These scripts will, by default, use the currently active Xcode installation.
If you want to use a different Xcode installation, you can use
``xcode-select`` to set a new default Xcode globally, or you can use the
``DEVELOPER_DIR`` environment variable to specify an Xcode install. The
scripts will use the default ``iphoneos``/``iphonesimulator`` SDK version for
the select Xcode install; if you want to use a different SDK, you can set the
``IOS_SDK_VERSION`` environment variable. (e.g, setting
``IOS_SDK_VERSION=17.1`` would cause the scripts to use the ``iphoneos17.1``
and ``iphonesimulator17.1`` SDKs, regardless of the Xcode default.)
The path has also been cleared of any user customizations. A common source of
bugs is for tools like Homebrew to accidentally leak macOS binaries into an iOS
build. Resetting the path to a known "bare bones" value is the easiest way to
avoid these problems.
* ``/path/to/install`` is the location where the final ``Python.framework`` will
be output.
* ``--host`` is the architecture and ABI that you want to build, in GNU compiler
triple format. This will be one of:
- ``arm64-apple-ios`` for ARM64 iOS devices.
- ``arm64-apple-ios-simulator`` for the iOS simulator running on Apple
Silicon devices.
- ``x86_64-apple-ios-simulator`` for the iOS simulator running on Intel
devices.
* ``--build`` is the GNU compiler triple for the machine that will be running
the compiler. This is one of:
- ``arm64-apple-darwin`` for Apple Silicon devices.
- ``x86_64-apple-darwin`` for Intel devices.
* ``/path/to/python.exe`` is the path to a Python binary on the machine that
will be running the compiler. This is needed because the Python compilation
process involves running some Python code. On a normal desktop build of
Python, you can compile a python interpreter and then use that interpreter to
run Python code. However, the binaries produced for iOS won't run on macOS, so
you need to provide an external Python interpreter. This interpreter must be
the same version as the Python that is being compiled. To be completely safe,
this should be the *exact* same commit hash. However, the longer a Python
release has been stable, the more likely it is that this constraint can be
relaxed - the same micro version will often be sufficient.
For a full CPython build, you also need to specify the paths to iOS builds of
the binary libraries that CPython depends on (XZ, BZip2, LibFFI and OpenSSL).
This can be done by defining the ``LIBLZMA_CFLAGS``, ``LIBLZMA_LIBS``,
``BZIP2_CFLAGS``, ``BZIP2_LIBS``, ``LIBFFI_CFLAGS``, and ``LIBFFI_LIBS``
environment variables, and the ``--with-openssl`` configure option. Versions of
these libraries pre-compiled for iOS can be found in `this repository
<https://github.com/beeware/cpython-apple-source-deps/releases>`__.
By default, Python will be compiled with an iOS deployment target (i.e., the
minimum supported iOS version) of 12.0. To specify a different deployment
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.
Merge thin frameworks into fat frameworks
-----------------------------------------
Once you've built a ``Python.framework`` for each ABI and and architecture, you
must produce a "fat" framework for each ABI that contains all the architectures
for that ABI.
The ``iphoneos`` build only needs to support a single architecture, so it can be
used without modification.
If you only want to support a single simulator architecture, (e.g., only support
ARM64 simulators), you can use a single architecture ``Python.framework`` build.
However, if you want to create ``Python.xcframework`` that supports *all*
architectures, you'll need to merge the ``iphonesimulator`` builds for ARM64 and
x86_64 into a single "fat" framework.
The "fat" framework can be constructed by performing a directory merge of the
content of the two "thin" ``Python.framework`` directories, plus the ``bin`` and
``lib`` folders for each thin framework. When performing this merge:
* The pure Python standard library content is identical for each architecture,
except for a handful of platform-specific files (such as the ``sysconfig``
module). Ensure that the "fat" framework has the union of all standard library
files.
* Any binary files in the standard library, plus the main
``libPython3.X.dylib``, can be merged using the ``lipo`` tool, provide by
Xcode::
$ lipo -create -output module.dylib path/to/x86_64/module.dylib path/to/arm64/module.dylib
* The header files will be indentical on both architectures, except for
``pyconfig.h``. Copy all the headers from one platform (say, arm64), rename
``pyconfig.h`` to ``pyconfig-arm64.h``, and copy the ``pyconfig.h`` for the
other architecture into the merged header folder as ``pyconfig-x86_64.h``.
Then copy the ``iOS/Resources/pyconfig.h`` file from the CPython sources into
the merged headers folder. This will allow the two Python architectures to
share a common ``pyconfig.h`` header file.
At this point, you should have 2 Python.framework folders - one for ``iphoneos``,
and one for ``iphonesimulator`` that is a merge of x86+64 and ARM64 content.
Merge frameworks into an XCframework
------------------------------------
Now that we have 2 (potentially fat) ABI-specific frameworks, we can merge those
frameworks into a single ``XCframework``.
The initial skeleton of an ``XCframework`` is built using::
xcodebuild -create-xcframework -output Python.xcframework -framework path/to/iphoneos/Python.framework -framework path/to/iphonesimulator/Python.framework
Then, copy the ``bin`` and ``lib`` folders into the architecture-specific slices of
the XCframework::
cp path/to/iphoneos/bin Python.xcframework/ios-arm64
cp path/to/iphoneos/lib Python.xcframework/ios-arm64
cp path/to/iphonesimulator/bin Python.xcframework/ios-arm64_x86-64-simulator
cp path/to/iphonesimulator/lib Python.xcframework/ios-arm64_x86-64-simulator
Note that the name of the architecture-specific slice for the simulator will
depend on the CPU architecture that you build.
Then, add symbolic links to "common" platform names for each slice::
ln -si ios-arm64 Python.xcframework/iphoneos
ln -si ios-arm64_x86-64-simulator Python.xcframework/iphonesimulator
You now have a Python.xcframework that can be used in a project.
Testing Python on iOS
=====================
The ``iOS/testbed`` folder that contains an Xcode project that is able to run
the iOS test suite. This project converts the Python test suite into a single
test case in Xcode's XCTest framework. The single XCTest passes if the test
suite passes.
To run the test suite, configure a Python build for an iOS simulator (i.e.,
``--host=arm64-apple-ios-simulator`` or ``--host=x86_64-apple-ios-simulator``
), setting the framework location to the testbed project::
--enable-framework="./iOS/testbed/Python.xcframework/ios-arm64_x86_64-simulator"
Then run ``make all install testiOS``. This will build an iOS framework for your
chosen architecture, install the Python iOS framework into the testbed project,
and run the test suite on an "iPhone SE (3rd generation)" simulator.
While the test suite is running, Xcode does not display any console output.
After showing some Xcode build commands, the console output will print ``Testing
started``, and then appear to stop. It will remain in this state until the test
suite completes. On a 2022 M1 MacBook Pro, the test suite takes approximately 12
minutes to run; a couple of extra minutes is required to boot and prepare the
iOS simulator.
On success, the test suite will exit and report successful completion of the
test suite. No output of the Python test suite will be displayed.
On failure, the output of the Python test suite *will* be displayed. This will
show the details of the tests that failed.
Debugging test failures
-----------------------
The easiest way to diagnose a single test failure is to open the testbed project
in Xcode and run the tests from there using the "Product > Test" menu item.
Running specific tests
^^^^^^^^^^^^^^^^^^^^^^
As the test suite is being executed on an iOS simulator, it is not possible to
pass in command line arguments to configure test suite operation. To work around
this limitation, the arguments that would normally be passed as command line
arguments are configured as a static string at the start of the XCTest method
``- (void)testPython`` in ``iOSTestbedTests.m``. To pass an argument to the test
suite, add a a string to the ``argv`` defintion. These arguments will be passed
to the test suite as if they had been passed to ``python -m test`` at the
command line.
Disabling automated breakpoints
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
By default, Xcode will inserts an automatic breakpoint whenever a signal is
raised. The Python test suite raises many of these signals as part of normal
operation; unless you are trying to diagnose an issue with signals, the
automatic breakpoints can be inconvenient. However, they can be disabled by
creating a symbolic breakpoint that is triggered at the start of the test run.
Select "Debug > Breakpoints > Create Symbolic Breakpoint" from the Xcode menu, and
populate the new brewpoint with the following details:
* **Name**: IgnoreSignals
* **Symbol**: UIApplicationMain
* **Action**: Add debugger commands for:
- ``process handle SIGINT -n true -p true -s false``
- ``process handle SIGUSR1 -n true -p true -s false``
- ``process handle SIGUSR2 -n true -p true -s false``
- ``process handle SIGXFSZ -n true -p true -s false``
* Check the "Automatically continue after evaluating" box.
All other details can be left blank. When the process executes the
``UIApplicationMain`` entry point, the breakpoint will trigger, run the debugger
commands to disable the automatic breakpoints, and automatically resume.

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>Python</string>
<key>CFBundleGetInfoString</key>
<string>Python Runtime and Library</string>
<key>CFBundleIdentifier</key>
<string>@PYTHONFRAMEWORKIDENTIFIER@</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Python</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>%VERSION%</string>
<key>CFBundleLongVersionString</key>
<string>%VERSION%, (c) 2001-2024 Python Software Foundation.</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>MinimumOSVersion</key>
<string>@IOS_DEPLOYMENT_TARGET@</string>
</dict>
</plist>

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphoneos${IOS_SDK_VERSION} ar $@

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphoneos${IOS_SDK_VERSION} clang -target arm64-apple-ios $@

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphoneos${IOS_SDK_VERSION} clang -target arm64-apple-ios -E $@

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphonesimulator${IOS_SDK_VERSION} ar $@

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target arm64-apple-ios-simulator $@

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target arm64-apple-ios-simulator -E $@

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphonesimulator${IOS_SDK_VERSION} ar $@

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target x86_64-apple-ios-simulator $@

View File

@ -0,0 +1,2 @@
#!/bin/sh
xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target x86_64-apple-ios-simulator -E $@

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string></string>
<key>CFBundleIdentifier</key>
<string></string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>MinimumOSVersion</key>
<string>12.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

7
iOS/Resources/pyconfig.h Normal file
View File

@ -0,0 +1,7 @@
#ifdef __arm64__
#include "pyconfig-arm64.h"
#endif
#ifdef __x86_64__
#include "pyconfig-x86_64.h"
#endif