From dfd97f85dcb8d09d466137dceceec99c7668057b Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 13 Feb 2024 14:38:35 +0800 Subject: [PATCH 01/13] Add configure and Makefile targets to support iOS compilation. --- .gitignore | 1 + Makefile.pre.in | 56 ++- ...-02-13-14-52-59.gh-issue-114099.zjXsQr.rst | 2 + Misc/platform_triplet.c | 15 + config.sub | 5 +- configure | 228 ++++++++-- configure.ac | 213 ++++++++-- iOS/README.rst | 392 ++++++++++++++++++ iOS/Resources/Info.plist.in | 34 ++ iOS/Resources/bin/arm64-apple-ios-ar | 2 + iOS/Resources/bin/arm64-apple-ios-clang | 2 + iOS/Resources/bin/arm64-apple-ios-cpp | 2 + .../bin/arm64-apple-ios-simulator-ar | 2 + .../bin/arm64-apple-ios-simulator-clang | 2 + .../bin/arm64-apple-ios-simulator-cpp | 2 + .../bin/x86_64-apple-ios-simulator-ar | 2 + .../bin/x86_64-apple-ios-simulator-clang | 2 + .../bin/x86_64-apple-ios-simulator-cpp | 2 + iOS/Resources/dylib-Info-template.plist | 26 ++ iOS/Resources/pyconfig.h | 7 + 20 files changed, 906 insertions(+), 91 deletions(-) create mode 100644 Misc/NEWS.d/next/Build/2024-02-13-14-52-59.gh-issue-114099.zjXsQr.rst create mode 100644 iOS/README.rst create mode 100644 iOS/Resources/Info.plist.in create mode 100755 iOS/Resources/bin/arm64-apple-ios-ar create mode 100755 iOS/Resources/bin/arm64-apple-ios-clang create mode 100755 iOS/Resources/bin/arm64-apple-ios-cpp create mode 100755 iOS/Resources/bin/arm64-apple-ios-simulator-ar create mode 100755 iOS/Resources/bin/arm64-apple-ios-simulator-clang create mode 100755 iOS/Resources/bin/arm64-apple-ios-simulator-cpp create mode 100755 iOS/Resources/bin/x86_64-apple-ios-simulator-ar create mode 100755 iOS/Resources/bin/x86_64-apple-ios-simulator-clang create mode 100755 iOS/Resources/bin/x86_64-apple-ios-simulator-cpp create mode 100644 iOS/Resources/dylib-Info-template.plist create mode 100644 iOS/Resources/pyconfig.h diff --git a/.gitignore b/.gitignore index 6ed7197e3ab626..2194b393aa4821 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Makefile.pre.in b/Makefile.pre.in index e0527633ccd03b..6bee2ab9b65630 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -911,6 +911,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) @@ -2583,10 +2598,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; \ @@ -2607,6 +2623,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 $(PYTHONFRAMEWORKPREFIX)/include; then \ + echo "Clearing stale header symlink directory"; \ + rm -rf $(PYTHONFRAMEWORKPREFIX)/include; \ + fi + $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKINSTALLDIR) + sed 's/%VERSION%/'"`$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(PYTHONFRAMEWORKINSTALLDIR)/Info.plist + $(INSTALL_SHARED) $(LDLIBRARY) $(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY) + $(INSTALL) -d -m $(DIRMODE) $(BINDIR) + for file in $(RESSRCDIR)/bin/* ; do \ + $(INSTALL) -m $(EXEMODE) $$file $(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. @@ -2647,6 +2684,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 $(PYTHONFRAMEWORKINSTALLDIR)/Headers; then \ + echo "Removing old framework headers"; \ + rm -rf $(PYTHONFRAMEWORKINSTALLDIR)/Headers; \ + fi + mv "$(PYTHONFRAMEWORKPREFIX)/include/python$(VERSION)" "$(PYTHONFRAMEWORKINSTALLDIR)/Headers" + $(LN) -fs "$(PYTHONFRAMEWORKDIR)" "$(PYTHONFRAMEWORKPREFIX)/include/python$(VERSION)" + # Build the toplevel Makefile Makefile.pre: $(srcdir)/Makefile.pre.in config.status CONFIG_FILES=Makefile.pre CONFIG_HEADERS= ./config.status diff --git a/Misc/NEWS.d/next/Build/2024-02-13-14-52-59.gh-issue-114099.zjXsQr.rst b/Misc/NEWS.d/next/Build/2024-02-13-14-52-59.gh-issue-114099.zjXsQr.rst new file mode 100644 index 00000000000000..e2858bd71d28cb --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-02-13-14-52-59.gh-issue-114099.zjXsQr.rst @@ -0,0 +1,2 @@ +Makefile targets were added to support compiling an iOS-compatible framework +build. diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c index 3307260544e8a6..0b912e332510a6 100644 --- a/Misc/platform_triplet.c +++ b/Misc/platform_triplet.c @@ -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__) diff --git a/config.sub b/config.sub index 2c6a07ab3c34ea..1bb6a05dc11026 100755 --- a/config.sub +++ b/config.sub @@ -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 diff --git a/configure b/configure index ba2d49df7c65fe..ab9d1a3f59ed44 100755 --- a/configure +++ b/configure @@ -969,6 +969,7 @@ LDFLAGS CFLAGS CC HAS_XCRUN +IOS_DEPLOYMENT_TARGET EXPORT_MACOSX_DEPLOYMENT_TARGET CONFIGURE_MACOSX_DEPLOYMENT_TARGET _PYTHON_HOST_PLATFORM @@ -4028,6 +4029,9 @@ then *-*-cygwin*) ac_sys_system=Cygwin ;; + *-apple-ios*) + ac_sys_system=iOS + ;; *-*-vxworks*) ac_sys_system=VxWorks ;; @@ -4220,11 +4224,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" @@ -4286,6 +4290,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 @@ -4352,6 +4371,28 @@ if test "$cross_compiling" = yes; then *-*-cygwin*) _host_ident= ;; + *-apple-ios*-simulator) + _host_os=`echo $host | cut -d '-' -f3` + IOS_DEPLOYMENT_TARGET=${_host_os:3} + case "$host_cpu" in + aarch64) + _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-arm64 + ;; + *) + _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-$host_cpu + esac + ;; + *-apple-ios*) + _host_os=`echo $host | cut -d '-' -f3` + IOS_DEPLOYMENT_TARGET=${_host_os:3} + case "$host_cpu" in + aarch64) + _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-arm64 + ;; + *) + _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-$host_cpu + esac + ;; *-*-vxworks*) _host_ident=$host_cpu ;; @@ -4430,6 +4471,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) @@ -4524,6 +4568,18 @@ case $host in #( ;; esac +case $ac_sys_system in #( + iOS) : + + IOS_DEPLOYMENT_TARGET=${IOS_DEPLOYMENT_TARGET:=12.0} + 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. @@ -6786,6 +6842,8 @@ printf %s "checking for multiarch... " >&6; } case $ac_sys_system in #( Darwin*) : MULTIARCH="" ;; #( + iOS) : + MULTIARCH="" ;; #( FreeBSD*) : MULTIARCH="" ;; #( *) : @@ -6806,6 +6864,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 ;; @@ -6851,6 +6911,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 ;; @@ -7306,12 +7370,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 @@ -7369,6 +7436,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}} @@ -12619,6 +12689,7 @@ if test -z "$SHLIB_SUFFIX"; then esac ;; CYGWIN*) SHLIB_SUFFIX=.dll;; + iOS) SHLIB_SUFFIX=.dylib;; *) SHLIB_SUFFIX=.so;; esac fi @@ -12701,6 +12772,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';; @@ -12836,14 +12912,14 @@ then # Issue #18075: the default maximum stack size (8MBytes) is too # small for the default recursion limit. Increase the stack size # to ensure that tests don't crash - stack_size="1000000" # 16 MB - if test "$with_ubsan" = "yes" - then - # Undefined behavior sanitizer requires an even deeper stack - stack_size="4000000" # 64 MB - fi + stack_size="1000000" # 16 MB + if test "$with_ubsan" = "yes" + then + # Undefined behavior sanitizer requires an even deeper stack + stack_size="4000000" # 64 MB + fi - LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED" + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED" printf "%s\n" "#define THREAD_STACK_SIZE 0x$stack_size" >>confdefs.h @@ -12854,6 +12930,24 @@ printf "%s\n" "#define THREAD_STACK_SIZE 0x$stack_size" >>confdefs.h LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' fi LINKFORSHARED="$LINKFORSHARED";; + iOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" + + # Issue #18075: the default maximum stack size (8MBytes) is too + # small for the default recursion limit. Increase the stack size + # to ensure that tests don't crash + stack_size="1000000" # 16 MB + if test "$with_ubsan" = "yes" + then + # Undefined behavior sanitizer requires an even deeper stack + stack_size="4000000" # 64 MB + fi + + +printf "%s\n" "#define THREAD_STACK_SIZE 0x$stack_size" >>confdefs.h + + + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";; SCO_SV*) LINKFORSHARED="-Wl,-Bexport";; ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";; @@ -14242,6 +14336,10 @@ then : ctypes_malloc_closure=yes ;; #( + iOS) : + + ctypes_malloc_closure=yes + ;; #( sunos5) : as_fn_append LIBFFI_LIBS " -mimpure-text" ;; #( @@ -17493,12 +17591,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 @@ -17541,12 +17633,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 @@ -18273,12 +18359,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 @@ -18457,6 +18537,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} @@ -21752,6 +21858,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 : @@ -21762,7 +21872,7 @@ then : else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for clock_settime in -lrt" >&5 printf %s "checking for clock_settime in -lrt... " >&6; } if test ${ac_cv_lib_rt_clock_settime+y} then : @@ -21800,7 +21910,7 @@ printf "%s\n" "$ac_cv_lib_rt_clock_settime" >&6; } if test "x$ac_cv_lib_rt_clock_settime" = xyes then : - printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h + printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h fi @@ -21809,6 +21919,7 @@ fi fi done +fi for ac_func in clock_nanosleep @@ -26693,24 +26804,25 @@ 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_cv_file__dev_ptmx+set}" != set; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptmx" >&5 +if test "$ac_sys_system" != "iOS" ; then + 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; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5 printf "%s\n" "not set" >&6; } - as_fn_error $? "set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5 - fi - if test "${ac_cv_file__dev_ptc+set}" != set; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5 + as_fn_error $? "set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling" "$LINENO" 5 + fi + if test "${ac_cv_file__dev_ptc+set}" != set; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for /dev/ptc" >&5 printf %s "checking for /dev/ptc... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not set" >&5 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 + 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 : @@ -26731,12 +26843,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 : @@ -26757,10 +26869,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 @@ -28143,6 +28256,28 @@ case $ac_sys_system in #( ;; #( 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__xxsubinterpreters=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*) : @@ -31754,6 +31889,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" ;; diff --git a/configure.ac b/configure.ac index b39af7422c4c7c..b317ab44a34297 100644 --- a/configure.ac +++ b/configure.ac @@ -327,6 +327,9 @@ then *-*-cygwin*) ac_sys_system=Cygwin ;; + *-apple-ios*) + ac_sys_system=iOS + ;; *-*-vxworks*) ac_sys_system=VxWorks ;; @@ -511,11 +514,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,6 +577,20 @@ 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]) ;; @@ -634,6 +651,28 @@ if test "$cross_compiling" = yes; then *-*-cygwin*) _host_ident= ;; + *-apple-ios*-simulator) + _host_os=`echo $host | cut -d '-' -f3` + IOS_DEPLOYMENT_TARGET=${_host_os:3} + case "$host_cpu" in + aarch64) + _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-arm64 + ;; + *) + _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-$host_cpu + esac + ;; + *-apple-ios*) + _host_os=`echo $host | cut -d '-' -f3` + IOS_DEPLOYMENT_TARGET=${_host_os:3} + case "$host_cpu" in + aarch64) + _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-arm64 + ;; + *) + _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-$host_cpu + esac + ;; *-*-vxworks*) _host_ident=$host_cpu ;; @@ -711,6 +750,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 +843,18 @@ AS_CASE([$host], ], ) +dnl iOS needs to enforce the deployment target; if the version hasn't +dnl been provided as part of the --host configuration, fall back to +dnl a default value (12.0 for iOS). +AS_CASE([$ac_sys_system], + [iOS], [ + IOS_DEPLOYMENT_TARGET=${IOS_DEPLOYMENT_TARGET:=12.0} + 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 +1021,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 +1043,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 +1075,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 +1395,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 @@ -1399,6 +1460,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}} @@ -3169,6 +3233,7 @@ if test -z "$SHLIB_SUFFIX"; then esac ;; CYGWIN*) SHLIB_SUFFIX=.dll;; + iOS) SHLIB_SUFFIX=.dylib;; *) SHLIB_SUFFIX=.so;; esac fi @@ -3249,6 +3314,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';; @@ -3375,24 +3445,42 @@ then # Issue #18075: the default maximum stack size (8MBytes) is too # small for the default recursion limit. Increase the stack size # to ensure that tests don't crash - stack_size="1000000" # 16 MB - if test "$with_ubsan" = "yes" - then - # Undefined behavior sanitizer requires an even deeper stack - stack_size="4000000" # 64 MB - fi + stack_size="1000000" # 16 MB + if test "$with_ubsan" = "yes" + then + # Undefined behavior sanitizer requires an even deeper stack + stack_size="4000000" # 64 MB + fi - LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED" + 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.]) + AC_DEFINE_UNQUOTED([THREAD_STACK_SIZE], + [0x$stack_size], + [Custom thread stack size depending on chosen sanitizer runtimes.]) if test "$enable_framework" then LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' fi LINKFORSHARED="$LINKFORSHARED";; + iOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" + + # Issue #18075: the default maximum stack size (8MBytes) is too + # small for the default recursion limit. Increase the stack size + # to ensure that tests don't crash + stack_size="1000000" # 16 MB + if test "$with_ubsan" = "yes" + then + # Undefined behavior sanitizer requires an even deeper stack + stack_size="4000000" # 64 MB + fi + + AC_DEFINE_UNQUOTED([THREAD_STACK_SIZE], + [0x$stack_size], + [Custom thread stack size depending on chosen sanitizer runtimes.]) + + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";; SCO_SV*) LINKFORSHARED="-Wl,-Bexport";; ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";; @@ -3766,6 +3854,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], [ @@ -4831,8 +4922,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 \ @@ -4849,7 +4940,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 \ ]) @@ -4861,6 +4952,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.])], @@ -5161,11 +5260,16 @@ AC_CHECK_FUNCS([clock_getres], [], [ ]) ]) -AC_CHECK_FUNCS([clock_settime], [], [ - AC_CHECK_LIB([rt], [clock_settime], [ - AC_DEFINE([HAVE_CLOCK_SETTIME], [1]) - ]) -]) +# 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], [ @@ -6524,28 +6628,32 @@ 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 - if test "${ac_cv_file__dev_ptmx+set}" != set; then - AC_MSG_CHECKING([for /dev/ptmx]) - AC_MSG_RESULT([not set]) - AC_MSG_ERROR([set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling]) - fi - if test "${ac_cv_file__dev_ptc+set}" != set; then - AC_MSG_CHECKING([for /dev/ptc]) - 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]) +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 + 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]) + AC_MSG_ERROR([set ac_cv_file__dev_ptmx to yes/no in your CONFIG_SITE file when cross compiling]) + fi + if test "${ac_cv_file__dev_ptc+set}" != set; then + AC_MSG_CHECKING([for /dev/ptc]) + 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_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 - AC_DEFINE([HAVE_DEV_PTC], [1], - [Define to 1 if you have the /dev/ptc device file.]) + 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 + 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 @@ -7188,6 +7296,29 @@ 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], + [_xxsubinterpreters], + [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])], diff --git a/iOS/README.rst b/iOS/README.rst new file mode 100644 index 00000000000000..4ed242891d305a --- /dev/null +++ b/iOS/README.rst @@ -0,0 +1,392 @@ +==================== +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 on iOS, tools such as `BeeWare's +Briefcase `__ and `Kivy's Builddozer +`__ 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. + +iOS specific arguments to configure +=================================== + +* ``--enable-framework[=DIR]`` + + This argument specifies the location where the Python.framework will + be installed. + +* ``--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=aarch64-apple-ios-simulator \ + --build=aarch64-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, ``xcrun`` embeds user- and + version-specific paths into the sysconfig data, which limits the portability + of the compiled Python. It also 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. The + ``iOS/Resources/bin`` folder contains some wrapper scripts that present as + simple compilers and linkers, but wrap underlying calls to ``xcrun``. + + 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: + + - ``aarch64-apple-ios`` for ARM64 iOS devices. + - ``aarch64-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: + + - ``aarch64-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 version as the Python that is being compiled. + +In practice, you will likely also need to specify the paths to iOS builds of the +binary libraries that CPython depends on (XZ, BZip2, LibFFI and OpenSSL). + +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. + +Using Python on iOS +=================== + +To add Python to an iOS Xcode project: + +1. Build a Python ``XCFramework`` using the instructions above. At a minimum, + you will need a build for `arm64-apple-ios`, plus one of either + `arm64-apple-ios-simulator` or `x86_64-apple-ios-simulator`. + +2. Drag the ``XCframework`` into your iOS project. In the following + instructions, we'll assume you've dropped the ``XCframework`` into the root + of your project; however, you can use any other location that you want. + +3. Drag the ``iOS/Resources/dylib-Info-template.plist`` file into your project, + and ensure it is associated with the app target. + +4. Select the app target by selecting the root node of your Xcode project, then + the target name in the sidebar that appears. + +5. In the "General" settings, under "Frameworks, Libraries and Embedded + Content", Add ``Python.xcframework``, with "Embed & Sign" selected. + +6. In the "Build Settings" tab, modify the following: + + - Build Options + * User script sandboxing: No + * Enable Testability: Yes + - Search Paths + * Framework Search Paths: ``$(PROJECT_DIR)`` + * Header Search Paths: ``"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers"`` + - Apple Clang - Warnings - All languages + * Quoted Include in Framework Header: No + +7. In the "Build Phases" tab, add a new "Run Script" build step *before* the + "Embed Frameworks" step. Name the step "Install Target Specific Python + Standard Library", disable the "Based on dependency analysis" checkbox, and + set the script content to:: + + set -e + + mkdir -p "$CODESIGNING_FOLDER_PATH/python/lib" + if [ "$EFFECTIVE_PLATFORM_NAME" = "-iphonesimulator" ]; then + echo "Installing Python modules for iOS Simulator" + rsync -au --delete "$PROJECT_DIR/Python.xcframework/iphonesimulator/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" + else + echo "Installing Python modules for iOS Device" + rsync -au --delete "$PROJECT_DIR/Python.xcframework/iphoneos/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" + fi + +8. Add a second "Run Script" build step *directly after* the step you just + added, named "Prepare Python Binary Modules". It should also have "Based on + dependency analysis" unchecked, with the following script content:: + + set -e + + install_dylib () { + INSTALL_BASE=$1 + FULL_DYLIB=$2 + + # The name of the .dylib file + DYLIB=$(basename "$FULL_DYLIB") + # The name of the .dylib file, relative to the install base + RELATIVE_DYLIB=${FULL_DYLIB#$CODESIGNING_FOLDER_PATH/$INSTALL_BASE/} + # The full dotted name of the binary module, constructed from the file path. + FULL_MODULE_NAME=$(echo $RELATIVE_DYLIB | cut -d "." -f 1 | tr "/" "."); + # A bundle identifier; not actually used, but required by Xcode framework packaging + FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr "_" "-") + # The name of the framework folder. + FRAMEWORK_FOLDER="Frameworks/$FULL_MODULE_NAME.framework" + + # If the framework folder doesn't exist, create it. + if [ ! -d "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" ]; then + echo "Creating framework for $RELATIVE_DYLIB" + mkdir -p "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" + + cp "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" + plutil -replace CFBundleExecutable -string "$DYLIB" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" + plutil -replace CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" + fi + + echo "Installing binary for $RELATIVE_DYLIB" + mv "$FULL_DYLIB" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" + } + + PYTHON_VER=$(ls "$CODESIGNING_FOLDER_PATH/python/lib") + echo "Install Python $PYTHON_VER standard library dylibs..." + find "$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload" -name "*.dylib" | while read FULL_DYLIB; do + install_dylib python/lib/$PYTHON_VER/lib-dynload "$FULL_DYLIB" + done + + # Clean up dylib template + rm -f "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" + + echo "Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)..." + find "$CODESIGNING_FOLDER_PATH/Frameworks" -name "*.framework" -exec /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der "{}" \; + +9. Add Objective C code to initialize and use a Python interpreter in embedded + mode. When configuring the interpreter, you can use: + + [NSString stringWithFormat:@"%@/python", [[NSBundle mainBundle] resourcePath], nil] + + as the value of ``PYTHONHOME``; the standard library will be installed as the + ``lib/python3.X`` subfolder of that ``PYTHONHOME``. + +If you have third-party binary modules in your app, they will need to be: + +* Compiled for both on-device and simulator platforms; +* Copied into your project as part of the script in step 9; +* Installed and signed as part of the script in step 10. + +Testing Python on iOS +===================== + +The ``Tools/iOSTestbed`` 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=aarch64-apple-ios-simulator`` or ``--host=x86_64-apple-ios-simulator`` +), setting the framework location to the testbed project:: + + --enable-framework="./Tools/iOSTestbed/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. + +Debuging 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. diff --git a/iOS/Resources/Info.plist.in b/iOS/Resources/Info.plist.in new file mode 100644 index 00000000000000..3ecdc894f0a285 --- /dev/null +++ b/iOS/Resources/Info.plist.in @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + Python + CFBundleGetInfoString + Python Runtime and Library + CFBundleIdentifier + @PYTHONFRAMEWORKIDENTIFIER@ + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Python + CFBundlePackageType + FMWK + CFBundleShortVersionString + %VERSION% + CFBundleLongVersionString + %VERSION%, (c) 2001-2024 Python Software Foundation. + CFBundleSignature + ???? + CFBundleVersion + 1 + CFBundleSupportedPlatforms + + iPhoneOS + + MinimumOSVersion + @IOS_DEPLOYMENT_TARGET@ + + diff --git a/iOS/Resources/bin/arm64-apple-ios-ar b/iOS/Resources/bin/arm64-apple-ios-ar new file mode 100755 index 00000000000000..add54095b14892 --- /dev/null +++ b/iOS/Resources/bin/arm64-apple-ios-ar @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphoneos ar $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-clang b/iOS/Resources/bin/arm64-apple-ios-clang new file mode 100755 index 00000000000000..e1a7b59f45d80a --- /dev/null +++ b/iOS/Resources/bin/arm64-apple-ios-clang @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphoneos clang -target arm64-apple-ios $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-cpp b/iOS/Resources/bin/arm64-apple-ios-cpp new file mode 100755 index 00000000000000..ff3ce4f363d4d6 --- /dev/null +++ b/iOS/Resources/bin/arm64-apple-ios-cpp @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphoneos clang -target arm64-apple-ios -E $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-simulator-ar b/iOS/Resources/bin/arm64-apple-ios-simulator-ar new file mode 100755 index 00000000000000..722ee1b996bb52 --- /dev/null +++ b/iOS/Resources/bin/arm64-apple-ios-simulator-ar @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphonesimulator ar $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-simulator-clang b/iOS/Resources/bin/arm64-apple-ios-simulator-clang new file mode 100755 index 00000000000000..3dfc651212b604 --- /dev/null +++ b/iOS/Resources/bin/arm64-apple-ios-simulator-clang @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphonesimulator clang -target arm64-apple-ios-simulator $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-simulator-cpp b/iOS/Resources/bin/arm64-apple-ios-simulator-cpp new file mode 100755 index 00000000000000..aa44f39a80166d --- /dev/null +++ b/iOS/Resources/bin/arm64-apple-ios-simulator-cpp @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphonesimulator clang -target arm64-apple-ios-simulator -E $@ diff --git a/iOS/Resources/bin/x86_64-apple-ios-simulator-ar b/iOS/Resources/bin/x86_64-apple-ios-simulator-ar new file mode 100755 index 00000000000000..722ee1b996bb52 --- /dev/null +++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-ar @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphonesimulator ar $@ diff --git a/iOS/Resources/bin/x86_64-apple-ios-simulator-clang b/iOS/Resources/bin/x86_64-apple-ios-simulator-clang new file mode 100755 index 00000000000000..567bf6b6f21d2c --- /dev/null +++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-clang @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphonesimulator clang -target x86_64-apple-ios-simulator $@ diff --git a/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp b/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp new file mode 100755 index 00000000000000..046cccfd0190af --- /dev/null +++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk iphonesimulator clang -target x86_64-apple-ios-simulator -E $@ diff --git a/iOS/Resources/dylib-Info-template.plist b/iOS/Resources/dylib-Info-template.plist new file mode 100644 index 00000000000000..f652e272f71c88 --- /dev/null +++ b/iOS/Resources/dylib-Info-template.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + + CFBundleIdentifier + + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSupportedPlatforms + + iPhoneOS + + MinimumOSVersion + 12.0 + CFBundleVersion + 1 + + diff --git a/iOS/Resources/pyconfig.h b/iOS/Resources/pyconfig.h new file mode 100644 index 00000000000000..4acff2c6051637 --- /dev/null +++ b/iOS/Resources/pyconfig.h @@ -0,0 +1,7 @@ +#ifdef __arm64__ +#include "pyconfig-arm64.h" +#endif + +#ifdef __x86_64__ +#include "pyconfig-x86_64.h" +#endif From 838713dcac89f24d88d54a2f0c668c8e13fdb076 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 14 Feb 2024 10:12:13 +0800 Subject: [PATCH 02/13] Improve error handling and reuse in configure.ac. --- configure | 82 +++++++++++++++++++++++-------------------------- configure.ac | 87 ++++++++++++++++++++++++---------------------------- 2 files changed, 78 insertions(+), 91 deletions(-) diff --git a/configure b/configure index ab9d1a3f59ed44..824efe3e750c33 100755 --- a/configure +++ b/configure @@ -4197,10 +4197,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=" "$LINENO" 5 + fi + PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework PYTHONFRAMEWORKPREFIX= @@ -4314,6 +4322,10 @@ then : else $as_nop + if test "$ac_sys_system" = "iOS"; then + as_fn_error $? "iOS builds must use --enable-framework=" "$LINENO" 5 + fi + PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework PYTHONFRAMEWORKPREFIX= @@ -4371,26 +4383,21 @@ if test "$cross_compiling" = yes; then *-*-cygwin*) _host_ident= ;; - *-apple-ios*-simulator) - _host_os=`echo $host | cut -d '-' -f3` - IOS_DEPLOYMENT_TARGET=${_host_os:3} - case "$host_cpu" in - aarch64) - _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-arm64 - ;; - *) - _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-$host_cpu - esac - ;; *-apple-ios*) _host_os=`echo $host | cut -d '-' -f3` - IOS_DEPLOYMENT_TARGET=${_host_os:3} + _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}-iphoneos-arm64 - ;; - *) - _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-$host_cpu + aarch64) + _host_ident=${IOS_DEPLOYMENT_TARGET}-arm64-iphone${_host_device} + ;; + *) + _host_ident=${IOS_DEPLOYMENT_TARGET}-$host_cpu-iphone${_host_device} + ;; esac ;; *-*-vxworks*) @@ -4571,7 +4578,6 @@ esac case $ac_sys_system in #( iOS) : - IOS_DEPLOYMENT_TARGET=${IOS_DEPLOYMENT_TARGET:=12.0} as_fn_append CFLAGS " -mios-version-min=${IOS_DEPLOYMENT_TARGET}" as_fn_append LDFLAGS " -mios-version-min=${IOS_DEPLOYMENT_TARGET}" @@ -12906,7 +12912,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 @@ -12919,35 +12925,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 - LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' - fi - LINKFORSHARED="$LINKFORSHARED";; - iOS/*) - LINKFORSHARED="$extra_undefs -framework CoreFoundation" + if test $ac_sys_system = "Darwin"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED" - # Issue #18075: the default maximum stack size (8MBytes) is too - # small for the default recursion limit. Increase the stack size - # to ensure that tests don't crash - stack_size="1000000" # 16 MB - if test "$with_ubsan" = "yes" - then - # Undefined behavior sanitizer requires an even deeper stack - stack_size="4000000" # 64 MB + if test "$enable_framework"; then + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED" + elif test $ac_sys_system = "iOS"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' fi - - -printf "%s\n" "#define THREAD_STACK_SIZE 0x$stack_size" >>confdefs.h - - - LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; + ;; OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";; SCO_SV*) LINKFORSHARED="-Wl,-Bexport";; ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";; @@ -26804,7 +26796,10 @@ 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 "$ac_sys_system" != "iOS" ; 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 @@ -28268,7 +28263,6 @@ case $ac_sys_system in #( py_cv_module__posixsubprocess=n/a py_cv_module__scproxy=n/a py_cv_module__tkinter=n/a - py_cv_module__xxsubinterpreters=n/a py_cv_module_grp=n/a py_cv_module_nis=n/a py_cv_module_readline=n/a diff --git a/configure.ac b/configure.ac index b317ab44a34297..60af6f61a49551 100644 --- a/configure.ac +++ b/configure.ac @@ -487,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=]) + fi + PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework PYTHONFRAMEWORKPREFIX= @@ -597,6 +605,10 @@ AC_ARG_ENABLE([framework], esac esac ],[ + if test "$ac_sys_system" = "iOS"; then + AC_MSG_ERROR([iOS builds must use --enable-framework=]) + fi + PYTHONFRAMEWORK= PYTHONFRAMEWORKDIR=no-framework PYTHONFRAMEWORKPREFIX= @@ -651,26 +663,22 @@ if test "$cross_compiling" = yes; then *-*-cygwin*) _host_ident= ;; - *-apple-ios*-simulator) - _host_os=`echo $host | cut -d '-' -f3` - IOS_DEPLOYMENT_TARGET=${_host_os:3} - case "$host_cpu" in - aarch64) - _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-arm64 - ;; - *) - _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-$host_cpu - esac - ;; *-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}-iphoneos-arm64 - ;; - *) - _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-$host_cpu + aarch64) + _host_ident=${IOS_DEPLOYMENT_TARGET}-arm64-iphone${_host_device} + ;; + *) + _host_ident=${IOS_DEPLOYMENT_TARGET}-$host_cpu-iphone${_host_device} + ;; esac ;; *-*-vxworks*) @@ -843,12 +851,9 @@ AS_CASE([$host], ], ) -dnl iOS needs to enforce the deployment target; if the version hasn't -dnl been provided as part of the --host configuration, fall back to -dnl a default value (12.0 for iOS). +dnl Add the compiler flag for the iOS minimum supported OS version. AS_CASE([$ac_sys_system], [iOS], [ - IOS_DEPLOYMENT_TARGET=${IOS_DEPLOYMENT_TARGET:=12.0} 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]) @@ -3439,7 +3444,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 @@ -3452,35 +3457,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 - LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' - fi - LINKFORSHARED="$LINKFORSHARED";; - iOS/*) - LINKFORSHARED="$extra_undefs -framework CoreFoundation" + if test $ac_sys_system = "Darwin"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED" - # Issue #18075: the default maximum stack size (8MBytes) is too - # small for the default recursion limit. Increase the stack size - # to ensure that tests don't crash - stack_size="1000000" # 16 MB - if test "$with_ubsan" = "yes" - then - # Undefined behavior sanitizer requires an even deeper stack - stack_size="4000000" # 64 MB + if test "$enable_framework"; then + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED" + elif test $ac_sys_system = "iOS"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' fi - - AC_DEFINE_UNQUOTED([THREAD_STACK_SIZE], - [0x$stack_size], - [Custom thread stack size depending on chosen sanitizer runtimes.]) - - LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; + ;; OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";; SCO_SV*) LINKFORSHARED="-Wl,-Bexport";; ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";; @@ -6629,8 +6620,11 @@ AC_MSG_NOTICE([checking for device files]) dnl NOTE: Inform user how to proceed with files when cross compiling. 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 +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]) @@ -7310,7 +7304,6 @@ AS_CASE([$ac_sys_system], [_posixsubprocess], [_scproxy], [_tkinter], - [_xxsubinterpreters], [grp], [nis], [readline], From 5b54336b583e3044388a93d6d273699ea0ad28fa Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 14 Feb 2024 10:12:54 +0800 Subject: [PATCH 03/13] Clarifications to iOS README from review. --- iOS/README.rst | 140 ++++++++----------------------------------------- 1 file changed, 21 insertions(+), 119 deletions(-) diff --git a/iOS/README.rst b/iOS/README.rst index 4ed242891d305a..ae4a670f14a6b6 100644 --- a/iOS/README.rst +++ b/iOS/README.rst @@ -26,10 +26,11 @@ as Apple does not maintain Xcode for older macOS versions. iOS specific arguments to configure =================================== -* ``--enable-framework[=DIR]`` +* ``--enable-framework=DIR`` - This argument specifies the location where the Python.framework will - be installed. + 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`` @@ -131,10 +132,21 @@ In this invocation: 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 version as the Python that is being compiled. - -In practice, you will likely also need to specify the paths to iOS builds of the -binary libraries that CPython depends on (XZ, BZip2, LibFFI and OpenSSL). + the *exact* same version as the Python that is being compiled. + +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 ----------------------------------------- @@ -207,116 +219,6 @@ Then, add symbolic links to "common" platform names for each slice:: You now have a Python.xcframework that can be used in a project. -Using Python on iOS -=================== - -To add Python to an iOS Xcode project: - -1. Build a Python ``XCFramework`` using the instructions above. At a minimum, - you will need a build for `arm64-apple-ios`, plus one of either - `arm64-apple-ios-simulator` or `x86_64-apple-ios-simulator`. - -2. Drag the ``XCframework`` into your iOS project. In the following - instructions, we'll assume you've dropped the ``XCframework`` into the root - of your project; however, you can use any other location that you want. - -3. Drag the ``iOS/Resources/dylib-Info-template.plist`` file into your project, - and ensure it is associated with the app target. - -4. Select the app target by selecting the root node of your Xcode project, then - the target name in the sidebar that appears. - -5. In the "General" settings, under "Frameworks, Libraries and Embedded - Content", Add ``Python.xcframework``, with "Embed & Sign" selected. - -6. In the "Build Settings" tab, modify the following: - - - Build Options - * User script sandboxing: No - * Enable Testability: Yes - - Search Paths - * Framework Search Paths: ``$(PROJECT_DIR)`` - * Header Search Paths: ``"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers"`` - - Apple Clang - Warnings - All languages - * Quoted Include in Framework Header: No - -7. In the "Build Phases" tab, add a new "Run Script" build step *before* the - "Embed Frameworks" step. Name the step "Install Target Specific Python - Standard Library", disable the "Based on dependency analysis" checkbox, and - set the script content to:: - - set -e - - mkdir -p "$CODESIGNING_FOLDER_PATH/python/lib" - if [ "$EFFECTIVE_PLATFORM_NAME" = "-iphonesimulator" ]; then - echo "Installing Python modules for iOS Simulator" - rsync -au --delete "$PROJECT_DIR/Python.xcframework/iphonesimulator/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" - else - echo "Installing Python modules for iOS Device" - rsync -au --delete "$PROJECT_DIR/Python.xcframework/iphoneos/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" - fi - -8. Add a second "Run Script" build step *directly after* the step you just - added, named "Prepare Python Binary Modules". It should also have "Based on - dependency analysis" unchecked, with the following script content:: - - set -e - - install_dylib () { - INSTALL_BASE=$1 - FULL_DYLIB=$2 - - # The name of the .dylib file - DYLIB=$(basename "$FULL_DYLIB") - # The name of the .dylib file, relative to the install base - RELATIVE_DYLIB=${FULL_DYLIB#$CODESIGNING_FOLDER_PATH/$INSTALL_BASE/} - # The full dotted name of the binary module, constructed from the file path. - FULL_MODULE_NAME=$(echo $RELATIVE_DYLIB | cut -d "." -f 1 | tr "/" "."); - # A bundle identifier; not actually used, but required by Xcode framework packaging - FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr "_" "-") - # The name of the framework folder. - FRAMEWORK_FOLDER="Frameworks/$FULL_MODULE_NAME.framework" - - # If the framework folder doesn't exist, create it. - if [ ! -d "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" ]; then - echo "Creating framework for $RELATIVE_DYLIB" - mkdir -p "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" - - cp "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" - plutil -replace CFBundleExecutable -string "$DYLIB" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" - plutil -replace CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" - fi - - echo "Installing binary for $RELATIVE_DYLIB" - mv "$FULL_DYLIB" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" - } - - PYTHON_VER=$(ls "$CODESIGNING_FOLDER_PATH/python/lib") - echo "Install Python $PYTHON_VER standard library dylibs..." - find "$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload" -name "*.dylib" | while read FULL_DYLIB; do - install_dylib python/lib/$PYTHON_VER/lib-dynload "$FULL_DYLIB" - done - - # Clean up dylib template - rm -f "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" - - echo "Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)..." - find "$CODESIGNING_FOLDER_PATH/Frameworks" -name "*.framework" -exec /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" ${OTHER_CODE_SIGN_FLAGS:-} -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der "{}" \; - -9. Add Objective C code to initialize and use a Python interpreter in embedded - mode. When configuring the interpreter, you can use: - - [NSString stringWithFormat:@"%@/python", [[NSBundle mainBundle] resourcePath], nil] - - as the value of ``PYTHONHOME``; the standard library will be installed as the - ``lib/python3.X`` subfolder of that ``PYTHONHOME``. - -If you have third-party binary modules in your app, they will need to be: - -* Compiled for both on-device and simulator platforms; -* Copied into your project as part of the script in step 9; -* Installed and signed as part of the script in step 10. - Testing Python on iOS ===================== @@ -348,8 +250,8 @@ 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. -Debuging test failures ----------------------- +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. From 9a5f851eb1db3494b295406fbc9ea4c99f7b4b03 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 15 Feb 2024 06:26:28 +0800 Subject: [PATCH 04/13] Normalize usage of arm64 in iOS README. --- iOS/README.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iOS/README.rst b/iOS/README.rst index ae4a670f14a6b6..8dc3d2604f6bf3 100644 --- a/iOS/README.rst +++ b/iOS/README.rst @@ -85,8 +85,8 @@ Python for the ARM64 iOS simulator will look something like:: CPP=arm64-apple-ios-simulator-cpp \ CXX=arm64-apple-ios-simulator-clang \ --enable-framework=/path/to/install \ - --host=aarch64-apple-ios-simulator \ - --build=aarch64-apple-darwin \ + --host=arm64-apple-ios-simulator \ + --build=arm64-apple-darwin \ --with-build-python=/path/to/python.exe $ make $ make install @@ -114,8 +114,8 @@ In this invocation: * ``--host`` is the architecture and ABI that you want to build, in GNU compiler triple format. This will be one of: - - ``aarch64-apple-ios`` for ARM64 iOS devices. - - ``aarch64-apple-ios-simulator`` for the iOS simulator running on Apple + - ``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. @@ -123,7 +123,7 @@ In this invocation: * ``--build`` is the GNU compiler triple for the machine that will be running the compiler. This is one of: - - ``aarch64-apple-darwin`` for Apple Silicon devices. + - ``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 @@ -228,7 +228,7 @@ 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=aarch64-apple-ios-simulator`` or ``--host=x86_64-apple-ios-simulator`` +``--host=arm64-apple-ios-simulator`` or ``--host=x86_64-apple-ios-simulator`` ), setting the framework location to the testbed project:: --enable-framework="./Tools/iOSTestbed/Python.xcframework/ios-arm64_x86_64-simulator" From 8c763af9c03ada22084e8109d74814d1590dfc9c Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 16 Feb 2024 09:15:28 +0800 Subject: [PATCH 05/13] Move the future location of the iOS testbed project to the iOS folder. --- iOS/README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iOS/README.rst b/iOS/README.rst index 8dc3d2604f6bf3..fe14e96fd2833d 100644 --- a/iOS/README.rst +++ b/iOS/README.rst @@ -222,7 +222,7 @@ You now have a Python.xcframework that can be used in a project. Testing Python on iOS ===================== -The ``Tools/iOSTestbed`` folder that contains an Xcode project that is able to run +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. @@ -231,7 +231,7 @@ 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="./Tools/iOSTestbed/Python.xcframework/ios-arm64_x86_64-simulator" + --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, From 95275c1db77a27a800dcf9b0ab15d53a9ecec70d Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sat, 17 Feb 2024 09:26:14 +0800 Subject: [PATCH 06/13] Corrections to iOS README. --- iOS/README.rst | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/iOS/README.rst b/iOS/README.rst index fe14e96fd2833d..302863c6c25527 100644 --- a/iOS/README.rst +++ b/iOS/README.rst @@ -10,10 +10,10 @@ 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 on iOS, tools such as `BeeWare's -Briefcase `__ and `Kivy's Builddozer -`__ will provide a much more approachable user -experience. +experiment with writing an iOS app in Python, tools such as `BeeWare's Briefcase +`__ and `Kivy's Buildozer +`__ will provide a much more approachable +user experience. Compilers for building on iOS ============================= @@ -34,7 +34,7 @@ iOS specific arguments to configure * ``--with-framework-name=NAME`` - Specify the name for the python framework; defaults to ``Python``. + Specify the name for the Python framework; defaults to ``Python``. Building Python on iOS ====================== @@ -95,13 +95,20 @@ 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, ``xcrun`` embeds user- and + 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. It also 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. The - ``iOS/Resources/bin`` folder contains some wrapper scripts that present as - simple compilers and linkers, but wrap underlying calls to ``xcrun``. + 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. 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 @@ -139,8 +146,8 @@ 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). +these libraries pre-compiled for iOS can be found in `this repository +`__. 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 From 302a5b093e2ee47e11c75c6081a6ce9a4fa2cd7d Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 23 Feb 2024 12:30:29 +0800 Subject: [PATCH 07/13] Add note about Command Line Tools, and the need for a Simulator platform. --- iOS/README.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/iOS/README.rst b/iOS/README.rst index 302863c6c25527..3c3520a80effff 100644 --- a/iOS/README.rst +++ b/iOS/README.rst @@ -21,7 +21,14 @@ 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. +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 =================================== From ba946fbd63ba14cf29322b51377b32efa0d808c0 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 23 Feb 2024 15:29:06 +0800 Subject: [PATCH 08/13] Modify compiler utility scripts to avoid bash, and allow for SDK version configuration. --- iOS/README.rst | 10 ++++++++++ iOS/Resources/bin/arm64-apple-ios-ar | 4 ++-- iOS/Resources/bin/arm64-apple-ios-clang | 4 ++-- iOS/Resources/bin/arm64-apple-ios-cpp | 4 ++-- iOS/Resources/bin/arm64-apple-ios-simulator-ar | 4 ++-- iOS/Resources/bin/arm64-apple-ios-simulator-clang | 4 ++-- iOS/Resources/bin/arm64-apple-ios-simulator-cpp | 4 ++-- iOS/Resources/bin/x86_64-apple-ios-simulator-ar | 4 ++-- iOS/Resources/bin/x86_64-apple-ios-simulator-clang | 4 ++-- iOS/Resources/bin/x86_64-apple-ios-simulator-cpp | 4 ++-- 10 files changed, 28 insertions(+), 18 deletions(-) diff --git a/iOS/README.rst b/iOS/README.rst index 3c3520a80effff..9e0caa9e77d840 100644 --- a/iOS/README.rst +++ b/iOS/README.rst @@ -117,6 +117,16 @@ In this invocation: 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 diff --git a/iOS/Resources/bin/arm64-apple-ios-ar b/iOS/Resources/bin/arm64-apple-ios-ar index add54095b14892..8122332b9c1de0 100755 --- a/iOS/Resources/bin/arm64-apple-ios-ar +++ b/iOS/Resources/bin/arm64-apple-ios-ar @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphoneos ar $@ +#!/bin/sh +xcrun --sdk iphoneos${IOS_SDK_VERSION} ar $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-clang b/iOS/Resources/bin/arm64-apple-ios-clang index e1a7b59f45d80a..4d525751eba798 100755 --- a/iOS/Resources/bin/arm64-apple-ios-clang +++ b/iOS/Resources/bin/arm64-apple-ios-clang @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphoneos clang -target arm64-apple-ios $@ +#!/bin/sh +xcrun --sdk iphoneos${IOS_SDK_VERSION} clang -target arm64-apple-ios $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-cpp b/iOS/Resources/bin/arm64-apple-ios-cpp index ff3ce4f363d4d6..891bb25bb4318c 100755 --- a/iOS/Resources/bin/arm64-apple-ios-cpp +++ b/iOS/Resources/bin/arm64-apple-ios-cpp @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphoneos clang -target arm64-apple-ios -E $@ +#!/bin/sh +xcrun --sdk iphoneos${IOS_SDK_VERSION} clang -target arm64-apple-ios -E $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-simulator-ar b/iOS/Resources/bin/arm64-apple-ios-simulator-ar index 722ee1b996bb52..74ed3bc6df1c2b 100755 --- a/iOS/Resources/bin/arm64-apple-ios-simulator-ar +++ b/iOS/Resources/bin/arm64-apple-ios-simulator-ar @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphonesimulator ar $@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} ar $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-simulator-clang b/iOS/Resources/bin/arm64-apple-ios-simulator-clang index 3dfc651212b604..32574cad284441 100755 --- a/iOS/Resources/bin/arm64-apple-ios-simulator-clang +++ b/iOS/Resources/bin/arm64-apple-ios-simulator-clang @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphonesimulator clang -target arm64-apple-ios-simulator $@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target arm64-apple-ios-simulator $@ diff --git a/iOS/Resources/bin/arm64-apple-ios-simulator-cpp b/iOS/Resources/bin/arm64-apple-ios-simulator-cpp index aa44f39a80166d..6aaf6fbe188c32 100755 --- a/iOS/Resources/bin/arm64-apple-ios-simulator-cpp +++ b/iOS/Resources/bin/arm64-apple-ios-simulator-cpp @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphonesimulator clang -target arm64-apple-ios-simulator -E $@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target arm64-apple-ios-simulator -E $@ diff --git a/iOS/Resources/bin/x86_64-apple-ios-simulator-ar b/iOS/Resources/bin/x86_64-apple-ios-simulator-ar index 722ee1b996bb52..74ed3bc6df1c2b 100755 --- a/iOS/Resources/bin/x86_64-apple-ios-simulator-ar +++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-ar @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphonesimulator ar $@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} ar $@ diff --git a/iOS/Resources/bin/x86_64-apple-ios-simulator-clang b/iOS/Resources/bin/x86_64-apple-ios-simulator-clang index 567bf6b6f21d2c..bcbe91f6061e16 100755 --- a/iOS/Resources/bin/x86_64-apple-ios-simulator-clang +++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-clang @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphonesimulator clang -target x86_64-apple-ios-simulator $@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target x86_64-apple-ios-simulator $@ diff --git a/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp b/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp index 046cccfd0190af..e6a42d9b85dec7 100755 --- a/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp +++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-cpp @@ -1,2 +1,2 @@ -#!/bin/bash -xcrun --sdk iphonesimulator clang -target x86_64-apple-ios-simulator -E $@ +#!/bin/sh +xcrun --sdk iphonesimulator${IOS_SDK_VERSION} clang -target x86_64-apple-ios-simulator -E $@ From 24b3770857d628d5080a4510beb21cefd91b1f3e Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 23 Feb 2024 16:03:52 +0800 Subject: [PATCH 09/13] Added support for DESTDIR to iOS framework targets. --- Makefile.pre.in | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 0e241eccd6b106..1f913c039e5b59 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2656,16 +2656,16 @@ frameworkinstallunversionedstructure: $(LDLIBRARY) exit 1; \ else true; \ fi - if test -d $(PYTHONFRAMEWORKPREFIX)/include; then \ + if test -d $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include; then \ echo "Clearing stale header symlink directory"; \ - rm -rf $(PYTHONFRAMEWORKPREFIX)/include; \ + rm -rf $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/include; \ fi - $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKINSTALLDIR) - sed 's/%VERSION%/'"`$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(PYTHONFRAMEWORKINSTALLDIR)/Info.plist - $(INSTALL_SHARED) $(LDLIBRARY) $(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY) - $(INSTALL) -d -m $(DIRMODE) $(BINDIR) + $(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 $(RESSRCDIR)/bin/* ; do \ - $(INSTALL) -m $(EXEMODE) $$file $(BINDIR); \ + $(INSTALL) -m $(EXEMODE) $$file $(DESTDIR)$(BINDIR); \ done # This installs Mac/Lib into the framework @@ -2714,12 +2714,12 @@ frameworkinstallextras: # Python.framework; Move the headers to their final framework-compatible home. .PHONY: frameworkinstallmobileheaders frameworkinstallmobileheaders: - if test -d $(PYTHONFRAMEWORKINSTALLDIR)/Headers; then \ + if test -d $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers; then \ echo "Removing old framework headers"; \ - rm -rf $(PYTHONFRAMEWORKINSTALLDIR)/Headers; \ + rm -rf $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers; \ fi - mv "$(PYTHONFRAMEWORKPREFIX)/include/python$(VERSION)" "$(PYTHONFRAMEWORKINSTALLDIR)/Headers" - $(LN) -fs "$(PYTHONFRAMEWORKDIR)" "$(PYTHONFRAMEWORKPREFIX)/include/python$(VERSION)" + 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 From 3a1a6fbf31f5ccc167fe99c052a7706e20232877 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sun, 25 Feb 2024 10:37:05 +0800 Subject: [PATCH 10/13] Correct dependency issue with parallel builds. --- configure | 9 ++++++++- configure.ac | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 0a9d6b4b1400b1..73362c0c5b5f11 100755 --- a/configure +++ b/configure @@ -24065,16 +24065,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)' diff --git a/configure.ac b/configure.ac index d1a4f62fea87b5..81f3f7753870f1 100644 --- a/configure.ac +++ b/configure.ac @@ -5980,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)' From 6247052b1d9090d29a458283218405cffb95b406 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sun, 25 Feb 2024 10:37:31 +0800 Subject: [PATCH 11/13] Correct issue with finding resources when not building from the root dir. --- Makefile.pre.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index 1f913c039e5b59..becd5ad6bdc7b4 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2661,10 +2661,10 @@ frameworkinstallunversionedstructure: $(LDLIBRARY) 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 + sed 's/%VERSION%/'"`$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import platform; print(platform.python_version())'`"'/g' < $(srcdir)/$(RESSRCDIR)/Info.plist > $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Info.plist $(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY) $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$(BINDIR) - for file in $(RESSRCDIR)/bin/* ; do \ + for file in $(srcdir)/$(RESSRCDIR)/bin/* ; do \ $(INSTALL) -m $(EXEMODE) $$file $(DESTDIR)$(BINDIR); \ done From 49778feeccea892901b3009cf4e8de9a6e08e85d Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 26 Feb 2024 08:38:46 +0800 Subject: [PATCH 12/13] Removed an unnecessary srcdir usage. --- Makefile.pre.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.pre.in b/Makefile.pre.in index becd5ad6bdc7b4..8893da816e9336 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -2661,7 +2661,7 @@ frameworkinstallunversionedstructure: $(LDLIBRARY) 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' < $(srcdir)/$(RESSRCDIR)/Info.plist > $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Info.plist + 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 \ From 8a3cbebce468d438d82c335edd97d18b2576db11 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 26 Feb 2024 08:55:40 +0800 Subject: [PATCH 13/13] Clarified the restriction on host python compatibility. --- iOS/README.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iOS/README.rst b/iOS/README.rst index 9e0caa9e77d840..1043b5ecebbc0c 100644 --- a/iOS/README.rst +++ b/iOS/README.rst @@ -156,7 +156,10 @@ In this invocation: 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 *exact* same version as the Python that is being compiled. + 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).