From f0c1acdfeaa592e8010fcfad246b7e02677c730a Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 1 Nov 2023 09:30:58 +0800 Subject: [PATCH 01/13] Extract macOS framework from official binary release. --- Makefile | 192 ++++++++--------------------- patch/Python/release.macOS.exclude | 12 +- 2 files changed, 59 insertions(+), 145 deletions(-) diff --git a/Makefile b/Makefile index 76689c3..32019c9 100644 --- a/Makefile +++ b/Makefile @@ -104,6 +104,12 @@ downloads/Python-$(PYTHON_VERSION).tar.gz: curl $(CURL_FLAGS) -o $@ \ https://www.python.org/ftp/python/$(PYTHON_MICRO_VERSION)/Python-$(PYTHON_VERSION).tgz +downloads/python-$(PYTHON_VERSION)-macos11.pkg: + @echo ">>> Download macOS Python package" + mkdir -p downloads + curl $(CURL_FLAGS) -o $@ \ + https://www.python.org/ftp/python/$(PYTHON_MICRO_VERSION)/python-$(PYTHON_VERSION)-macos11.pkg + ########################################################################### # Build for specified target (from $(TARGETS-*)) ########################################################################### @@ -398,146 +404,15 @@ endif # Expand the build-target macro for target on this OS $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(eval $$(call build-target,$$(target),$(os)))) -########################################################################### -# SDK: Aliases -########################################################################### - -support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(sdk))-clang: - patch/make-xcrun-alias $$@ "--sdk $(sdk) clang" - -support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(sdk))-cpp: - patch/make-xcrun-alias $$@ "--sdk $(sdk) clang -E" - -support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(sdk))-ar: - patch/make-xcrun-alias $$@ "--sdk $(sdk) ar" - -########################################################################### -# SDK: BZip2 -########################################################################### - -BZIP2_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/bzip2-$(BZIP2_VERSION) -BZIP2_LIB-$(sdk)=$$(BZIP2_INSTALL-$(sdk))/lib/libbz2.a - -# This is only used on macOS. -downloads/bzip2-$(BZIP2_VERSION)-$(sdk).tar.gz: - @echo ">>> Download BZip2 for $(sdk)" - mkdir -p downloads - curl $(CURL_FLAGS) -o $$@ \ - https://github.com/beeware/cpython-macOS-source-deps/releases/download/BZip2-$(BZIP2_VERSION)/bzip2-$(BZIP2_VERSION)-$(sdk).tar.gz - -$$(BZIP2_LIB-$(sdk)): downloads/bzip2-$(BZIP2_VERSION)-$(sdk).tar.gz - @echo ">>> Install BZip2 for $(sdk)" - mkdir -p $$(BZIP2_INSTALL-$(sdk)) - cd $$(BZIP2_INSTALL-$(sdk)) && tar zxvf $(PROJECT_DIR)/downloads/bzip2-$(BZIP2_VERSION)-$(sdk).tar.gz - # Ensure the target is marked as clean. - touch $$(BZIP2_LIB-$(sdk)) - -########################################################################### -# SDK: XZ (LZMA) -########################################################################### - -XZ_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/xz-$(XZ_VERSION) -XZ_LIB-$(sdk)=$$(XZ_INSTALL-$(sdk))/lib/liblzma.a - -# This is only used on macOS. -downloads/xz-$(XZ_VERSION)-$(sdk).tar.gz: - @echo ">>> Download XZ for $(sdk)" - mkdir -p downloads - curl $(CURL_FLAGS) -o $$@ \ - https://github.com/beeware/cpython-macOS-source-deps/releases/download/XZ-$(XZ_VERSION)/xz-$(XZ_VERSION)-$(sdk).tar.gz - -$$(XZ_LIB-$(sdk)): downloads/xz-$(XZ_VERSION)-$(sdk).tar.gz - @echo ">>> Install XZ for $(sdk)" - mkdir -p $$(XZ_INSTALL-$(sdk)) - cd $$(XZ_INSTALL-$(sdk)) && tar zxvf $(PROJECT_DIR)/downloads/xz-$(XZ_VERSION)-$(sdk).tar.gz - # Ensure the target is marked as clean. - touch $$(XZ_LIB-$(sdk)) - -########################################################################### -# SDK: OpenSSL -########################################################################### - -OPENSSL_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/openssl-$(OPENSSL_VERSION) -OPENSSL_SSL_LIB-$(sdk)=$$(OPENSSL_INSTALL-$(sdk))/lib/libssl.a - -# This is only used on macOS. -downloads/openssl-$(OPENSSL_VERSION)-$(sdk).tar.gz: - @echo ">>> Download OpenSSL for $(sdk)" - mkdir -p downloads - curl $(CURL_FLAGS) -o $$@ \ - https://github.com/beeware/cpython-macOS-source-deps/releases/download/OpenSSL-$(OPENSSL_VERSION)/openssl-$(OPENSSL_VERSION)-$(sdk).tar.gz - -$$(OPENSSL_SSL_LIB-$(sdk)): downloads/openssl-$(OPENSSL_VERSION)-$(sdk).tar.gz - @echo ">>> Install OpenSSL for $(sdk)" - mkdir -p $$(OPENSSL_INSTALL-$(sdk)) - cd $$(OPENSSL_INSTALL-$(sdk)) && tar zxvf $(PROJECT_DIR)/downloads/openssl-$(OPENSSL_VERSION)-$(sdk).tar.gz - # Ensure the target is marked as clean. - touch $$(OPENSSL_SSL_LIB-$(sdk)) - ########################################################################### # SDK: Python ########################################################################### -# macOS builds are compiled as a single universal2 build. The fat library is a -# direct copy of OS build, and the headers and standard library are unmodified -# from the versions produced by the OS build. -ifeq ($(os),macOS) - -PYTHON_SRCDIR-$(sdk)=build/$(os)/$(sdk)/python-$(PYTHON_VERSION) - -$$(PYTHON_SRCDIR-$(sdk))/configure: \ - $$(BZIP2_LIB-$$(sdk)) \ - $$(XZ_LIB-$$(sdk)) \ - $$(OPENSSL_SSL_LIB-$$(sdk)) \ - downloads/Python-$(PYTHON_VERSION).tar.gz - @echo ">>> Unpack and configure Python for $(sdk)" - mkdir -p $$(PYTHON_SRCDIR-$(sdk)) - tar zxf downloads/Python-$(PYTHON_VERSION).tar.gz --strip-components 1 -C $$(PYTHON_SRCDIR-$(sdk)) - # Apply target Python patches - cd $$(PYTHON_SRCDIR-$(sdk)) && patch -p1 < $(PROJECT_DIR)/patch/Python/Python.patch - # Touch the configure script to ensure that Make identifies it as up to date. - touch $$(PYTHON_SRCDIR-$(sdk))/configure - -$$(PYTHON_SRCDIR-$(sdk))/Makefile: \ - support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(sdk))-clang \ - support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(sdk))-cpp \ - $$(PYTHON_SRCDIR-$(sdk))/configure - # Configure target Python - cd $$(PYTHON_SRCDIR-$(sdk)) && \ - PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/bin:$(PATH)" \ - ./configure \ - CC=$$(TARGET_TRIPLE-$(sdk))-clang \ - CPP=$$(TARGET_TRIPLE-$(sdk))-cpp \ - CFLAGS="$$(CFLAGS-$(sdk))" \ - LDFLAGS="$$(LDFLAGS-$(sdk))" \ - LIBLZMA_CFLAGS="-I$$(XZ_INSTALL-$(sdk))/include" \ - LIBLZMA_LIBS="-L$$(XZ_INSTALL-$(sdk))/lib -llzma" \ - BZIP2_CFLAGS="-I$$(BZIP2_INSTALL-$(sdk))/include" \ - BZIP2_LIBS="-L$$(BZIP2_INSTALL-$(sdk))/lib -lbz2" \ - MACOSX_DEPLOYMENT_TARGET="$$(VERSION_MIN-$(os))" \ - --prefix="$$(PYTHON_INSTALL-$(sdk))" \ - --enable-ipv6 \ - --enable-universalsdk \ - --with-openssl="$$(OPENSSL_INSTALL-$(sdk))" \ - --with-universal-archs=universal2 \ - --without-ensurepip \ - 2>&1 | tee -a ../python-$(PYTHON_VERSION).config.log - -$$(PYTHON_SRCDIR-$(sdk))/python.exe: $$(PYTHON_SRCDIR-$(sdk))/Makefile - @echo ">>> Build Python for $(sdk)" - cd $$(PYTHON_SRCDIR-$(sdk)) && \ - PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/bin:$(PATH)" \ - make all \ - 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log - -$$(PYTHON_LIB-$(sdk)) $$(PYTHON_INCLUDE-$$(sdk))/Python.h $$(PYTHON_STDLIB-$(sdk))/LICENSE.TXT: $$(PYTHON_SRCDIR-$(sdk))/python.exe - @echo ">>> Install Python for $(sdk)" - cd $$(PYTHON_SRCDIR-$(sdk)) && \ - make install \ - 2>&1 | tee -a ../python-$(PYTHON_VERSION).install.log - -else +ifneq ($(os),macOS) +# macOS builds are extracted from the official installer package, then +# reprocessed into an XCFramework. +# # Non-macOS builds need to be merged on a per-SDK basis. The merge covers: # * Merging a fat libPython.a # * Installing an architecture-sensitive pyconfig.h @@ -632,6 +507,47 @@ $$(foreach sdk,$$(SDKS-$(os)),$$(eval $$(call build-sdk,$$(sdk),$(os)))) # Build: Python ########################################################################### +ifeq ($(os),macOS) + +$$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \ + downloads/python-$(PYTHON_VERSION)-macos11.pkg + @echo ">>> Repackage macOS package as XCFramework" + + # Unpack .pkg file. It turns out .pkg files are readable by tar... although + # their internal format is a bit of a mess. From tar's perspective, the .pkg + # is a tarball that contains additional tarballs; the inner tarball has the + # "payload" that is the framework. + mkdir -p build/macOS/macosx/python-$(PYTHON_VERSION) + tar zxf downloads/python-$(PYTHON_VERSION)-macos11.pkg -C build/macOS/macosx/python-$(PYTHON_VERSION) + + # Unpack payload inside .pkg file + mkdir -p install/macOS/macosx/python-$(PYTHON_VERSION)/Python.framework + tar zxf build/macOS/macosx/python-$(PYTHON_VERSION)/Python_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/Payload -C install/macOS/macosx/python-$(PYTHON_VERSION)/Python.framework -X patch/Python/release.macOS.exclude + + # Remove the signature from the extracted framework + codesign --remove-signature install/macOS/macosx/python-$(PYTHON_VERSION)/Python.framework + + # Create XCFramework out of the extracted framework + xcodebuild -create-xcframework -output $$(PYTHON_XCFRAMEWORK-$(os)) -framework install/macOS/macosx/python-$(PYTHON_VERSION)/Python.framework + +support/$(PYTHON_VER)/macOS/VERSIONS: + @echo ">>> Create VERSIONS file for macOS" + echo "Python version: $(PYTHON_VERSION) " > support/$(PYTHON_VER)/macOS/VERSIONS + echo "Build: $(BUILD_NUMBER)" >> support/$(PYTHON_VER)/macOS/VERSIONS + echo "Min macOS version: $$(VERSION_MIN-macOS)" >> support/$(PYTHON_VER)/macOS/VERSIONS + +dist/Python-$(PYTHON_VER)-macOS-support.$(BUILD_NUMBER).tar.gz: \ + $$(PYTHON_XCFRAMEWORK-macOS)/Info.plist \ + support/$(PYTHON_VER)/macOS/VERSIONS \ + $$(foreach target,$$(TARGETS-macOS), $$(PYTHON_SITECUSTOMIZE-$$(target))) + + @echo ">>> Create final distribution artefact for macOS" + mkdir -p dist + # Build a distributable tarball + tar zcvf $$@ -C support/$(PYTHON_VER)/macOS `ls -A support/$(PYTHON_VER)/macOS/` + +else + $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \ $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_LIB-$$(sdk)) $$(PYTHON_INCLUDE-$$(sdk))/Python.h) @echo ">>> Create Python.XCFramework on $(os)" @@ -666,11 +582,7 @@ $$(PYTHON_STDLIB-$(os))/VERSIONS: \ echo "Build: $(BUILD_NUMBER)" >> support/$(PYTHON_VER)/$(os)/VERSIONS echo "Min $(os) version: $$(VERSION_MIN-$(os))" >> support/$(PYTHON_VER)/$(os)/VERSIONS echo "---------------------" >> support/$(PYTHON_VER)/$(os)/VERSIONS -ifeq ($(os),macOS) - echo "libFFI: built-in" >> support/$(PYTHON_VER)/$(os)/VERSIONS -else echo "libFFI: $(LIBFFI_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS -endif echo "BZip2: $(BZIP2_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS echo "OpenSSL: $(OPENSSL_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS echo "XZ: $(XZ_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS @@ -687,6 +599,8 @@ dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz: \ # Build a distributable tarball tar zcvf $$@ -X patch/Python/release.common.exclude -X patch/Python/release.$(os).exclude -C support/$(PYTHON_VER)/$(os) `ls -A support/$(PYTHON_VER)/$(os)/` +endif + clean-$(os): @echo ">>> Clean Python build products on $(os)" rm -rf \ diff --git a/patch/Python/release.macOS.exclude b/patch/Python/release.macOS.exclude index 1428348..1385454 100644 --- a/patch/Python/release.macOS.exclude +++ b/patch/Python/release.macOS.exclude @@ -1,8 +1,8 @@ -# This is a list of support package path patterns that we exclude -# from macOS Python-Apple-support tarballs. +# This is a list of Framework path patterns that we exclude +# when building macOS Python-Apple-support tarballs from the official Framework # It is used by `tar -X` during the Makefile build. # -# Remove the testing binary modules -python-stdlib/lib-dynload/*_test*.so -python-stdlib/lib-dynload/_xx*.so -python-stdlib/lib-dynload/xx*.so +./Versions/*/Resources/Python.app +./Versions/*/bin +./Versions/*/etc +./Versions/*/share From 9ef6e91805677336f09c42fa3e54aec8e364f6a7 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 14 Nov 2023 13:43:20 +0800 Subject: [PATCH 02/13] Modify build process to generate frameworks for iOS/tvOS/watchOS. --- Makefile | 205 ++- patch/Python/Python.patch | 1835 ++++++++++++++++++++++++-- patch/Python/release.common.exclude | 26 - patch/Python/release.iOS.exclude | 12 +- patch/Python/release.tvOS.exclude | 12 +- patch/Python/release.watchOS.exclude | 12 +- patch/make-macho-standalone.py | 10 + 7 files changed, 1867 insertions(+), 245 deletions(-) delete mode 100644 patch/Python/release.common.exclude create mode 100644 patch/make-macho-standalone.py diff --git a/Makefile b/Makefile index 32019c9..40d637e 100644 --- a/Makefile +++ b/Makefile @@ -37,23 +37,19 @@ CURL_FLAGS=--disable --fail --location --create-dirs --progress-bar # macOS targets TARGETS-macOS=macosx.x86_64 macosx.arm64 VERSION_MIN-macOS=11.0 -CFLAGS-macOS=-mmacosx-version-min=$(VERSION_MIN-macOS) # iOS targets TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64 VERSION_MIN-iOS=12.0 -CFLAGS-iOS=-mios-version-min=$(VERSION_MIN-iOS) # tvOS targets TARGETS-tvOS=appletvsimulator.x86_64 appletvsimulator.arm64 appletvos.arm64 VERSION_MIN-tvOS=9.0 -CFLAGS-tvOS=-mtvos-version-min=$(VERSION_MIN-tvOS) PYTHON_CONFIGURE-tvOS=ac_cv_func_sigaltstack=no # watchOS targets TARGETS-watchOS=watchsimulator.x86_64 watchsimulator.arm64 watchos.arm64_32 VERSION_MIN-watchOS=4.0 -CFLAGS-watchOS=-mwatchos-version-min=$(VERSION_MIN-watchOS) PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no # The architecture of the machine doing the build @@ -131,29 +127,17 @@ ARCH-$(target)=$$(subst .,,$$(suffix $(target))) WHEEL_TAG-$(target)=py3-none-$$(shell echo $$(OS_LOWER-$(target))_$$(VERSION_MIN-$(os))_$(target) | sed "s/\./_/g") -ifeq ($(os),macOS) -TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-darwin -else +ifneq ($(os),macOS) ifeq ($$(findstring simulator,$$(SDK-$(target))),) TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))$$(VERSION_MIN-$(os)) +TARGET_TOOL_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target)) else TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))$$(VERSION_MIN-$(os))-simulator +TARGET_TOOL_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))-simulator endif endif SDK_ROOT-$(target)=$$(shell xcrun --sdk $$(SDK-$(target)) --show-sdk-path) -CFLAGS-$(target)=$$(CFLAGS-$(os)) -LDFLAGS-$(target)=$$(CFLAGS-$(os)) - -########################################################################### -# Target: Aliases -########################################################################### - -support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(target))-clang: - patch/make-xcrun-alias $$@ "--sdk $$(SDK-$(target)) clang -target $$(TARGET_TRIPLE-$(target))" - -support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(target))-cpp: - patch/make-xcrun-alias $$@ "--sdk $$(SDK-$(target)) clang -target $$(TARGET_TRIPLE-$(target)) -E" ########################################################################### # Target: BZip2 @@ -253,7 +237,11 @@ ifneq ($(os),macOS) PYTHON_SRCDIR-$(target)=build/$(os)/$(target)/python-$(PYTHON_VERSION) PYTHON_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/python-$(PYTHON_VERSION) -PYTHON_LIB-$(target)=$$(PYTHON_INSTALL-$(target))/lib/libpython$(PYTHON_VER).a +PYTHON_FRAMEWORK-$(target)=$$(PYTHON_INSTALL-$(target))/Python.framework +PYTHON_LIB-$(target)=$$(PYTHON_FRAMEWORK-$(target))/Python +PYTHON_BIN-$(target)=$$(PYTHON_INSTALL-$(target))/bin +PYTHON_INCLUDE-$(target)=$$(PYTHON_FRAMEWORK-$(target))/Headers +PYTHON_STDLIB-$(target)=$$(PYTHON_INSTALL-$(target))/lib/python$(PYTHON_VER) $$(PYTHON_SRCDIR-$(target))/configure: \ downloads/Python-$(PYTHON_VERSION).tar.gz \ @@ -266,24 +254,21 @@ $$(PYTHON_SRCDIR-$(target))/configure: \ tar zxf downloads/Python-$(PYTHON_VERSION).tar.gz --strip-components 1 -C $$(PYTHON_SRCDIR-$(target)) # Apply target Python patches cd $$(PYTHON_SRCDIR-$(target)) && patch -p1 < $(PROJECT_DIR)/patch/Python/Python.patch + # Make sure the binary scripts are executable + chmod 755 $$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin/* # Touch the configure script to ensure that Make identifies it as up to date. touch $$(PYTHON_SRCDIR-$(target))/configure $$(PYTHON_SRCDIR-$(target))/Makefile: \ - support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$$(SDK-$(target)))-ar \ - support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(target))-clang \ - support/$(PYTHON_VER)/$(os)/bin/$$(TARGET_TRIPLE-$(target))-cpp \ $$(PYTHON_SRCDIR-$(target))/configure # Configure target Python cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ ./configure \ - AR=$$(TARGET_TRIPLE-$$(SDK-$(target)))-ar \ - CC=$$(TARGET_TRIPLE-$(target))-clang \ - CPP=$$(TARGET_TRIPLE-$(target))-cpp \ - CXX=$$(TARGET_TRIPLE-$(target))-clang \ - CFLAGS="$$(CFLAGS-$(target))" \ - LDFLAGS="$$(LDFLAGS-$(target))" \ + AR=$$(TARGET_TOOL_TRIPLE-$(target))-ar \ + CC=$$(TARGET_TOOL_TRIPLE-$(target))-clang \ + CPP=$$(TARGET_TOOL_TRIPLE-$(target))-cpp \ + CXX=$$(TARGET_TOOL_TRIPLE-$(target))-clang \ LIBLZMA_CFLAGS="-I$$(XZ_INSTALL-$(target))/include" \ LIBLZMA_LIBS="-L$$(XZ_INSTALL-$(target))/lib -llzma" \ BZIP2_CFLAGS="-I$$(BZIP2_INSTALL-$(target))/include" \ @@ -293,10 +278,10 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ --host=$$(TARGET_TRIPLE-$(target)) \ --build=$(HOST_ARCH)-apple-darwin \ --with-build-python=$(HOST_PYTHON) \ - --prefix="$$(PYTHON_INSTALL-$(target))" \ --enable-ipv6 \ --with-openssl="$$(OPENSSL_INSTALL-$(target))" \ --without-ensurepip \ + --enable-framework="$$(PYTHON_INSTALL-$(target))" \ ac_cv_file__dev_ptmx=no \ ac_cv_file__dev_ptc=no \ $$(PYTHON_CONFIGURE-$(os)) \ @@ -305,14 +290,14 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ $$(PYTHON_SRCDIR-$(target))/python.exe: $$(PYTHON_SRCDIR-$(target))/Makefile @echo ">>> Build Python for $(target)" cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ make all \ 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log $$(PYTHON_LIB-$(target)): $$(PYTHON_SRCDIR-$(target))/python.exe @echo ">>> Install Python for $(target)" cd $$(PYTHON_SRCDIR-$(target)) && \ - PATH="$(PROJECT_DIR)/support/$(PYTHON_VER)/$(os)/bin:$(PATH)" \ + PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ make install \ 2>&1 | tee -a ../python-$(PYTHON_VERSION).install.log @@ -341,8 +326,6 @@ vars-$(target): @echo "ARCH-$(target): $$(ARCH-$(target))" @echo "TARGET_TRIPLE-$(target): $$(TARGET_TRIPLE-$(target))" @echo "SDK_ROOT-$(target): $$(SDK_ROOT-$(target))" - @echo "CFLAGS-$(target): $$(CFLAGS-$(target))" - @echo "LDFLAGS-$(target): $$(LDFLAGS-$(target))" @echo "BZIP2_INSTALL-$(target): $$(BZIP2_INSTALL-$(target))" @echo "BZIP2_LIB-$(target): $$(BZIP2_LIB-$(target))" @echo "XZ_INSTALL-$(target): $$(XZ_INSTALL-$(target))" @@ -353,7 +336,11 @@ vars-$(target): @echo "LIBFFI_LIB-$(target): $$(LIBFFI_LIB-$(target))" @echo "PYTHON_SRCDIR-$(target): $$(PYTHON_SRCDIR-$(target))" @echo "PYTHON_INSTALL-$(target): $$(PYTHON_INSTALL-$(target))" + @echo "PYTHON_FRAMEWORK-$(target): $$(PYTHON_FRAMEWORK-$(target))" @echo "PYTHON_LIB-$(target): $$(PYTHON_LIB-$(target))" + @echo "PYTHON_BIN-$(target): $$(PYTHON_BIN-$(target))" + @echo "PYTHON_INCLUDE-$(target): $$(PYTHON_INCLUDE-$(target))" + @echo "PYTHON_STDLIB-$(target): $$(PYTHON_STDLIB-$(target))" @echo endef # build-target @@ -382,25 +369,6 @@ else SDK_SLICE-$(sdk)=$$(OS_LOWER-$(sdk))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g")-simulator endif -CFLAGS-$(sdk)=$$(CFLAGS-$(os)) -LDFLAGS-$(sdk)=$$(CFLAGS-$(os)) - -# Predeclare SDK constants that are used by the build-target macro -PYTHON_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/python-$(PYTHON_VERSION) -PYTHON_LIB-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/lib/libpython$(PYTHON_VER).a -PYTHON_INCLUDE-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/include/python$(PYTHON_VER) -PYTHON_STDLIB-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/lib/python$(PYTHON_VER) - -ifeq ($(os),macOS) -TARGET_TRIPLE-$(sdk)=apple-darwin -else - ifeq ($$(findstring simulator,$(sdk)),) -TARGET_TRIPLE-$(sdk)=apple-$$(OS_LOWER-$(sdk))$$(VERSION_MIN-$(os)) - else -TARGET_TRIPLE-$(sdk)=apple-$$(OS_LOWER-$(sdk))$$(VERSION_MIN-$(os))-simulator - endif -endif - # Expand the build-target macro for target on this OS $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(eval $$(call build-target,$$(target),$(os)))) @@ -408,15 +376,31 @@ $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(eval $$(call build-target,$$(target) # SDK: Python ########################################################################### -ifneq ($(os),macOS) +ifeq ($(os),macOS) # macOS builds are extracted from the official installer package, then # reprocessed into an XCFramework. -# + +PYTHON_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/python-$(PYTHON_VERSION) +PYTHON_FRAMEWORK-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/Python.framework +PYTHON_INSTALL_VERSION-$(sdk)=$$(PYTHON_FRAMEWORK-$(sdk))/Versions/$(PYTHON_VER) +PYTHON_LIB-$(sdk)=$$(PYTHON_INSTALL_VERSION-$(sdk))/Python +PYTHON_INCLUDE-$(sdk)=$$(PYTHON_INSTALL_VERSION-$(sdk))/include/python$(PYTHON_VER) +PYTHON_STDLIB-$(sdk)=$$(PYTHON_INSTALL_VERSION-$(sdk))/lib/python$(PYTHON_VER) + +else # Non-macOS builds need to be merged on a per-SDK basis. The merge covers: -# * Merging a fat libPython.a +# * Merging a fat libPython # * Installing an architecture-sensitive pyconfig.h # * Merging fat versions of the standard library lib-dynload folder +# The non-macOS frameworks don't use the versioning structure. + +PYTHON_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/python-$(PYTHON_VERSION) +PYTHON_FRAMEWORK-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/Python.framework +PYTHON_LIB-$(sdk)=$$(PYTHON_FRAMEWORK-$(sdk))/Python +PYTHON_BIN-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/bin +PYTHON_INCLUDE-$(sdk)=$$(PYTHON_FRAMEWORK-$(sdk))/Headers +PYTHON_STDLIB-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/lib/python$(PYTHON_VER) $$(PYTHON_LIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_LIB-$$(target))) @echo ">>> Build Python fat library for the $(sdk) SDK" @@ -424,21 +408,30 @@ $$(PYTHON_LIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_LIB-$$ lipo -create -output $$@ $$^ \ 2>&1 | tee -a install/$(os)/$(sdk)/python-$(PYTHON_VERSION).lipo.log -$$(PYTHON_INCLUDE-$(sdk))/Python.h: $$(PYTHON_LIB-$(sdk)) +$$(PYTHON_FRAMEWORK-$(sdk))/Info.plist: $$(PYTHON_LIB-$(sdk)) + @echo ">>> Install Info.plist for the $(sdk) SDK" + # Copy Info.plist as-is from the first target in the $(sdk) SDK + cp -r $$(PYTHON_FRAMEWORK-$$(firstword $$(SDK_TARGETS-$(sdk))))/Info.plist $$(PYTHON_FRAMEWORK-$(sdk)) + +$$(PYTHON_INCLUDE-$(sdk))/pyconfig.h: $$(PYTHON_LIB-$(sdk)) @echo ">>> Build Python fat headers for the $(sdk) SDK" + # Copy binary helpers from the first target in the $(sdk) SDK + cp -r $$(PYTHON_BIN-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_BIN-$(sdk)) # Copy headers as-is from the first target in the $(sdk) SDK - mkdir -p $$(shell dirname $$(PYTHON_INCLUDE-$(sdk))) - cp -r $$(PYTHON_INSTALL-$$(firstword $$(SDK_TARGETS-$(sdk))))/include/python$(PYTHON_VER) $$(PYTHON_INCLUDE-$(sdk)) + cp -r $$(PYTHON_INCLUDE-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_INCLUDE-$(sdk)) + # Link the PYTHONHOME version of the headers + mkdir -p $$(PYTHON_INSTALL-$(sdk))/include + ln -si ../Python.framework/Headers $$(PYTHON_INSTALL-$(sdk))/include/python$(PYTHON_VER) + # Add the individual headers from each target in an arch-specific name + $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_INCLUDE-$$(target))/pyconfig.h $$(PYTHON_INCLUDE-$(sdk))/pyconfig-$$(ARCH-$$(target)).h; ) # Copy the cross-target header from the patch folder cp $(PROJECT_DIR)/patch/Python/pyconfig-$(os).h $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h - # Add the individual headers from each target in an arch-specific name - $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_INSTALL-$$(target))/include/python$(PYTHON_VER)/pyconfig.h $$(PYTHON_INCLUDE-$(sdk))/pyconfig-$$(ARCH-$$(target)).h; ) -$$(PYTHON_STDLIB-$(sdk))/LICENSE.TXT: $$(PYTHON_LIB-$(sdk)) +$$(PYTHON_STDLIB-$(sdk))/LICENSE.TXT: $$(PYTHON_LIB-$(sdk)) $$(PYTHON_FRAMEWORK-$(sdk))/Info.plist $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h @echo ">>> Build Python stdlib for the $(sdk) SDK" mkdir -p $$(PYTHON_STDLIB-$(sdk))/lib-dynload # Copy stdlib from the first target associated with the $(sdk) SDK - cp -r $$(PYTHON_INSTALL-$$(firstword $$(SDK_TARGETS-$(sdk))))/lib/python$(PYTHON_VER)/ $$(PYTHON_STDLIB-$(sdk)) + cp -r $$(PYTHON_STDLIB-$$(firstword $$(SDK_TARGETS-$(sdk))))/ $$(PYTHON_STDLIB-$(sdk)) # Delete the single-SDK parts of the standard library rm -rf \ @@ -447,13 +440,10 @@ $$(PYTHON_STDLIB-$(sdk))/LICENSE.TXT: $$(PYTHON_LIB-$(sdk)) $$(PYTHON_STDLIB-$(sdk))/lib-dynload/* # Copy the individual _sysconfigdata modules into names that include the architecture - $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_INSTALL-$$(target))/lib/python$(PYTHON_VER)/_sysconfigdata_* $$(PYTHON_STDLIB-$(sdk))/; ) - - # Copy the individual config modules directories into names that include the architecture - $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp -r $$(PYTHON_INSTALL-$$(target))/lib/python$(PYTHON_VER)/config-$(PYTHON_VER)-$(sdk)-$$(ARCH-$$(target)) $$(PYTHON_STDLIB-$(sdk))/; ) + $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_STDLIB-$$(target))/_sysconfigdata_* $$(PYTHON_STDLIB-$(sdk))/; ) # Merge the binary modules from each target in the $(sdk) SDK into a single binary - $$(foreach module,$$(wildcard $$(PYTHON_INSTALL-$$(firstword $$(SDK_TARGETS-$(sdk))))/lib/python$(PYTHON_VER)/lib-dynload/*),lipo -create -output $$(PYTHON_STDLIB-$(sdk))/lib-dynload/$$(notdir $$(module)) $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_INSTALL-$$(target))/lib/python$(PYTHON_VER)/lib-dynload/$$(notdir $$(module))); ) + $$(foreach module,$$(wildcard $$(PYTHON_STDLIB-$$(firstword $$(SDK_TARGETS-$(sdk))))/lib-dynload/*),lipo -create -output $$(PYTHON_STDLIB-$(sdk))/lib-dynload/$$(notdir $$(module)) $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_STDLIB-$$(target))/lib-dynload/$$(notdir $$(module))); ) endif @@ -468,13 +458,14 @@ vars-$(sdk): @echo "SDK_TARGETS-$(sdk): $$(SDK_TARGETS-$(sdk))" @echo "SDK_ARCHES-$(sdk): $$(SDK_ARCHES-$(sdk))" @echo "SDK_SLICE-$(sdk): $$(SDK_SLICE-$(sdk))" - @echo "CFLAGS-$(sdk): $$(CFLAGS-$(sdk))" @echo "LDFLAGS-$(sdk): $$(LDFLAGS-$(sdk))" - @echo "PYTHON_SRCDIR-$(sdk): $$(PYTHON_SRCDIR-$(sdk))" @echo "PYTHON_INSTALL-$(sdk): $$(PYTHON_INSTALL-$(sdk))" + @echo "PYTHON_FRAMEWORK-$(sdk): $$(PYTHON_FRAMEWORK-$(sdk))" @echo "PYTHON_LIB-$(sdk): $$(PYTHON_LIB-$(sdk))" + @echo "PYTHON_BIN-$(sdk): $$(PYTHON_BIN-$(sdk))" @echo "PYTHON_INCLUDE-$(sdk): $$(PYTHON_INCLUDE-$(sdk))" @echo "PYTHON_STDLIB-$(sdk): $$(PYTHON_STDLIB-$(sdk))" + @echo endef # build-sdk @@ -496,9 +487,6 @@ os=$1 SDKS-$(os)=$$(sort $$(basename $$(TARGETS-$(os)))) -# Predeclare the Python XCFramework files so they can be referenced in SDK targets -PYTHON_XCFRAMEWORK-$(os)=support/$(PYTHON_VER)/$(os)/Python.xcframework -PYTHON_STDLIB-$(os)=support/$(PYTHON_VER)/$(os)/python-stdlib # Expand the build-sdk macro for all the sdks on this OS (e.g., iphoneos, iphonesimulator) $$(foreach sdk,$$(SDKS-$(os)),$$(eval $$(call build-sdk,$$(sdk),$(os)))) @@ -507,8 +495,13 @@ $$(foreach sdk,$$(SDKS-$(os)),$$(eval $$(call build-sdk,$$(sdk),$(os)))) # Build: Python ########################################################################### + +PYTHON_XCFRAMEWORK-$(os)=support/$(PYTHON_VER)/$(os)/Python.xcframework + ifeq ($(os),macOS) +PYTHON_FRAMEWORK-$(os)=$$(PYTHON_INSTALL-$(sdk))/Python.framework + $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \ downloads/python-$(PYTHON_VERSION)-macos11.pkg @echo ">>> Repackage macOS package as XCFramework" @@ -521,14 +514,31 @@ $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \ tar zxf downloads/python-$(PYTHON_VERSION)-macos11.pkg -C build/macOS/macosx/python-$(PYTHON_VERSION) # Unpack payload inside .pkg file - mkdir -p install/macOS/macosx/python-$(PYTHON_VERSION)/Python.framework - tar zxf build/macOS/macosx/python-$(PYTHON_VERSION)/Python_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/Payload -C install/macOS/macosx/python-$(PYTHON_VERSION)/Python.framework -X patch/Python/release.macOS.exclude - - # Remove the signature from the extracted framework - codesign --remove-signature install/macOS/macosx/python-$(PYTHON_VERSION)/Python.framework + mkdir -p $$(PYTHON_FRAMEWORK-macosx) + tar zxf build/macOS/macosx/python-$(PYTHON_VERSION)/Python_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/Payload -C $$(PYTHON_FRAMEWORK-macosx) -X patch/Python/release.macOS.exclude + + # Rewrite the framework to make it standalone + python3 patch/make-macho-standalone.py $$(PYTHON_FRAMEWORK-macosx) \ + 2>&1 | tee $$(PYTHON_INSTALL-macosx)/python-$(PY_VERSION).make-macho-standalone.log + + # Remove the "development" versions of the libs + rm -f $$(PYTHON_INSTALL_VERSION-macosx)/lib/*.dylib + rm -f $$(PYTHON_INSTALL_VERSION-macosx)/lib/*.a + rm -rf $$(PYTHON_INSTALL_VERSION-macosx)/lib/python$(PY_VERSION)/config-* + + # Re-apply the signature on the binaries. + codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f $$(PYTHON_LIB-macosx) \ + 2>&1 | tee $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log + find install/macOS/macosx/python-3.13.0a1/Python.framework -name "*.dylib" -type f -exec codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \; \ + 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log + find install/macOS/macosx/python-3.13.0a1/Python.framework -name "*.so" -type f -exec codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \; \ + 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log + codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f $$(PYTHON_FRAMEWORK-macosx) \ + 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log # Create XCFramework out of the extracted framework - xcodebuild -create-xcframework -output $$(PYTHON_XCFRAMEWORK-$(os)) -framework install/macOS/macosx/python-$(PYTHON_VERSION)/Python.framework + xcodebuild -create-xcframework -output $$(PYTHON_XCFRAMEWORK-$(os)) -framework $$(PYTHON_FRAMEWORK-macosx) \ + 2>&1 | tee $$(PYTHON_INSTALL-macosx)/python-$(os).xcframework.log support/$(PYTHON_VER)/macOS/VERSIONS: @echo ">>> Create VERSIONS file for macOS" @@ -549,33 +559,20 @@ dist/Python-$(PYTHON_VER)-macOS-support.$(BUILD_NUMBER).tar.gz: \ else $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \ - $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_LIB-$$(sdk)) $$(PYTHON_INCLUDE-$$(sdk))/Python.h) + $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_STDLIB-$$(sdk))/LICENSE.TXT) @echo ">>> Create Python.XCFramework on $(os)" mkdir -p $$(dir $$(PYTHON_XCFRAMEWORK-$(os))) xcodebuild -create-xcframework \ - -output $$(PYTHON_XCFRAMEWORK-$(os)) $$(foreach sdk,$$(SDKS-$(os)),-library $$(PYTHON_LIB-$$(sdk)) -headers $$(PYTHON_INCLUDE-$$(sdk))) \ + -output $$(PYTHON_XCFRAMEWORK-$(os)) $$(foreach sdk,$$(SDKS-$(os)),-framework $$(PYTHON_FRAMEWORK-$$(sdk))) \ 2>&1 | tee -a support/$(PYTHON_VER)/python-$(os).xcframework.log -$$(PYTHON_STDLIB-$(os))/VERSIONS: \ - $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_STDLIB-$$(sdk))/LICENSE.TXT) - @echo ">>> Create Python stdlib on $(os)" - # Copy stdlib from first SDK in $(os) - cp -r $$(PYTHON_STDLIB-$$(firstword $$(SDKS-$(os)))) $$(PYTHON_STDLIB-$(os)) - - # Delete the single-SDK stdlib artefacts from $(os) - rm -rf \ - $$(PYTHON_STDLIB-$(os))/_sysconfigdata__*.py \ - $$(PYTHON_STDLIB-$(os))/config-* \ - $$(PYTHON_STDLIB-$(os))/lib-dynload/* - - # Copy the config-* contents from every SDK in $(os) into the support folder. - $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_STDLIB-$$(sdk))/config-$(PYTHON_VER)-* $$(PYTHON_STDLIB-$(os)); ) - - # Copy the _sysconfigdata modules from every SDK in $(os) into the support folder. - $$(foreach sdk,$$(SDKS-$(os)),cp $$(PYTHON_STDLIB-$$(sdk))/_sysconfigdata__*.py $$(PYTHON_STDLIB-$(os)); ) + @echo ">>> Install PYTHONHOME for $(os)" + $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_INSTALL-$$(sdk))/include $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk)); ) + $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_INSTALL-$$(sdk))/bin $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk)); ) + $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_INSTALL-$$(sdk))/lib $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk)); ) - # Copy the lib-dynload contents from every SDK in $(os) into the support folder. - $$(foreach sdk,$$(SDKS-$(os)),cp $$(PYTHON_STDLIB-$$(sdk))/lib-dynload/* $$(PYTHON_STDLIB-$(os))/lib-dynload; ) + @echo ">>> Create helper links in XCframework for $(os)" + $$(foreach sdk,$$(SDKS-$(os)),ln -si $$(SDK_SLICE-$$(sdk)) $$(PYTHON_XCFRAMEWORK-$(os))/$$(sdk); ) @echo ">>> Create VERSIONS file for $(os)" echo "Python version: $(PYTHON_VERSION) " > support/$(PYTHON_VER)/$(os)/VERSIONS @@ -589,15 +586,12 @@ $$(PYTHON_STDLIB-$(os))/VERSIONS: \ dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz: \ $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist \ - $$(PYTHON_STDLIB-$(os))/VERSIONS \ $$(foreach target,$$(TARGETS-$(os)), $$(PYTHON_SITECUSTOMIZE-$$(target))) @echo ">>> Create final distribution artefact for $(os)" mkdir -p dist - # Build a "full" tarball with all content for test purposes - tar zcvf dist/Python-$(PYTHON_VER)-$(os)-support.test-$(BUILD_NUMBER).tar.gz -X patch/Python/test.exclude -C support/$(PYTHON_VER)/$(os) `ls -A support/$(PYTHON_VER)/$(os)/` # Build a distributable tarball - tar zcvf $$@ -X patch/Python/release.common.exclude -X patch/Python/release.$(os).exclude -C support/$(PYTHON_VER)/$(os) `ls -A support/$(PYTHON_VER)/$(os)/` + tar zcvf $$@ -X patch/Python/release.$(os).exclude -C support/$(PYTHON_VER)/$(os) `ls -A support/$(PYTHON_VER)/$(os)/` endif @@ -609,6 +603,7 @@ clean-$(os): install/$(os)/*/python-$(PYTHON_VER)* \ install/$(os)/*/python-$(PYTHON_VER)*.*.log \ support/$(PYTHON_VER)/$(os) \ + support/$(PYTHON_VER)/python-$(os).*.log \ dist/Python-$(PYTHON_VER)-$(os)-* dev-clean-$(os): diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index 7267418..cd30184 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -1152,6 +1152,139 @@ index 8b0628745c..2d8de8aecb 100755 # # Platform support for Windows +diff --git a/Makefile.pre.in b/Makefile.pre.in +index 4996c5c309..24ee442643 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -184,6 +184,8 @@ + PYTHONFRAMEWORKDIR= @PYTHONFRAMEWORKDIR@ + PYTHONFRAMEWORKPREFIX= @PYTHONFRAMEWORKPREFIX@ + PYTHONFRAMEWORKINSTALLDIR= @PYTHONFRAMEWORKINSTALLDIR@ ++PYTHONFRAMEWORKINSTALLNAMEPREFIX= @PYTHONFRAMEWORKINSTALLNAMEPREFIX@ ++RESSRCDIR= @RESSRCDIR@ + # Deployment target selected during configure, to be checked + # by distutils. The export statement is needed to ensure that the + # deployment target is active during build. +@@ -843,7 +845,7 @@ + $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^ + + libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) +- $(CC) -dynamiclib -Wl,-single_module $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \ ++ $(CC) -dynamiclib $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \ + + + libpython$(VERSION).sl: $(LIBRARY_OBJS) +@@ -868,14 +870,13 @@ + # This rule is here for OPENSTEP/Rhapsody/MacOSX. It builds a temporary + # minimal framework (not including the Lib directory and such) in the current + # directory. +-RESSRCDIR=Mac/Resources/framework + $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \ + $(LIBRARY) \ + $(RESSRCDIR)/Info.plist + $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION) + $(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \ +- -all_load $(LIBRARY) -Wl,-single_module \ +- -install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \ ++ -all_load $(LIBRARY) \ ++ -install_name $(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \ + -compatibility_version $(VERSION) \ + -current_version $(VERSION) \ + -framework CoreFoundation $(LIBS); +@@ -887,6 +888,21 @@ + $(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) +@@ -1924,7 +1940,7 @@ + # which can lead to two parallel `./python setup.py build` processes that + # step on each others toes. + .PHONY: install +-install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKINSTALLLAST@ ++install: @FRAMEWORKINSTALLFIRST@ @INSTALLTARGETS@ @FRAMEWORKINSTALLLAST@ + if test "x$(ENSUREPIP)" != "xno" ; then \ + case $(ENSUREPIP) in \ + upgrade) ensurepip="--upgrade" ;; \ +@@ -2507,20 +2523,32 @@ + exit 1; \ + else true; \ + fi +- @for i in $(prefix)/Resources/English.lproj $(prefix)/lib; do\ +- if test ! -d $(DESTDIR)$$i; then \ +- echo "Creating directory $(DESTDIR)$$i"; \ +- $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$$i; \ +- else true; \ +- fi; \ +- done +- $(LN) -fsn include/python$(LDVERSION) $(DESTDIR)$(prefix)/Headers +- sed 's/%VERSION%/'"`$(RUNSHARED) ./$(BUILDPYTHON) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(prefix)/Resources/Info.plist +- $(LN) -fsn $(VERSION) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/Current +- $(LN) -fsn Versions/Current/$(PYTHONFRAMEWORK) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/$(PYTHONFRAMEWORK) +- $(LN) -fsn Versions/Current/Headers $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers +- $(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 binaries ++ @if test "$(MACHDEP)" = ios -o "$(MACHDEP)" = tvos -o "$(MACHDEP)" = watchos; then \ ++ $(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; \ ++ else \ ++ for i in $(prefix)/Resources/English.lproj $(prefix)/lib; do \ ++ if test ! -d $(DESTDIR)$$i; then \ ++ echo "Creating directory $(DESTDIR)$$i"; \ ++ $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$$i; \ ++ else true; \ ++ fi; \ ++ done; \ ++ $(LN) -fsn include/python$(LDVERSION) $(DESTDIR)$(prefix)/Headers; \ ++ sed 's/%VERSION%/'"`$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(prefix)/Resources/Info.plist; \ ++ $(LN) -fsn $(VERSION) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/Current; \ ++ $(LN) -fsn Versions/Current/$(PYTHONFRAMEWORK) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/$(PYTHONFRAMEWORK); \ ++ $(LN) -fsn Versions/Current/Headers $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers; \ ++ $(LN) -fsn Versions/Current/Resources $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Resources; \ ++ $(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY); \ ++ fi + + # This installs Mac/Lib into the framework + # Install a number of symlinks to keep software that expects a normal unix +@@ -2562,6 +2590,15 @@ + 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: ++ 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/platform_triplet.c b/Misc/platform_triplet.c index 3307260544..b5db9e8a80 100644 --- a/Misc/platform_triplet.c @@ -1311,6 +1444,19 @@ index 2898eedc3e..b48a143c34 100644 } /* module level code ********************************************************/ +diff --git a/Modules/getpath.c b/Modules/getpath.c +index 6f76a84e78..e91272f833 100644 +--- a/Modules/getpath.c ++++ b/Modules/getpath.c +@@ -758,7 +758,7 @@ + return winmodule_to_dict(dict, key, PyWin_DLLhModule); + } + #endif +-#elif defined(WITH_NEXT_FRAMEWORK) ++#elif defined(WITH_NEXT_FRAMEWORK) && !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + static char modPath[MAXPATHLEN + 1]; + static int modPathInitialized = -1; + if (modPathInitialized < 0) { diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index a4d9466559..8f51bef22d 100644 --- a/Modules/mathmodule.c @@ -1696,13 +1842,66 @@ index d74fb6deac..09ebc4287c 100755 # Blank kernel with real OS is always fine. ;; diff --git a/configure b/configure -index c87f518382..69685cd25a 100755 +index c87f518382..45f021d1b1 100755 --- a/configure +++ b/configure -@@ -4247,6 +4247,15 @@ - *-*-cygwin*) - ac_sys_system=Cygwin - ;; +@@ -963,10 +963,13 @@ + CFLAGS + CC + HAS_XCRUN ++WATCHOS_DEPLOYMENT_TARGET ++TVOS_DEPLOYMENT_TARGET ++IOS_DEPLOYMENT_TARGET + EXPORT_MACOSX_DEPLOYMENT_TARGET + CONFIGURE_MACOSX_DEPLOYMENT_TARGET + _PYTHON_HOST_PLATFORM +-MACHDEP ++INSTALLTARGETS + FRAMEWORKINSTALLAPPSPREFIX + FRAMEWORKUNIXTOOLSPREFIX + FRAMEWORKPYTHONW +@@ -974,6 +977,8 @@ + FRAMEWORKALTINSTALLFIRST + FRAMEWORKINSTALLLAST + FRAMEWORKINSTALLFIRST ++RESSRCDIR ++PYTHONFRAMEWORKINSTALLNAMEPREFIX + PYTHONFRAMEWORKINSTALLDIR + PYTHONFRAMEWORKPREFIX + PYTHONFRAMEWORKDIR +@@ -983,6 +988,7 @@ + LIPO_32BIT_FLAGS + ARCH_RUN_32BIT + UNIVERSALSDK ++MACHDEP + PKG_CONFIG_LIBDIR + PKG_CONFIG_PATH + PKG_CONFIG +@@ -3988,6 +3994,86 @@ + as_fn_error $? "pkg-config is required" "$LINENO" 5] + fi + ++# Set name for machine-dependent library files ++ ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5 ++printf %s "checking MACHDEP... " >&6; } ++if test -z "$MACHDEP" ++then ++ # avoid using uname for cross builds ++ if test "$cross_compiling" = yes; then ++ # ac_sys_system and ac_sys_release are used for setting ++ # a lot of different things including 'define_xopen_source' ++ # in the case statement below. ++ case "$host" in ++ *-*-linux-android*) ++ ac_sys_system=Linux-android ++ ;; ++ *-*-linux*) ++ ac_sys_system=Linux ++ ;; ++ *-*-cygwin*) ++ ac_sys_system=Cygwin ++ ;; + *-apple-ios*) + ac_sys_system=iOS + ;; @@ -1712,10 +1911,326 @@ index c87f518382..69685cd25a 100755 + *-apple-watchos*) + ac_sys_system=watchOS + ;; - *-*-vxworks*) - ac_sys_system=VxWorks - ;; -@@ -4303,27 +4312,96 @@ ++ *-*-vxworks*) ++ ac_sys_system=VxWorks ++ ;; ++ *-*-emscripten) ++ ac_sys_system=Emscripten ++ ;; ++ *-*-wasi) ++ ac_sys_system=WASI ++ ;; ++ *) ++ # for now, limit cross builds to known configurations ++ MACHDEP="unknown" ++ as_fn_error $? "cross build not supported for $host" "$LINENO" 5 ++ esac ++ ac_sys_release= ++ else ++ ac_sys_system=`uname -s` ++ if test "$ac_sys_system" = "AIX" \ ++ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then ++ ac_sys_release=`uname -v` ++ else ++ ac_sys_release=`uname -r` ++ fi ++ fi ++ ac_md_system=`echo $ac_sys_system | ++ tr -d '/ ' | tr '[A-Z]' '[a-z]'` ++ ac_md_release=`echo $ac_sys_release | ++ tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'` ++ MACHDEP="$ac_md_system$ac_md_release" ++ ++ case $MACHDEP in ++ aix*) MACHDEP="aix";; ++ linux*) MACHDEP="linux";; ++ cygwin*) MACHDEP="cygwin";; ++ darwin*) MACHDEP="darwin";; ++ '') MACHDEP="unknown";; ++ esac ++ ++ if test "$ac_sys_system" = "SunOS"; then ++ # For Solaris, there isn't an OS version specific macro defined ++ # in most compilers, so we define one here. ++ SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\(0-9\)$!.0\1!g' | tr -d '.'` ++ ++printf "%s\n" "#define Py_SUNOS_VERSION $SUNOS_VERSION" >>confdefs.h ++ ++ fi ++fi ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5 ++printf "%s\n" "\"$MACHDEP\"" >&6; } ++ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-universalsdk" >&5 + printf %s "checking for --enable-universalsdk... " >&6; } + # Check whether --enable-universalsdk was given. +@@ -4111,11 +4197,15 @@ + PYTHONFRAMEWORKDIR=no-framework + PYTHONFRAMEWORKPREFIX= + PYTHONFRAMEWORKINSTALLDIR= ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX= ++ RESSRCDIR= + FRAMEWORKINSTALLFIRST= + FRAMEWORKINSTALLLAST= + FRAMEWORKALTINSTALLFIRST= + FRAMEWORKALTINSTALLLAST= + FRAMEWORKPYTHONW= ++ INSTALLTARGETS="commoninstall bininstall maninstall" ++ + if test "x${prefix}" = "xNONE"; then + FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" + else +@@ -4128,65 +4218,112 @@ + PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR + FRAMEWORKINSTALLFIRST="frameworkinstallstructure" + FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure " +- FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools" +- FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools" +- FRAMEWORKPYTHONW="frameworkpythonw" +- FRAMEWORKINSTALLAPPSPREFIX="/Applications" + +- if test "x${prefix}" = "xNONE" ; then +- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" ++ case $ac_sys_system in #( ++ iOS) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" + +- else +- FRAMEWORKUNIXTOOLSPREFIX="${prefix}" +- fi ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=iOS/Resources + +- case "${enableval}" in +- /System*) +- FRAMEWORKINSTALLAPPSPREFIX="/Applications" +- if test "${prefix}" = "NONE" ; then +- # See below +- FRAMEWORKUNIXTOOLSPREFIX="/usr" +- fi +- ;; ++ ac_config_files="$ac_config_files iOS/Resources/Info.plist" + +- /Library*) +- FRAMEWORKINSTALLAPPSPREFIX="/Applications" +- ;; ++ ;; ++ tvOS) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" + +- */Library/Frameworks) +- MDIR="`dirname "${enableval}"`" +- MDIR="`dirname "${MDIR}"`" +- FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications" +- +- if test "${prefix}" = "NONE"; then +- # User hasn't specified the +- # --prefix option, but wants to install +- # the framework in a non-default location, +- # ensure that the compatibility links get +- # installed relative to that prefix as well +- # instead of in /usr/local. +- FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" +- fi +- ;; ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources + +- *) +- FRAMEWORKINSTALLAPPSPREFIX="/Applications" +- ;; +- esac ++ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" + +- prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION ++ ;; ++ watchOS) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" + +- # Add files for Mac specific code to the list of output +- # files: +- ac_config_files="$ac_config_files Mac/Makefile" ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=watchOS/Resources + +- ac_config_files="$ac_config_files Mac/PythonLauncher/Makefile" ++ ac_config_files="$ac_config_files watchOS/Resources/Info.plist" + +- ac_config_files="$ac_config_files Mac/Resources/framework/Info.plist" ++ ;; ++ *) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools" ++ FRAMEWORKPYTHONW="frameworkpythonw" ++ FRAMEWORKINSTALLAPPSPREFIX="/Applications" ++ INSTALLTARGETS="commoninstall bininstall maninstall" + +- ac_config_files="$ac_config_files Mac/Resources/app/Info.plist" ++ if test "x${prefix}" = "xNONE" ; then ++ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" + +- esac ++ else ++ FRAMEWORKUNIXTOOLSPREFIX="${prefix}" ++ fi ++ ++ case "${enableval}" in ++ /System*) ++ FRAMEWORKINSTALLAPPSPREFIX="/Applications" ++ if test "${prefix}" = "NONE" ; then ++ # See below ++ FRAMEWORKUNIXTOOLSPREFIX="/usr" ++ fi ++ ;; ++ ++ /Library*) ++ FRAMEWORKINSTALLAPPSPREFIX="/Applications" ++ ;; ++ ++ */Library/Frameworks) ++ MDIR="`dirname "${enableval}"`" ++ MDIR="`dirname "${MDIR}"`" ++ FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications" ++ ++ if test "${prefix}" = "NONE"; then ++ # User hasn't specified the ++ # --prefix option, but wants to install ++ # the framework in a non-default location, ++ # ensure that the compatibility links get ++ # installed relative to that prefix as well ++ # instead of in /usr/local. ++ FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" ++ fi ++ ;; ++ ++ *) ++ FRAMEWORKINSTALLAPPSPREFIX="/Applications" ++ ;; ++ esac ++ ++ prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=$(prefix) ++ RESSRCDIR=Mac/Resources/framework ++ ++ # Add files for Mac specific code to the list of output ++ # files: ++ ac_config_files="$ac_config_files Mac/Makefile" ++ ++ ac_config_files="$ac_config_files Mac/PythonLauncher/Makefile" ++ ++ ac_config_files="$ac_config_files Mac/Resources/app/Info.plist" ++ ++ ac_config_files="$ac_config_files Mac/Resources/framework/Info.plist" ++ ++ ;; ++ esac ++ esac + + else $as_nop + +@@ -4194,6 +4331,8 @@ + PYTHONFRAMEWORKDIR=no-framework + PYTHONFRAMEWORKPREFIX= + PYTHONFRAMEWORKINSTALLDIR= ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX= ++ RESSRCDIR= + FRAMEWORKINSTALLFIRST= + FRAMEWORKINSTALLLAST= + FRAMEWORKALTINSTALLFIRST= +@@ -4223,79 +4362,11 @@ + + + +-printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h + + +-# Set name for machine-dependent library files + +-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5 +-printf %s "checking MACHDEP... " >&6; } +-if test -z "$MACHDEP" +-then +- # avoid using uname for cross builds +- if test "$cross_compiling" = yes; then +- # ac_sys_system and ac_sys_release are used for setting +- # a lot of different things including 'define_xopen_source' +- # in the case statement below. +- case "$host" in +- *-*-linux-android*) +- ac_sys_system=Linux-android +- ;; +- *-*-linux*) +- ac_sys_system=Linux +- ;; +- *-*-cygwin*) +- ac_sys_system=Cygwin +- ;; +- *-*-vxworks*) +- ac_sys_system=VxWorks +- ;; +- *-*-emscripten) +- ac_sys_system=Emscripten +- ;; +- *-*-wasi) +- ac_sys_system=WASI +- ;; +- *) +- # for now, limit cross builds to known configurations +- MACHDEP="unknown" +- as_fn_error $? "cross build not supported for $host" "$LINENO" 5 +- esac +- ac_sys_release= +- else +- ac_sys_system=`uname -s` +- if test "$ac_sys_system" = "AIX" \ +- -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then +- ac_sys_release=`uname -v` +- else +- ac_sys_release=`uname -r` +- fi +- fi +- ac_md_system=`echo $ac_sys_system | +- tr -d '/ ' | tr '[A-Z]' '[a-z]'` +- ac_md_release=`echo $ac_sys_release | +- tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'` +- MACHDEP="$ac_md_system$ac_md_release" +- +- case $MACHDEP in +- aix*) MACHDEP="aix";; +- linux*) MACHDEP="linux";; +- cygwin*) MACHDEP="cygwin";; +- darwin*) MACHDEP="darwin";; +- '') MACHDEP="unknown";; +- esac +- +- if test "$ac_sys_system" = "SunOS"; then +- # For Solaris, there isn't an OS version specific macro defined +- # in most compilers, so we define one here. +- SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\(0-9\)$!.0\1!g' | tr -d '.'` +- +-printf "%s\n" "#define Py_SUNOS_VERSION $SUNOS_VERSION" >>confdefs.h ++printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h + +- fi +-fi +-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5 +-printf "%s\n" "\"$MACHDEP\"" >&6; } + + + if test "$cross_compiling" = yes; then +@@ -4303,27 +4374,102 @@ *-*-linux*) case "$host_cpu" in arm*) @@ -1732,63 +2247,69 @@ index c87f518382..69685cd25a 100755 + _host_ident= + ;; + *-apple-ios*-simulator) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ IOS_DEPLOYMENT_TARGET=${_host_os:3} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-iphonesimulator-arm64 ++ _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-iphonesimulator-$host_cpu ++ _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-$host_cpu + esac + ;; + *-apple-ios*) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ IOS_DEPLOYMENT_TARGET=${_host_os:3} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-iphoneos-arm64 ++ _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-iphoneos-$host_cpu ++ _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-$host_cpu + esac + ;; + *-apple-tvos*-simulator) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-appletvsimulator-arm64 ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvsimulator-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-appletvsimulator-$host_cpu ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvsimulator-$host_cpu + esac + ;; + *-apple-tvos*) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-appletvos-arm64 ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvos-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-appletvos-$host_cpu ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvos-$host_cpu + esac + ;; + *-apple-watchos*-simulator) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-watchsimualtor-arm64 ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchsimulator-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-watchsimualtor-$host_cpu ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchsimulator-$host_cpu + esac + ;; + *-apple-watchos*) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-watchosos-arm64_32 ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchosos-arm64_32 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-watchosos-$host_cpu ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchosos-$host_cpu + esac + ;; + *-apple-*) @@ -1818,7 +2339,7 @@ index c87f518382..69685cd25a 100755 fi # Some systems cannot stand _XOPEN_SOURCE being defined at all; they -@@ -4390,6 +4468,13 @@ +@@ -4390,6 +4536,13 @@ define_xopen_source=no;; Darwin/[12][0-9].*) define_xopen_source=no;; @@ -1832,7 +2353,40 @@ index c87f518382..69685cd25a 100755 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -6746,6 +6831,12 @@ +@@ -4484,6 +4637,32 @@ + ;; + 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}" ++ ++ ;; #( ++ tvOS) : ++ ++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=9.0} ++ as_fn_append CFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" ++ as_fn_append LDFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" ++ ++ ;; #( ++ watchOS) : ++ ++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} ++ as_fn_append CFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" ++ as_fn_append LDFLAGS " -mwatchos-version-min=${WATCHOS_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. +@@ -6746,6 +6925,12 @@ case $ac_sys_system in #( Darwin*) : MULTIARCH="" ;; #( @@ -1845,17 +2399,16 @@ index c87f518382..69685cd25a 100755 FreeBSD*) : MULTIARCH="" ;; #( *) : -@@ -6753,9 +6844,6 @@ +@@ -6753,8 +6938,6 @@ ;; esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5 -printf "%s\n" "$MULTIARCH" >&6; } -- + if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then if test x$PLATFORM_TRIPLET != x$MULTIARCH; then - as_fn_error $? "internal configure error for the platform triplet, please file a bug report" "$LINENO" 5 -@@ -6764,6 +6852,16 @@ +@@ -6764,6 +6947,16 @@ MULTIARCH=$PLATFORM_TRIPLET fi @@ -1872,7 +2425,7 @@ index c87f518382..69685cd25a 100755 if test x$MULTIARCH != x; then MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" -@@ -6807,8 +6905,14 @@ +@@ -6807,6 +7000,12 @@ PY_SUPPORT_TIER=3 ;; #( x86_64-*-freebsd*/clang) : PY_SUPPORT_TIER=3 ;; #( @@ -1883,12 +2436,58 @@ index c87f518382..69685cd25a 100755 + aarch64-apple-ios*/clang) : + PY_SUPPORT_TIER=3 ;; #( *) : -- PY_SUPPORT_TIER=0 -+ PY_SUPPORT_TIER=0 + PY_SUPPORT_TIER=0 ;; - esac - -@@ -12515,6 +12619,7 @@ +@@ -7257,17 +7456,23 @@ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDLIBRARY" >&5 + printf %s "checking LDLIBRARY... " >&6; } + +-# MacOSX framework builds need more magic. LDLIBRARY is the dynamic ++# iOS/MacOSX framework builds need more magic. LDLIBRARY is the dynamic + # library that we build, but we do not want to link against it (we + # 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 +- LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' +- RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}} ++ case $ac_sys_system in ++ iOS|tvOS|watchOS) ++ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; ++ *) ++ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; ++ esac + BLDLIBRARY='' ++ RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}} + else + BLDLIBRARY='$(LDLIBRARY)' + fi +@@ -7317,12 +7522,16 @@ + ;; + Darwin*) + LDLIBRARY='libpython$(LDVERSION).dylib' +- BLDLIBRARY='-L. -lpython$(LDVERSION)' +- RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} ++ BLDLIBRARY='-L. -lpython$(LDVERSION)' ++ RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} ++ ;; ++ iOS|tvOS|watchOS) ++ LDLIBRARY='libpython$(LDVERSION).dylib' ++ BLDLIBRARY='-L. -lpython$(LDVERSION)' + ;; + AIX*) +- LDLIBRARY='libpython$(LDVERSION).so' +- RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}} ++ LDLIBRARY='libpython$(LDVERSION).so' ++ RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}} + ;; + + esac +@@ -12515,6 +12724,7 @@ esac ;; CYGWIN*) SHLIB_SUFFIX=.dll;; @@ -1896,17 +2495,44 @@ index c87f518382..69685cd25a 100755 *) SHLIB_SUFFIX=.so;; esac fi -@@ -12597,6 +12702,9 @@ +@@ -12597,6 +12807,11 @@ BLDSHARED="$LDSHARED" fi ;; + iOS/*|tvOS/*|watchOS/*) -+ LDSHARED='$(CC) -dynamiclib -undefined dynamic_lookup' -+ LDCXXSHARED='$(CXX) -dynamiclib -undefined dynamic_lookup';; ++ LDSHARED='$(CC) -dynamiclib -F . -framework Python' ++ LDCXXSHARED='$(CXX) -dynamiclib -F . -framework Python' ++ BLDSHARED="$LDSHARED" ++ ;; Emscripten|WASI) LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; -@@ -14138,6 +14246,10 @@ +@@ -12750,6 +12965,24 @@ + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED";; ++ iOS/*|tvOS/*|watchOS/*) ++ 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";; +@@ -14138,6 +14371,10 @@ ctypes_malloc_closure=yes ;; #( @@ -1917,7 +2543,7 @@ index c87f518382..69685cd25a 100755 sunos5) : as_fn_append LIBFFI_LIBS " -mimpure-text" ;; #( -@@ -23651,7 +23763,7 @@ +@@ -23651,7 +23888,7 @@ printf "%s\n" "$ABIFLAGS" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking SOABI" >&5 printf %s "checking SOABI... " >&6; } @@ -1926,7 +2552,7 @@ index c87f518382..69685cd25a 100755 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SOABI" >&5 printf "%s\n" "$SOABI" >&6; } -@@ -23660,7 +23772,7 @@ +@@ -23660,7 +23897,7 @@ if test "$Py_DEBUG" = 'true'; then # Similar to SOABI but remove "d" flag from ABIFLAGS @@ -1935,7 +2561,7 @@ index c87f518382..69685cd25a 100755 printf "%s\n" "#define ALT_SOABI \"${ALT_SOABI}\"" >>confdefs.h -@@ -27949,6 +28061,28 @@ +@@ -27949,6 +28186,28 @@ ;; #( Darwin) : ;; #( @@ -1964,19 +2590,49 @@ index c87f518382..69685cd25a 100755 CYGWIN*) : -@@ -32186,4 +32320,3 @@ - CPython core team, see https://peps.python.org/pep-0011/ for more information. - " >&2;} - fi -- +@@ -31528,10 +31787,13 @@ + do + case $ac_config_target in + "pyconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS pyconfig.h" ;; ++ "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; ++ "tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES tvOS/Resources/Info.plist" ;; ++ "watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES watchOS/Resources/Info.plist" ;; + "Mac/Makefile") CONFIG_FILES="$CONFIG_FILES Mac/Makefile" ;; + "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" ;; ++ "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/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 cd69f0ede5..135036bf67 100644 +index cd69f0ede5..a96ca3a3c7 100644 --- a/configure.ac +++ b/configure.ac -@@ -553,6 +553,15 @@ - *-*-cygwin*) - ac_sys_system=Cygwin - ;; +@@ -310,6 +310,83 @@ + AC_MSG_ERROR([pkg-config is required])] + fi + ++# Set name for machine-dependent library files ++AC_ARG_VAR([MACHDEP], [name for machine-dependent library files]) ++AC_MSG_CHECKING([MACHDEP]) ++if test -z "$MACHDEP" ++then ++ # avoid using uname for cross builds ++ if test "$cross_compiling" = yes; then ++ # ac_sys_system and ac_sys_release are used for setting ++ # a lot of different things including 'define_xopen_source' ++ # in the case statement below. ++ case "$host" in ++ *-*-linux-android*) ++ ac_sys_system=Linux-android ++ ;; ++ *-*-linux*) ++ ac_sys_system=Linux ++ ;; ++ *-*-cygwin*) ++ ac_sys_system=Cygwin ++ ;; + *-apple-ios*) + ac_sys_system=iOS + ;; @@ -1986,10 +2642,322 @@ index cd69f0ede5..135036bf67 100644 + *-apple-watchos*) + ac_sys_system=watchOS + ;; - *-*-vxworks*) - ac_sys_system=VxWorks - ;; -@@ -607,27 +616,96 @@ ++ *-*-vxworks*) ++ ac_sys_system=VxWorks ++ ;; ++ *-*-emscripten) ++ ac_sys_system=Emscripten ++ ;; ++ *-*-wasi) ++ ac_sys_system=WASI ++ ;; ++ *) ++ # for now, limit cross builds to known configurations ++ MACHDEP="unknown" ++ AC_MSG_ERROR([cross build not supported for $host]) ++ esac ++ ac_sys_release= ++ else ++ ac_sys_system=`uname -s` ++ if test "$ac_sys_system" = "AIX" \ ++ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then ++ ac_sys_release=`uname -v` ++ else ++ ac_sys_release=`uname -r` ++ fi ++ fi ++ ac_md_system=`echo $ac_sys_system | ++ tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'` ++ ac_md_release=`echo $ac_sys_release | ++ tr -d '[/ ]' | sed 's/^[[A-Z]]\.//' | sed 's/\..*//'` ++ MACHDEP="$ac_md_system$ac_md_release" ++ ++ case $MACHDEP in ++ aix*) MACHDEP="aix";; ++ linux*) MACHDEP="linux";; ++ cygwin*) MACHDEP="cygwin";; ++ darwin*) MACHDEP="darwin";; ++ '') MACHDEP="unknown";; ++ esac ++ ++ if test "$ac_sys_system" = "SunOS"; then ++ # For Solaris, there isn't an OS version specific macro defined ++ # in most compilers, so we define one here. ++ SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\([0-9]\)$!.0\1!g' | tr -d '.'` ++ AC_DEFINE_UNQUOTED([Py_SUNOS_VERSION], [$SUNOS_VERSION], ++ [The version of SunOS/Solaris as reported by `uname -r' without the dot.]) ++ fi ++fi ++AC_MSG_RESULT(["$MACHDEP"]) ++ + AC_MSG_CHECKING([for --enable-universalsdk]) + AC_ARG_ENABLE([universalsdk], + AS_HELP_STRING([--enable-universalsdk@<:@=SDKDIR@:>@], +@@ -427,11 +504,15 @@ + PYTHONFRAMEWORKDIR=no-framework + PYTHONFRAMEWORKPREFIX= + PYTHONFRAMEWORKINSTALLDIR= ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX= ++ RESSRCDIR= + FRAMEWORKINSTALLFIRST= + FRAMEWORKINSTALLLAST= + FRAMEWORKALTINSTALLFIRST= + FRAMEWORKALTINSTALLLAST= + FRAMEWORKPYTHONW= ++ INSTALLTARGETS="commoninstall bininstall maninstall" ++ + if test "x${prefix}" = "xNONE"; then + FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" + else +@@ -444,66 +525,112 @@ + PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR + FRAMEWORKINSTALLFIRST="frameworkinstallstructure" + FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure " +- FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools" +- FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools" +- FRAMEWORKPYTHONW="frameworkpythonw" +- FRAMEWORKINSTALLAPPSPREFIX="/Applications" + +- if test "x${prefix}" = "xNONE" ; then +- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" ++ case $ac_sys_system in #( ++ iOS) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" + +- else +- FRAMEWORKUNIXTOOLSPREFIX="${prefix}" +- fi ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=iOS/Resources + +- case "${enableval}" in +- /System*) +- FRAMEWORKINSTALLAPPSPREFIX="/Applications" +- if test "${prefix}" = "NONE" ; then +- # See below +- FRAMEWORKUNIXTOOLSPREFIX="/usr" +- fi +- ;; ++ AC_CONFIG_FILES([iOS/Resources/Info.plist]) ++ ;; ++ tvOS) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" + +- /Library*) +- FRAMEWORKINSTALLAPPSPREFIX="/Applications" +- ;; ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources + +- */Library/Frameworks) +- MDIR="`dirname "${enableval}"`" +- MDIR="`dirname "${MDIR}"`" +- FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications" +- +- if test "${prefix}" = "NONE"; then +- # User hasn't specified the +- # --prefix option, but wants to install +- # the framework in a non-default location, +- # ensure that the compatibility links get +- # installed relative to that prefix as well +- # instead of in /usr/local. +- FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" +- fi +- ;; ++ AC_CONFIG_FILES([tvOS/Resources/Info.plist]) ++ ;; ++ watchOS) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" + +- *) +- FRAMEWORKINSTALLAPPSPREFIX="/Applications" +- ;; +- esac ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=watchOS/Resources + +- prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION ++ AC_CONFIG_FILES([watchOS/Resources/Info.plist]) ++ ;; ++ *) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools" ++ FRAMEWORKPYTHONW="frameworkpythonw" ++ FRAMEWORKINSTALLAPPSPREFIX="/Applications" ++ INSTALLTARGETS="commoninstall bininstall maninstall" + +- # Add files for Mac specific code to the list of output +- # files: +- AC_CONFIG_FILES([Mac/Makefile]) +- AC_CONFIG_FILES([Mac/PythonLauncher/Makefile]) +- AC_CONFIG_FILES([Mac/Resources/framework/Info.plist]) +- AC_CONFIG_FILES([Mac/Resources/app/Info.plist]) +- esac ++ if test "x${prefix}" = "xNONE" ; then ++ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" ++ ++ else ++ FRAMEWORKUNIXTOOLSPREFIX="${prefix}" ++ fi ++ ++ case "${enableval}" in ++ /System*) ++ FRAMEWORKINSTALLAPPSPREFIX="/Applications" ++ if test "${prefix}" = "NONE" ; then ++ # See below ++ FRAMEWORKUNIXTOOLSPREFIX="/usr" ++ fi ++ ;; ++ ++ /Library*) ++ FRAMEWORKINSTALLAPPSPREFIX="/Applications" ++ ;; ++ ++ */Library/Frameworks) ++ MDIR="`dirname "${enableval}"`" ++ MDIR="`dirname "${MDIR}"`" ++ FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications" ++ ++ if test "${prefix}" = "NONE"; then ++ # User hasn't specified the ++ # --prefix option, but wants to install ++ # the framework in a non-default location, ++ # ensure that the compatibility links get ++ # installed relative to that prefix as well ++ # instead of in /usr/local. ++ FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" ++ fi ++ ;; ++ ++ *) ++ FRAMEWORKINSTALLAPPSPREFIX="/Applications" ++ ;; ++ esac ++ ++ prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=$(prefix) ++ RESSRCDIR=Mac/Resources/framework ++ ++ # Add files for Mac specific code to the list of output ++ # files: ++ AC_CONFIG_FILES([Mac/Makefile]) ++ AC_CONFIG_FILES([Mac/PythonLauncher/Makefile]) ++ AC_CONFIG_FILES([Mac/Resources/app/Info.plist]) ++ AC_CONFIG_FILES([Mac/Resources/framework/Info.plist]) ++ ;; ++ esac ++ esac + ],[ + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework + PYTHONFRAMEWORKPREFIX= + PYTHONFRAMEWORKINSTALLDIR= ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX= ++ RESSRCDIR= + FRAMEWORKINSTALLFIRST= + FRAMEWORKINSTALLLAST= + FRAMEWORKALTINSTALLFIRST= +@@ -522,6 +649,8 @@ + AC_SUBST([PYTHONFRAMEWORKDIR]) + AC_SUBST([PYTHONFRAMEWORKPREFIX]) + AC_SUBST([PYTHONFRAMEWORKINSTALLDIR]) ++AC_SUBST([PYTHONFRAMEWORKINSTALLNAMEPREFIX]) ++AC_SUBST([RESSRCDIR]) + AC_SUBST([FRAMEWORKINSTALLFIRST]) + AC_SUBST([FRAMEWORKINSTALLLAST]) + AC_SUBST([FRAMEWORKALTINSTALLFIRST]) +@@ -529,105 +658,113 @@ + AC_SUBST([FRAMEWORKPYTHONW]) + AC_SUBST([FRAMEWORKUNIXTOOLSPREFIX]) + AC_SUBST([FRAMEWORKINSTALLAPPSPREFIX]) ++AC_SUBST([INSTALLTARGETS]) + + AC_DEFINE_UNQUOTED([_PYTHONFRAMEWORK], ["${PYTHONFRAMEWORK}"], + [framework name]) + +-# Set name for machine-dependent library files +-AC_ARG_VAR([MACHDEP], [name for machine-dependent library files]) +-AC_MSG_CHECKING([MACHDEP]) +-if test -z "$MACHDEP" +-then +- # avoid using uname for cross builds +- if test "$cross_compiling" = yes; then +- # ac_sys_system and ac_sys_release are used for setting +- # a lot of different things including 'define_xopen_source' +- # in the case statement below. +- case "$host" in +- *-*-linux-android*) +- ac_sys_system=Linux-android +- ;; +- *-*-linux*) +- ac_sys_system=Linux +- ;; +- *-*-cygwin*) +- ac_sys_system=Cygwin +- ;; +- *-*-vxworks*) +- ac_sys_system=VxWorks +- ;; +- *-*-emscripten) +- ac_sys_system=Emscripten +- ;; +- *-*-wasi) +- ac_sys_system=WASI +- ;; +- *) +- # for now, limit cross builds to known configurations +- MACHDEP="unknown" +- AC_MSG_ERROR([cross build not supported for $host]) +- esac +- ac_sys_release= +- else +- ac_sys_system=`uname -s` +- if test "$ac_sys_system" = "AIX" \ +- -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then +- ac_sys_release=`uname -v` +- else +- ac_sys_release=`uname -r` +- fi +- fi +- ac_md_system=`echo $ac_sys_system | +- tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'` +- ac_md_release=`echo $ac_sys_release | +- tr -d '[/ ]' | sed 's/^[[A-Z]]\.//' | sed 's/\..*//'` +- MACHDEP="$ac_md_system$ac_md_release" +- +- case $MACHDEP in +- aix*) MACHDEP="aix";; +- linux*) MACHDEP="linux";; +- cygwin*) MACHDEP="cygwin";; +- darwin*) MACHDEP="darwin";; +- '') MACHDEP="unknown";; +- esac +- +- if test "$ac_sys_system" = "SunOS"; then +- # For Solaris, there isn't an OS version specific macro defined +- # in most compilers, so we define one here. +- SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\([0-9]\)$!.0\1!g' | tr -d '.'` +- AC_DEFINE_UNQUOTED([Py_SUNOS_VERSION], [$SUNOS_VERSION], +- [The version of SunOS/Solaris as reported by `uname -r' without the dot.]) +- fi +-fi +-AC_MSG_RESULT(["$MACHDEP"]) +- + AC_SUBST([_PYTHON_HOST_PLATFORM]) + if test "$cross_compiling" = yes; then + case "$host" in *-*-linux*) case "$host_cpu" in arm*) @@ -2006,63 +2974,69 @@ index cd69f0ede5..135036bf67 100644 + _host_ident= + ;; + *-apple-ios*-simulator) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ IOS_DEPLOYMENT_TARGET=${_host_os:3} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-iphonesimulator-arm64 ++ _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-iphonesimulator-$host_cpu ++ _host_ident=${IOS_DEPLOYMENT_TARGET}-iphonesimulator-$host_cpu + esac + ;; + *-apple-ios*) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ IOS_DEPLOYMENT_TARGET=${_host_os:3} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-iphoneos-arm64 ++ _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-iphoneos-$host_cpu ++ _host_ident=${IOS_DEPLOYMENT_TARGET}-iphoneos-$host_cpu + esac + ;; + *-apple-tvos*-simulator) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-appletvsimulator-arm64 ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvsimulator-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-appletvsimulator-$host_cpu ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvsimulator-$host_cpu + esac + ;; + *-apple-tvos*) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-appletvos-arm64 ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvos-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-appletvos-$host_cpu ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvos-$host_cpu + esac + ;; + *-apple-watchos*-simulator) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-watchsimualtor-arm64 ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchsimulator-arm64 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-watchsimualtor-$host_cpu ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchsimulator-$host_cpu + esac + ;; + *-apple-watchos*) -+ _host_os_min_version=`echo $host | cut -d '-' -f3` ++ _host_os=`echo $host | cut -d '-' -f3` ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} + case "$host_cpu" in + aarch64) -+ _host_ident=${_host_os_min_version:3}-watchosos-arm64_32 ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchosos-arm64_32 + ;; + *) -+ _host_ident=${_host_os_min_version:3}-watchosos-$host_cpu ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchosos-$host_cpu + esac + ;; + *-apple-*) @@ -2092,7 +3066,7 @@ index cd69f0ede5..135036bf67 100644 fi # Some systems cannot stand _XOPEN_SOURCE being defined at all; they -@@ -693,6 +771,13 @@ +@@ -693,6 +830,13 @@ define_xopen_source=no;; Darwin/@<:@[12]@:>@@<:@0-9@:>@.*) define_xopen_source=no;; @@ -2106,7 +3080,34 @@ index cd69f0ede5..135036bf67 100644 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -941,11 +1026,13 @@ +@@ -783,6 +927,26 @@ + ], + ) + ++dnl iOS/tvOS/watchOS need to enforce the deployment target. ++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]) ++ ],[tvOS], [ ++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=9.0} ++ AS_VAR_APPEND([CFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) ++ AS_VAR_APPEND([LDFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) ++ AC_SUBST([TVOS_DEPLOYMENT_TARGET]) ++ ],[watchOS], [ ++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} ++ AS_VAR_APPEND([CFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) ++ AS_VAR_APPEND([LDFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) ++ AC_SUBST([WATCHOS_DEPLOYMENT_TARGET]) ++ ], ++) ++ + if test "$ac_sys_system" = "Darwin" + then + dnl look for SDKROOT +@@ -941,11 +1105,13 @@ AC_MSG_CHECKING([for multiarch]) AS_CASE([$ac_sys_system], [Darwin*], [MULTIARCH=""], @@ -2121,7 +3122,7 @@ index cd69f0ede5..135036bf67 100644 if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then if test x$PLATFORM_TRIPLET != x$MULTIARCH; then -@@ -955,6 +1042,12 @@ +@@ -955,6 +1121,12 @@ MULTIARCH=$PLATFORM_TRIPLET fi AC_SUBST([PLATFORM_TRIPLET]) @@ -2134,7 +3135,7 @@ index cd69f0ede5..135036bf67 100644 if test x$MULTIARCH != x; then MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" -@@ -985,6 +1078,9 @@ +@@ -985,6 +1157,9 @@ [wasm32-unknown-emscripten/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly Emscripten [wasm32-unknown-wasi/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly System Interface [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64 @@ -2144,7 +3145,56 @@ index cd69f0ede5..135036bf67 100644 [PY_SUPPORT_TIER=0] ) -@@ -3085,6 +3181,7 @@ +@@ -1298,17 +1473,23 @@ + + AC_MSG_CHECKING([LDLIBRARY]) + +-# MacOSX framework builds need more magic. LDLIBRARY is the dynamic ++# iOS/MacOSX framework builds need more magic. LDLIBRARY is the dynamic + # library that we build, but we do not want to link against it (we + # 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 +- LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' +- RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}} ++ case $ac_sys_system in ++ iOS|tvOS|watchOS) ++ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; ++ *) ++ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; ++ esac + BLDLIBRARY='' ++ RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}} + else + BLDLIBRARY='$(LDLIBRARY)' + fi +@@ -1357,12 +1538,16 @@ + ;; + Darwin*) + LDLIBRARY='libpython$(LDVERSION).dylib' +- BLDLIBRARY='-L. -lpython$(LDVERSION)' +- RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} ++ BLDLIBRARY='-L. -lpython$(LDVERSION)' ++ RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} ++ ;; ++ iOS|tvOS|watchOS) ++ LDLIBRARY='libpython$(LDVERSION).dylib' ++ BLDLIBRARY='-L. -lpython$(LDVERSION)' + ;; + AIX*) +- LDLIBRARY='libpython$(LDVERSION).so' +- RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}} ++ LDLIBRARY='libpython$(LDVERSION).so' ++ RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}} + ;; + + esac +@@ -3085,6 +3270,7 @@ esac ;; CYGWIN*) SHLIB_SUFFIX=.dll;; @@ -2152,17 +3202,44 @@ index cd69f0ede5..135036bf67 100644 *) SHLIB_SUFFIX=.so;; esac fi -@@ -3165,6 +3262,9 @@ +@@ -3165,6 +3351,11 @@ BLDSHARED="$LDSHARED" fi ;; + iOS/*|tvOS/*|watchOS/*) -+ LDSHARED='$(CC) -dynamiclib -undefined dynamic_lookup' -+ LDCXXSHARED='$(CXX) -dynamiclib -undefined dynamic_lookup';; ++ LDSHARED='$(CC) -dynamiclib -F . -framework Python' ++ LDCXXSHARED='$(CXX) -dynamiclib -F . -framework Python' ++ BLDSHARED="$LDSHARED" ++ ;; Emscripten|WASI) LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; -@@ -3682,6 +3782,9 @@ +@@ -3309,6 +3500,24 @@ + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED";; ++ iOS/*|tvOS/*|watchOS/*) ++ 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";; +@@ -3682,6 +3891,9 @@ dnl when do we need USING_APPLE_OS_LIBFFI? ctypes_malloc_closure=yes ], @@ -2172,7 +3249,7 @@ index cd69f0ede5..135036bf67 100644 [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])] ) AS_VAR_IF([ctypes_malloc_closure], [yes], [ -@@ -5714,7 +5817,7 @@ +@@ -5714,7 +5926,7 @@ AC_MSG_CHECKING([ABIFLAGS]) AC_MSG_RESULT([$ABIFLAGS]) AC_MSG_CHECKING([SOABI]) @@ -2181,7 +3258,7 @@ index cd69f0ede5..135036bf67 100644 AC_MSG_RESULT([$SOABI]) # Release build, debug build (Py_DEBUG), and trace refs build (Py_TRACE_REFS) -@@ -5722,7 +5825,7 @@ +@@ -5722,7 +5934,7 @@ if test "$Py_DEBUG" = 'true'; then # Similar to SOABI but remove "d" flag from ABIFLAGS AC_SUBST([ALT_SOABI]) @@ -2190,7 +3267,7 @@ index cd69f0ede5..135036bf67 100644 AC_DEFINE_UNQUOTED([ALT_SOABI], ["${ALT_SOABI}"], [Alternative SOABI used in debug build to load C extensions built in release mode]) fi -@@ -7068,6 +7171,29 @@ +@@ -7068,6 +7280,29 @@ [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])], dnl The _scproxy module is available on macOS [Darwin], [], @@ -2220,3 +3297,581 @@ index cd69f0ede5..135036bf67 100644 [CYGWIN*], [PY_STDLIB_MOD_SET_NA([_scproxy])], [QNX*], [PY_STDLIB_MOD_SET_NA([_scproxy])], [FreeBSD*], [PY_STDLIB_MOD_SET_NA([_scproxy])], +--- /dev/null ++++ b/iOS/README.rst +@@ -0,0 +1,107 @@ ++==================== ++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. ++ ++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, on the ++most recently released macOS. ++ ++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 and using 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. ++ ++iOS can also support different CPU architectures within each ABI. At present, ++there is only a single support ed 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. ++ ++How do I build Python for iOS? ++------------------------------ ++ ++The Python build system will build a ``Python.framework`` that supports a ++*single* ABI with a *single* architecture. If you want to use Python in an iOS ++project, you need to: ++ ++1. Produce multiple ``Python.framework`` builds, one for each ABI and architecture; ++2. Merge the binaries for each architecture on a given ABI into a single "fat" binary; ++3. Merge the "fat" frameworks for each ABI into a single XCframework. ++ ++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 commands for building ++Python for iOS will look somethign like:: ++ ++ $ ./configure \ ++ --enable-framework=/path/to/install \ ++ --host=aarch64-apple-ios \ ++ --build=aarch64-apple-darwin \ ++ --with-build-python=/path/to/python.exe ++ $ make ++ $ make install ++ ++In this invocation: ++ ++* ``/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. ++ ++Using a framework-based Python on iOS ++===================================== +--- /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-2023 Python Software Foundation. ++ CFBundleSignature ++ ???? ++ CFBundleVersion ++ %VERSION% ++ CFBundleSupportedPlatforms ++ ++ iPhoneOS ++ ++ MinimumOSVersion ++ @IOS_DEPLOYMENT_TARGET@ ++ ++ +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk iphoneos ar $@ +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-clang +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk iphoneos clang -target arm64-apple-ios $@ +--- /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 $@ +--- /dev/null ++++ b/iOS/Resources/bin/arm64-apple-ios-simulator-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk iphonesimulator ar $@ +--- /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 $@ +--- /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 $@ +--- /dev/null ++++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk iphonesimulator ar $@ +--- /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 $@ +--- /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 $@ +--- /dev/null ++++ b/tvOS/README.rst +@@ -0,0 +1,108 @@ ++===================== ++Python on tvOS README ++===================== ++ ++:Authors: ++ Russell Keith-Magee (2023-11) ++ ++This document provides a quick overview of some tvOS specific features in the ++Python distribution. ++ ++Compilers for building on tvOS ++============================== ++ ++Building for tvOS requires the use of Apple's Xcode tooling. It is strongly ++recommended that you use the most recent stable release of Xcode, on the ++most recently released macOS. ++ ++tvOS 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 and using Python on tvOS ++================================= ++ ++ABIs and Architectures ++---------------------- ++ ++tvOS apps can be deployed on physical devices, and on the tvOS simulator. ++Although the API used on these devices is identical, the ABI is different - you ++need to link against different libraries for an tvOS device build ++(``appletvos``) or an tvOS simulator build (``appletvsimulator``). 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. ++ ++tvOS can also support different CPU architectures within each ABI. At present, ++there is only a single support ed 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. ++ ++How do I build Python for tvOS? ++------------------------------- ++ ++The Python build system will build a ``Python.framework`` that supports a ++*single* ABI with a *single* architecture. If you want to use Python in an tvOS ++project, you need to: ++ ++1. Produce multiple ``Python.framework`` builds, one for each ABI and architecture; ++2. Merge the binaries for each architecture on a given ABI into a single "fat" binary; ++3. Merge the "fat" frameworks for each ABI into a single XCframework. ++ ++tvOS 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 commands for building ++Python for tvOS will look somethign like:: ++ ++ $ ./configure \ ++ --enable-framework=/path/to/install \ ++ --host=aarch64-apple-tvos \ ++ --build=aarch64-apple-darwin \ ++ --with-build-python=/path/to/python.exe ++ $ make ++ $ make install ++ ++In this invocation: ++ ++* ``/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-tvos`` for ARM64 tvOS devices. ++ - ``aarch64-apple-tvos-simulator`` for the tvOS simulator running on Apple ++ Silicon devices. ++ - ``x86_64-apple-tvos-simulator`` for the tvOS 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 tvOS 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. ++ ++Using a framework-based Python on tvOS ++====================================== +--- /dev/null ++++ b/tvOS/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-2023 Python Software Foundation. ++ CFBundleSignature ++ ???? ++ CFBundleVersion ++ %VERSION% ++ CFBundleSupportedPlatforms ++ ++ tvOS ++ ++ MinimumOSVersion ++ @TVOS_DEPLOYMENT_TARGET@ ++ ++ +--- /dev/null ++++ b/tvOS/Resources/bin/arm64-apple-tvos-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvos ar $@ +--- /dev/null ++++ b/tvOS/Resources/bin/arm64-apple-tvos-clang +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvos clang -target arm64-apple-tvos $@ +--- /dev/null ++++ b/tvOS/Resources/bin/arm64-apple-tvos-cpp +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvos clang -target arm64-apple-tvos -E $@ +--- /dev/null ++++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvsimulator ar $@ +--- /dev/null ++++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-clang +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvsimulator clang -target arm64-apple-tvos-simulator $@ +--- /dev/null ++++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-cpp +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvsimulator clang -target arm64-apple-tvos-simulator -E $@ +--- /dev/null ++++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvsimulator ar $@ +--- /dev/null ++++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-clang +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvsimulator clang -target x86_64-apple-tvos-simulator $@ +--- /dev/null ++++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-cpp +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk appletvsimulator clang -target x86_64-apple-tvos-simulator -E $@ +--- /dev/null ++++ b/watchOS/README.rst +@@ -0,0 +1,108 @@ ++======================== ++Python on watchOS README ++======================== ++ ++:Authors: ++ Russell Keith-Magee (2023-11) ++ ++This document provides a quick overview of some watchOS specific features in the ++Python distribution. ++ ++Compilers for building on watchOS ++================================= ++ ++Building for watchOS requires the use of Apple's Xcode tooling. It is strongly ++recommended that you use the most recent stable release of Xcode, on the ++most recently released macOS. ++ ++watchOS 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 and using Python on watchOS ++==================================== ++ ++ABIs and Architectures ++---------------------- ++ ++watchOS apps can be deployed on physical devices, and on the watchOS simulator. ++Although the API used on these devices is identical, the ABI is different - you ++need to link against different libraries for an watchOS device build ++(``watchos``) or an watchOS simulator build (``watchsimulator``). 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. ++ ++watchOS can also support different CPU architectures within each ABI. At present, ++there is only a single support ed 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. ++ ++How do I build Python for watchOS? ++------------------------------- ++ ++The Python build system will build a ``Python.framework`` that supports a ++*single* ABI with a *single* architecture. If you want to use Python in an watchOS ++project, you need to: ++ ++1. Produce multiple ``Python.framework`` builds, one for each ABI and architecture; ++2. Merge the binaries for each architecture on a given ABI into a single "fat" binary; ++3. Merge the "fat" frameworks for each ABI into a single XCframework. ++ ++watchOS 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 commands for building ++Python for watchOS will look somethign like:: ++ ++ $ ./configure \ ++ --enable-framework=/path/to/install \ ++ --host=aarch64-apple-watchos \ ++ --build=aarch64-apple-darwin \ ++ --with-build-python=/path/to/python.exe ++ $ make ++ $ make install ++ ++In this invocation: ++ ++* ``/path/to/install`` is the location where the final Python.framework will be ++ output. ++ ++* ``--host`` is the architecture and ABI that you want to build, in GNU compiler ++ triple format. This will be one of: ++ ++ - ``arm64_32-apple-watchos`` for ARM64-32 watchOS devices. ++ - ``aarch64-apple-watchos-simulator`` for the watchOS simulator running on Apple ++ Silicon devices. ++ - ``x86_64-apple-watchos-simulator`` for the watchOS 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 watchOS 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. ++ ++Using a framework-based Python on watchOS ++====================================== +--- /dev/null ++++ b/watchOS/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-2023 Python Software Foundation. ++ CFBundleSignature ++ ???? ++ CFBundleVersion ++ %VERSION% ++ CFBundleSupportedPlatforms ++ ++ watchOS ++ ++ MinimumOSVersion ++ @WATCHOS_DEPLOYMENT_TARGET@ ++ ++ +--- /dev/null ++++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchsimulator ar $@ +--- /dev/null ++++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-clang +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchsimulator clang -target arm64-apple-watchos-simulator $@ +--- /dev/null ++++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-cpp +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchsimulator clang -target arm64-apple-watchos-simulator -E $@ +--- /dev/null ++++ b/watchOS/Resources/bin/arm64_32-apple-watchos-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchos ar $@ +--- /dev/null ++++ b/watchOS/Resources/bin/arm64_32-apple-watchos-clang +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchos clang -target arm64_32-apple-watchos $@ +--- /dev/null ++++ b/watchOS/Resources/bin/arm64_32-apple-watchos-cpp +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchos clang -target arm64_32-apple-watchos -E $@ +--- /dev/null ++++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-ar +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchsimulator ar $@ +--- /dev/null ++++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-clang +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchsimulator clang -target x86_64-apple-watchos-simulator $@ +--- /dev/null ++++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-cpp +@@ -0,0 +1,2 @@ ++#!/bin/bash ++xcrun --sdk watchsimulator clang -target x86_64-apple-watchos-simulator -E $@ diff --git a/patch/Python/release.common.exclude b/patch/Python/release.common.exclude deleted file mode 100644 index bec2b86..0000000 --- a/patch/Python/release.common.exclude +++ /dev/null @@ -1,26 +0,0 @@ -# This is a list of support package path patterns that we exclude -# from all Python-Apple-support tarballs. -# It is used by `tar -X` during the Makefile build. -# Remove standard library test suites. -python-stdlib/ctypes/test -python-stdlib/distutils/tests -python-stdlib/lib2to3/tests -python-stdlib/sqlite3/test -python-stdlib/test -# Remove config-* directory, which is used for compiling C extension modules. -python-stdlib/config-* -# Remove ensurepip. If user code needs pip, it can add it to -python-stdlib/ensurepip -# Remove libraries supporting IDLE. We don't need to ship an IDE -python-stdlib/idlelib -# Remove Tcl/Tk GUI code. We don't build against Tcl/Tk at the moment, so this -# will not work. -python-stdlib/tkinter -python-stdlib/turtle.py -python-stdlib/turtledemo -# Remove site-packages directory. The template unpacks user code and -# dependencies to a different path. -python-stdlib/site-packages -# Remove pyc files. These take up space, but since most stdlib modules are -# never imported by user code, they mostly have no value. -*/__pycache__ diff --git a/patch/Python/release.iOS.exclude b/patch/Python/release.iOS.exclude index fb1f841..f1d0f75 100644 --- a/patch/Python/release.iOS.exclude +++ b/patch/Python/release.iOS.exclude @@ -1,10 +1,6 @@ # This is a list of support package path patterns that we exclude -# from iOS Python-Apple-support tarballs. +# from all Python-Apple-support tarballs. # It is used by `tar -X` during the Makefile build. -# -# Remove command-line curses toolkit. -python-stdlib/curses -# Remove the testing binary modules -python-stdlib/lib-dynload/*_test*.dylib -python-stdlib/lib-dynload/_xx*.dylib -python-stdlib/lib-dynload/xx*.dylib +# Remove pyc files. These take up space, but since most stdlib modules are +# never imported by user code, they mostly have no value. +*/__pycache__ diff --git a/patch/Python/release.tvOS.exclude b/patch/Python/release.tvOS.exclude index e9ff418..f1d0f75 100644 --- a/patch/Python/release.tvOS.exclude +++ b/patch/Python/release.tvOS.exclude @@ -1,10 +1,6 @@ # This is a list of support package path patterns that we exclude -# from tvOS Python-Apple-support tarballs. +# from all Python-Apple-support tarballs. # It is used by `tar -X` during the Makefile build. -# -# Remove command-line curses toolkit. -python-stdlib/curses -# Remove the testing binary modules -python-stdlib/lib-dynload/*_test*.dylib -python-stdlib/lib-dynload/_xx*.dylib -python-stdlib/lib-dynload/xx*.dylib +# Remove pyc files. These take up space, but since most stdlib modules are +# never imported by user code, they mostly have no value. +*/__pycache__ diff --git a/patch/Python/release.watchOS.exclude b/patch/Python/release.watchOS.exclude index c8b1d66..f1d0f75 100644 --- a/patch/Python/release.watchOS.exclude +++ b/patch/Python/release.watchOS.exclude @@ -1,10 +1,6 @@ # This is a list of support package path patterns that we exclude -# from watchOS Python-Apple-support tarballs. +# from all Python-Apple-support tarballs. # It is used by `tar -X` during the Makefile build. -# -# Remove command-line curses toolkit. -python-stdlib/curses -# Remove the testing binary modules -python-stdlib/lib-dynload/*_test*.dylib -python-stdlib/lib-dynload/_xx*.dylib -python-stdlib/lib-dynload/xx*.dylib +# Remove pyc files. These take up space, but since most stdlib modules are +# never imported by user code, they mostly have no value. +*/__pycache__ diff --git a/patch/make-macho-standalone.py b/patch/make-macho-standalone.py new file mode 100644 index 0000000..975765d --- /dev/null +++ b/patch/make-macho-standalone.py @@ -0,0 +1,10 @@ +import os +import sys +from macholib.MachOStandalone import MachOStandalone + + +if __name__ == "__main__": + MachOStandalone( + sys.argv[1], + os.path.abspath(f"{sys.argv[1]}/") + ).run(contents="@rpath/") From b8fcfd7cca2237163ba9c7f2b64648058b693a6b Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 14 Nov 2023 14:13:09 +0800 Subject: [PATCH 03/13] Update docs describing the framework build and usage. --- README.rst | 39 ++++++++++++++++++---------------- USAGE.md | 61 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 62 insertions(+), 38 deletions(-) diff --git a/README.rst b/README.rst index dff2a8a..ae9d2ae 100644 --- a/README.rst +++ b/README.rst @@ -19,24 +19,24 @@ pre-requisites, and packaging them as static libraries that can be incorporated XCode project. The binary modules in the Python standard library are statically compiled, but are distributed as objects that can be dynamically loaded at runtime. -It exposes *almost* all the modules in the Python standard library except for: +The macOS package is a re-bundling of the official macOS binary, modified so that +it is relocatable. -* ``dbm.gnu`` -* ``tkinter`` -* ``readline`` -* ``nis`` (Deprecated by PEP594) -* ``ossaudiodev`` (Deprecated by PEP594) -* ``spwd`` (Deprecated by PEP594) - -The following standard library modules are available on macOS, but not the other -Apple platforms: +The iOS, tvOS and watchOS packages are compiled by this project. They expose +*almost* all the modules in the Python standard library except for: * ``curses`` +* ``dbm.gnu`` * ``grp`` * ``multiprocessing`` +* ``nis`` (Deprecated by PEP594) +* ``ossaudiodev`` (Deprecated by PEP594) * ``posixshmem`` * ``posixsubprocess`` +* ``readline`` +* ``spwd`` (Deprecated by PEP594) * ``syslog`` +* ``tkinter`` The binaries support x86_64 and arm64 for macOS; arm64 for iOS and appleTV devices; and arm64_32 for watchOS. It also supports device simulators on both @@ -93,10 +93,6 @@ Each support package contains: * ``VERSIONS``, a text file describing the specific versions of code used to build the support package; -* ``bin``, a folder containing shell aliases for the compilers that are needed - to build packages. This is required because Xcode uses the ``xcrun`` alias to - dynamically generate the name of binaries, but a lot of C tooling expects that ``CC`` - will not contain spaces. * ``platform-site``, a folder that contains site customization scripts that can be used to make your local Python install look like it is an on-device install for each of the underlying target architectures supported by the platform. This is needed because when @@ -107,10 +103,17 @@ Each support package contains: return ``platform`` and ``sysconfig`` responses consistent with on-device behavior, which will cause ``pip`` to install platform-appropriate packages. * ``Python.xcframework``, a multi-architecture build of the Python runtime library -* ``python-stdlib``, the code and binary modules comprising the Python standard library. - On iOS, tvOS and watchOS, there are 2 copies of every binary module - one for physical - devices, and one for the simulator. The simulator binaries are "fat", containing code - for both x86_64 and arm64. + +On iOS/tvOS/watchOS, the ``Python.xcframework`` contains a +slice for each supported ABI (device and simulator). The folder containing the +slice can also be used as a ``PYTHONHOME``, as it contains a ``bin``, ``include`` +and ``lib`` directory. + +The ``bin`` folder does not contain Python executables (as they can't be +invoked). However, it *does* contain shell aliases for the compilers that are +needed to build packages. This is required because Xcode uses the ``xcrun`` +alias to dynamically generate the name of binaries, but a lot of C tooling +expects that ``CC`` will not contain spaces. For a detailed instructions on using the support package in your own project, see the `usage guide <./USAGE.md>`__ diff --git a/USAGE.md b/USAGE.md index 706fe05..cf507ba 100644 --- a/USAGE.md +++ b/USAGE.md @@ -23,31 +23,42 @@ To add this support package to your own project: 1. [Download a release tarball for your desired Python version and Apple platform](https://github.com/beeware/Python-Apple-support/releases) -2. Add the `python-stdlib` and `Python.xcframework` to your Xcode project. Both - the `python-stdlib` folder and the `Python.xcframework` should be members of - any target that needs to use Python. +2. Add `Python.xcframework` to your Xcode project. You can put it anywhere in your + project that you want; the following instructions assume it has been put in a + folder named "Support". 3. In Xcode, select the root node of the project tree, and select the target you want to build. 4. Select "General" -> "Frameworks, Libraries and Embedded Content", and ensure that `Python.xcframework` is on the list of frameworks. It should be marked - "Do not embed". + "Embed and sign". -5. Select "General" -> "Build Phases", and ensure that the `python-stdlib` folder - is listed in the "Copy Bundle Resources" step. +5. Select "General" -> "Build Settings", and set the following values: + - Linking - General: + - `@executable_path/Frameworks` + - Search paths: + - Framework Search paths: `"$(PROJECT_DIR)/Support"` + - Header Search paths: `"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers"` -6. If you're on iOS, Add a new "Run script" build phase named "Purge Python Binary - Modules for Non-Target Platforms". This script will purge any dynamic module for the - platform you are *not* targeting. The script should have the following content: +6. Add a new "Run script" build phase named "Install target specific Python + Modules". This script will install the standard library for your target. The + script should have the following content: ```bash +set -e + +mkdir -p "$CODESIGNING_FOLDER_PATH/python/lib" if [ "$EFFECTIVE_PLATFORM_NAME" = "-iphonesimulator" ]; then - echo "Purging Python modules for iOS Device" - find "$CODESIGNING_FOLDER_PATH/python-stdlib" -name "*.*-iphoneos.dylib" -exec rm -f "{}" \; + echo "Installing Python modules for iOS Simulator" + rsync -au --delete "$PROJECT_DIR/Support/Python.xcframework/iphonesimulator/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" + # Also install any user-provided modules + # rsync -au --delete "$PROJECT_DIR/Testbed/app_packages.iphonesimulator/" "$CODESIGNING_FOLDER_PATH/app_packages" else - echo "Purging Python modules for iOS Simulator" - find "$CODESIGNING_FOLDER_PATH" -name "*.*-iphonesimulator.dylib" -exec rm -f "{}" \; + echo "Installing Python modules for iOS Device" + rsync -au --delete "$PROJECT_DIR/Support/Python.xcframework/iphoneos/lib/" "$CODESIGNING_FOLDER_PATH/python/lib" + # Also install any user-provided modules + # rsync -au --delete "$PROJECT_DIR/Testbed/app_packages.iphoneos/" "$CODESIGNING_FOLDER_PATH/app_packages" fi ``` @@ -69,13 +80,12 @@ install_dylib () { 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 (hopefully unique) name of the framework, constructed by replacing path - # separators in the relative name with underscores. - FRAMEWORK_NAME=$(echo $RELATIVE_DYLIB | cut -d "." -f 1 | tr "/" "_"); + # 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.$FRAMEWORK_NAME | tr "_" "-") + FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr "_" "-") # The name of the framework folder. - FRAMEWORK_FOLDER="Frameworks/$FRAMEWORK_NAME.framework" + FRAMEWORK_FOLDER="Frameworks/$FULL_MODULE_NAME.framework" # If the framework folder doesn't exist, create it. if [ ! -d "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" ]; then @@ -91,10 +101,16 @@ install_dylib () { mv "$FULL_DYLIB" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" } +# Make sure to update the Python version version reference here echo "Install standard library dylibs..." -find "$CODESIGNING_FOLDER_PATH/python-stdlib/lib-dynload" -name "*.dylib" | while read FULL_DYLIB; do - install_dylib python-stdlib/lib-dynload "$FULL_DYLIB" +find "$CODESIGNING_FOLDER_PATH/python/lib/python3.13/lib-dynload" -name "*.dylib" | while read FULL_DYLIB; do + install_dylib python/lib/python3.13/lib-dynload "$FULL_DYLIB" done +# Also install any user-provided dynamic modules; e.g., +# echo "Install app package dylibs..." +# find "$CODESIGNING_FOLDER_PATH/app_packages" -name "*.dylib" | while read FULL_DYLIB; do +# install_dylib app_packages "$FULL_DYLIB" +# done # Clean up dylib template rm -f "$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist" @@ -103,6 +119,11 @@ echo "Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SI 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 "{}" \; ``` + Make sure that you update these scripts to update the references to the + Python version, and include any user-provided code that you want to bundle. + If you use the ``rsync`` approach above, user-provided code should *not* be + included as part of the "Copy Bundle Resources" step. + You'll also need to add a file named `dylib-Info-template.plist` to your Xcode project, and make it a member of any target that needs to use Python. The template should have the following content: From 323aa5f800c3b471dfafb638cd3411e287f96901 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 20 Nov 2023 14:35:01 +0800 Subject: [PATCH 04/13] Update syntax for github outputs. --- .github/workflows/publish.yaml | 16 +++++-------- .github/workflows/release.yaml | 42 +++++++++++++--------------------- 2 files changed, 22 insertions(+), 36 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 6cb84f8..79654ee 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -20,17 +20,13 @@ jobs: env: TAG_NAME: ${{ github.ref }} run: | - export TAG=$(basename $TAG_NAME) - echo "TAG=${TAG}" - export PYTHON_VER="${TAG%-*}" - export BUILD_NUMBER="${TAG#*-}" + TAG=$(basename $TAG_NAME) + PYTHON_VER="${TAG%-*}" + BUILD_NUMBER="${TAG#*-}" - echo "PYTHON_VER=${PYTHON_VER}" - echo "BUILD_NUMBER=${BUILD_NUMBER}" - - echo "TAG=${TAG}" >> ${GITHUB_OUTPUT} - echo "PYTHON_VER=${PYTHON_VER}" >> ${GITHUB_OUTPUT} - echo "BUILD_NUMBER=${BUILD_NUMBER}" >> ${GITHUB_OUTPUT} + echo "TAG=${TAG}" | tee -a ${GITHUB_OUTPUT} + echo "PYTHON_VER=${PYTHON_VER}" | tee -a ${GITHUB_OUTPUT} + echo "BUILD_NUMBER=${BUILD_NUMBER}" | tee -a ${GITHUB_OUTPUT} - name: Update Release Asset to S3 env: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 3444886..4bb2368 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -30,17 +30,13 @@ jobs: env: TAG_NAME: ${{ github.ref }} run: | - export TAG=$(basename $TAG_NAME) - echo "TAG=${TAG}" - export PYTHON_VER="${TAG%-*}" - export BUILD_NUMBER="${TAG#*-}" + TAG=$(basename $TAG_NAME) + echo "TAG=${TAG}" | tee -a ${GITHUB_OUTPUT} - echo "PYTHON_VER=${PYTHON_VER}" - echo "BUILD_NUMBER=${BUILD_NUMBER}" - - echo "TAG=${TAG}" >> ${GITHUB_OUTPUT} - echo "PYTHON_VER=${PYTHON_VER}" >> ${GITHUB_OUTPUT} - echo "BUILD_NUMBER=${BUILD_NUMBER}" >> ${GITHUB_OUTPUT} + PYTHON_VER="${TAG%-*}" + BUILD_NUMBER="${TAG#*-}" + echo "PYTHON_VER=${PYTHON_VER}" | tee -a ${GITHUB_OUTPUT} + echo "BUILD_NUMBER=${BUILD_NUMBER}" | tee -a ${GITHUB_OUTPUT} - name: Set up Python uses: actions/setup-python@v4.7.1 @@ -55,23 +51,17 @@ jobs: - name: Extract version details id: version-details run: | - export PYTHON_VERSION=$(grep "Python version:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 3) - export BZIP2_VERSION=$(grep "BZip2:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 2) - export XZ_VERSION=$(grep "XZ:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 2) - export OPENSSL_VERSION=$(grep "OpenSSL:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 2) - export LIBFFI_VERSION=$(grep "libFFI:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 2) - - echo "PYTHON_VERSION=${PYTHON_VERSION}" - echo "BZIP2_VERSION=${BZIP2_VERSION}" - echo "XZ_VERSION=${XZ_VERSION}" - echo "OPENSSL_VERSION=${OPENSSL_VERSION}" - echo "LIBFFI_VERSION=${LIBFFI_VERSION}" + PYTHON_VERSION=$(grep "Python version:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 3) + BZIP2_VERSION=$(grep "BZip2:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 2) + XZ_VERSION=$(grep "XZ:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 2) + OPENSSL_VERSION=$(grep "OpenSSL:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 2) + LIBFFI_VERSION=$(grep "libFFI:" support/${{ steps.build-vars.outputs.PYTHON_VER }}/${{ matrix.target }}/VERSIONS | cut -d " " -f 2) - echo "PYTHON_VERSION=${PYTHON_VERSION}" >> ${GITHUB_OUTPUT} - echo "BZIP2_VERSION=${BZIP2_VERSION}" >> ${GITHUB_OUTPUT} - echo "XZ_VERSION=${XZ_VERSION}" >> ${GITHUB_OUTPUT} - echo "OPENSSL_VERSION=${OPENSSL_VERSION}" >> ${GITHUB_OUTPUT} - echo "LIBFFI_VERSION=${LIBFFI_VERSION}" >> ${GITHUB_OUTPUT} + echo "PYTHON_VERSION=${PYTHON_VERSION}" | tee -a ${GITHUB_OUTPUT} + echo "BZIP2_VERSION=${BZIP2_VERSION}" | tee -a ${GITHUB_OUTPUT} + echo "XZ_VERSION=${XZ_VERSION}" | tee -a ${GITHUB_OUTPUT} + echo "OPENSSL_VERSION=${OPENSSL_VERSION}" | tee -a ${GITHUB_OUTPUT} + echo "LIBFFI_VERSION=${LIBFFI_VERSION}" | tee -a ${GITHUB_OUTPUT} - name: Upload build artifact uses: actions/upload-artifact@v3.1.3 From 252d48be0c03f23c3e8050a4c5a672516922be68 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 20 Nov 2023 14:38:22 +0800 Subject: [PATCH 05/13] Add a makefile target to extract the Makefile config. --- Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 40d637e..58c87c4 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ PATH=/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin all: $(OS_LIST) .PHONY: \ - all clean distclean update-patch vars \ + all clean distclean update-patch vars config \ $(foreach os,$(OS_LIST),$(os) clean-$(os) dev-clean-$(os) vars-$(os)) \ $(foreach os,$(OS_LIST),$(foreach sdk,$$(sort $$(basename $$(TARGETS-$(os)))),$(sdk) vars-$(sdk))) $(foreach os,$(OS_LIST),$(foreach target,$$(TARGETS-$(os)),$(target) vars-$(target))) @@ -642,6 +642,15 @@ vars: $(foreach os,$(OS_LIST),vars-$(os)) @echo "HOST_PYTHON: $(HOST_PYTHON)" @echo +config: + @echo "PYTHON_VERSION=$(PYTHON_VERSION)" + @echo "PYTHON_VER=$(PYTHON_VER)" + @echo "BUILD_NUMBER=$(BUILD_NUMBER)" + @echo "BZIP2_VERSION=$(BZIP2_VERSION)" + @echo "XZ_VERSION=$(XZ_VERSION)" + @echo "OPENSSL_VERSION=$(OPENSSL_VERSION)" + @echo "LIBFFI_VERSION=$(LIBFFI_VERSION)" + # Expand cross-platform build and clean targets for each output product clean: $(foreach os,$(OS_LIST),clean-$(os)) dev-clean: $(foreach os,$(OS_LIST),dev-clean-$(os)) From 6ec85e76b2313c3fa595c50874988688d0942a07 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 20 Nov 2023 14:38:31 +0800 Subject: [PATCH 06/13] Add a CI workflow. --- .github/workflows/ci.yaml | 64 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/workflows/ci.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..7859373 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,64 @@ +name: CI +on: + pull_request: + +env: + FORCE_COLOR: "1" + +defaults: + run: + shell: bash + +# Cancel active CI runs for a PR before starting another run +concurrency: + group: ${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: macOS-latest + strategy: + matrix: + # target: ['macOS', 'iOS', 'tvOS', 'watchOS'] + target: ['macOS'] + include: + - briefcase-run-args: + + # - target: iOS + # briefcase-run-args: ' -d "iPhone SE (3rd generation)"' + steps: + - uses: actions/checkout@v4 + + - name: Extract config variables + id: config-vars + run: | + PYTHON_VER=$(make config | grep "PYTHON_VER=" | cut -d "=" -f 2) + echo "PYTHON_VER=${PYTHON_VER}" | tee -a ${GITHUB_OUTPUT} + + - name: Set up Python + uses: actions/setup-python@v4.7.1 + with: + # Appending -dev ensures that we can always build the dev release. + # It's a no-op for versions that have been published. + python-version: ${{ steps.config-vars.outputs.PYTHON_VER }}-dev + + - name: Build ${{ matrix.target }} + run: | + # Do the build for the requested target. + make ${{ matrix.target }} + + - uses: actions/checkout@v4 + with: + repository: beeware/Python-support-testbed + path: Python-support-testbed + ref: py3.13-support + + - name: Install dependencies + run: | + # Use the development version of Briefcase + python -m pip install git+https://github.com/beeware/briefcase.git + + - name: Run support testbed check + working-directory: Python-support-testbed + # TODO - remove the template_branch option. + run: briefcase run ${{ matrix.target }} Xcode --test ${{ matrix.briefcase-run-args }} -C support_package=\'../dist/Python-${{ steps.config-vars.outputs.PYTHON_VER }}-${{ matrix.target }}-support.custom.tar.gz\' -C template_branch=\'framework-lib\' From 55cf5f90d00497718e0be87fd18ef7eac040d821 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 21 Nov 2023 10:13:58 +0800 Subject: [PATCH 07/13] Add other platforms into CI check. --- .github/workflows/ci.yaml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7859373..242c348 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -18,14 +18,20 @@ jobs: build: runs-on: macOS-latest strategy: + fail-fast: false matrix: - # target: ['macOS', 'iOS', 'tvOS', 'watchOS'] - target: ['macOS'] + target: ['macOS', 'iOS', 'tvOS', 'watchOS'] include: - briefcase-run-args: + - run-tests: false + + - target: macOS + run-tests: true + + - target: iOS + briefcase-run-args: ' -d "iPhone SE (3rd generation)"' + run-tests: true - # - target: iOS - # briefcase-run-args: ' -d "iPhone SE (3rd generation)"' steps: - uses: actions/checkout@v4 @@ -48,17 +54,20 @@ jobs: make ${{ matrix.target }} - uses: actions/checkout@v4 + if: matrix.run-tests with: repository: beeware/Python-support-testbed path: Python-support-testbed ref: py3.13-support - name: Install dependencies + if: matrix.run-tests run: | # Use the development version of Briefcase python -m pip install git+https://github.com/beeware/briefcase.git - name: Run support testbed check + if: matrix.run-tests working-directory: Python-support-testbed # TODO - remove the template_branch option. run: briefcase run ${{ matrix.target }} Xcode --test ${{ matrix.briefcase-run-args }} -C support_package=\'../dist/Python-${{ steps.config-vars.outputs.PYTHON_VER }}-${{ matrix.target }}-support.custom.tar.gz\' -C template_branch=\'framework-lib\' From fd7051e0b8dfa8d47c0869a08517a87ff141a794 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 21 Nov 2023 11:19:05 +0800 Subject: [PATCH 08/13] Upload build artefacts as part of CI. --- .github/workflows/ci.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 242c348..38dce29 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -53,11 +53,18 @@ jobs: # Do the build for the requested target. make ${{ matrix.target }} + - name: Upload build artefacts + uses: actions/upload-artifact@v3.1.3 + with: + name: Python-${{ steps.config-vars.outputs.PYTHON_VER }}-${{ matrix.target }}-support.custom.tar.gz + path: dist/Python-${{ steps.config-vars.outputs.PYTHON_VER }}-${{ matrix.target }}-support.custom.tar.gz + - uses: actions/checkout@v4 if: matrix.run-tests with: repository: beeware/Python-support-testbed path: Python-support-testbed + # TODO - remove the py3.13 reference option. ref: py3.13-support - name: Install dependencies From 6d6abb0395226caba883ac9601f5fd445f2698b7 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 22 Nov 2023 12:51:22 +0800 Subject: [PATCH 09/13] Add a non-executable stub binary for crossenv detection purposes. --- Makefile | 13 +++++++++---- patch/Python/Python.patch | 8 ++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 58c87c4..aa4d33c 100644 --- a/Makefile +++ b/Makefile @@ -20,10 +20,7 @@ PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+") PYTHON_VER=$(basename $(PYTHON_VERSION)) # The binary releases of dependencies, published at: -# macOS: -# https://github.com/beeware/cpython-macOS-source-deps/releases -# iOS, tvOS, watchOS: -# https://github.com/beeware/cpython-apple-source-deps/releases +# https://github.com/beeware/cpython-apple-source-deps/releases BZIP2_VERSION=1.0.8-1 XZ_VERSION=5.4.4-1 OPENSSL_VERSION=3.0.12-1 @@ -417,13 +414,21 @@ $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h: $$(PYTHON_LIB-$(sdk)) @echo ">>> Build Python fat headers for the $(sdk) SDK" # Copy binary helpers from the first target in the $(sdk) SDK cp -r $$(PYTHON_BIN-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_BIN-$(sdk)) + + # Create a non-executable stub binary python3 + echo "#!/bin/bash\necho Can\\'t run $(sdk) binary\nexit 1" > $$(PYTHON_BIN-$(sdk))/python$(PYTHON_VER) + chmod 755 $$(PYTHON_BIN-$(sdk))/python$(PYTHON_VER) + # Copy headers as-is from the first target in the $(sdk) SDK cp -r $$(PYTHON_INCLUDE-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_INCLUDE-$(sdk)) + # Link the PYTHONHOME version of the headers mkdir -p $$(PYTHON_INSTALL-$(sdk))/include ln -si ../Python.framework/Headers $$(PYTHON_INSTALL-$(sdk))/include/python$(PYTHON_VER) + # Add the individual headers from each target in an arch-specific name $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_INCLUDE-$$(target))/pyconfig.h $$(PYTHON_INCLUDE-$(sdk))/pyconfig-$$(ARCH-$$(target)).h; ) + # Copy the cross-target header from the patch folder cp $(PROJECT_DIR)/patch/Python/pyconfig-$(os).h $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index cd30184..bf95e9e 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -1842,7 +1842,7 @@ index d74fb6deac..09ebc4287c 100755 # Blank kernel with real OS is always fine. ;; diff --git a/configure b/configure -index c87f518382..45f021d1b1 100755 +index c87f518382..ad0cd39350 100755 --- a/configure +++ b/configure @@ -963,10 +963,13 @@ @@ -2121,7 +2121,7 @@ index c87f518382..45f021d1b1 100755 + esac + + prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX=$(prefix) ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=${prefix} + RESSRCDIR=Mac/Resources/framework + + # Add files for Mac specific code to the list of output @@ -2606,7 +2606,7 @@ index c87f518382..45f021d1b1 100755 "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 cd69f0ede5..a96ca3a3c7 100644 +index cd69f0ede5..9306e1270b 100644 --- a/configure.ac +++ b/configure.ac @@ -310,6 +310,83 @@ @@ -2847,7 +2847,7 @@ index cd69f0ede5..a96ca3a3c7 100644 + esac + + prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX=$(prefix) ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX=${prefix} + RESSRCDIR=Mac/Resources/framework + + # Add files for Mac specific code to the list of output From c0cc33365aa04e1fe88ec2246accf7b42562a490 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 4 Dec 2023 14:18:08 +0800 Subject: [PATCH 10/13] Updated patch with version that passes CPython CI. --- Makefile | 5 +- patch/Python/Python.patch | 2649 ++++++++++++++++++++++++++----- patch/Python/pyconfig-iOS.h | 7 - patch/Python/pyconfig-tvOS.h | 7 - patch/Python/pyconfig-watchOS.h | 11 - patch/Python/test.exclude | 7 - 6 files changed, 2254 insertions(+), 432 deletions(-) delete mode 100644 patch/Python/pyconfig-iOS.h delete mode 100644 patch/Python/pyconfig-tvOS.h delete mode 100644 patch/Python/pyconfig-watchOS.h delete mode 100644 patch/Python/test.exclude diff --git a/Makefile b/Makefile index aa4d33c..59bea0a 100644 --- a/Makefile +++ b/Makefile @@ -429,8 +429,9 @@ $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h: $$(PYTHON_LIB-$(sdk)) # Add the individual headers from each target in an arch-specific name $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_INCLUDE-$$(target))/pyconfig.h $$(PYTHON_INCLUDE-$(sdk))/pyconfig-$$(ARCH-$$(target)).h; ) - # Copy the cross-target header from the patch folder - cp $(PROJECT_DIR)/patch/Python/pyconfig-$(os).h $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h + # Copy the cross-target header from the source folder of the first target in the $(sdk) SDK + cp $$(PYTHON_SRCDIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/$(os)/Resources/pyconfig.h $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h + $$(PYTHON_STDLIB-$(sdk))/LICENSE.TXT: $$(PYTHON_LIB-$(sdk)) $$(PYTHON_FRAMEWORK-$(sdk))/Info.plist $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h @echo ">>> Build Python stdlib for the $(sdk) SDK" diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index bf95e9e..24f7d21 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -19,43 +19,53 @@ index 6dd7d8d7ca..836c8a3fcf 100644 /* register() is useless on Windows, because only SIGSEGV, SIGABRT and --- /dev/null +++ b/Lib/_ios_support.py -@@ -0,0 +1,36 @@ -+from ctypes import cdll, c_void_p, c_char_p -+from ctypes import util +@@ -0,0 +1,46 @@ ++try: ++ from ctypes import cdll, c_void_p, c_char_p ++ from ctypes import util ++except ImportError: ++ # ctypes is an optional module. If it's not present, we're limited in what ++ # we can tell about the system, but we don't want to prevent the platform ++ # module from working. ++ cdll = None + + +def get_platform_ios(): -+ objc = cdll.LoadLibrary(util.find_library(b'objc')) ++ if cdll: ++ objc = cdll.LoadLibrary(util.find_library(b'objc')) + -+ objc.objc_getClass.restype = c_void_p -+ objc.objc_getClass.argtypes = [c_char_p] -+ objc.objc_msgSend.restype = c_void_p -+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p] -+ objc.sel_registerName.restype = c_void_p -+ objc.sel_registerName.argtypes = [c_char_p] ++ objc.objc_getClass.restype = c_void_p ++ objc.objc_getClass.argtypes = [c_char_p] ++ objc.objc_msgSend.restype = c_void_p ++ objc.objc_msgSend.argtypes = [c_void_p, c_void_p] ++ objc.sel_registerName.restype = c_void_p ++ objc.sel_registerName.argtypes = [c_char_p] + -+ UIDevice = c_void_p(objc.objc_getClass(b'UIDevice')) -+ SEL_currentDevice = c_void_p(objc.sel_registerName(b'currentDevice')) -+ device = c_void_p(objc.objc_msgSend(UIDevice, SEL_currentDevice)) ++ UIDevice = c_void_p(objc.objc_getClass(b'UIDevice')) ++ SEL_currentDevice = c_void_p(objc.sel_registerName(b'currentDevice')) ++ device = c_void_p(objc.objc_msgSend(UIDevice, SEL_currentDevice)) + -+ SEL_systemVersion = c_void_p(objc.sel_registerName(b'systemVersion')) -+ systemVersion = c_void_p(objc.objc_msgSend(device, SEL_systemVersion)) ++ SEL_systemVersion = c_void_p(objc.sel_registerName(b'systemVersion')) ++ systemVersion = c_void_p(objc.objc_msgSend(device, SEL_systemVersion)) + -+ SEL_systemName = c_void_p(objc.sel_registerName(b'systemName')) -+ systemName = c_void_p(objc.objc_msgSend(device, SEL_systemName)) ++ SEL_systemName = c_void_p(objc.sel_registerName(b'systemName')) ++ systemName = c_void_p(objc.objc_msgSend(device, SEL_systemName)) + -+ SEL_model = c_void_p(objc.sel_registerName(b'model')) -+ systemModel = c_void_p(objc.objc_msgSend(device, SEL_model)) ++ SEL_model = c_void_p(objc.sel_registerName(b'model')) ++ systemModel = c_void_p(objc.objc_msgSend(device, SEL_model)) + -+ # UTF8String returns a const char*; -+ SEL_UTF8String = c_void_p(objc.sel_registerName(b'UTF8String')) -+ objc.objc_msgSend.restype = c_char_p ++ # UTF8String returns a const char*; ++ SEL_UTF8String = c_void_p(objc.sel_registerName(b'UTF8String')) ++ objc.objc_msgSend.restype = c_char_p + -+ system = objc.objc_msgSend(systemName, SEL_UTF8String).decode() -+ release = objc.objc_msgSend(systemVersion, SEL_UTF8String).decode() -+ model = objc.objc_msgSend(systemModel, SEL_UTF8String).decode() ++ system = objc.objc_msgSend(systemName, SEL_UTF8String).decode() ++ release = objc.objc_msgSend(systemVersion, SEL_UTF8String).decode() ++ model = objc.objc_msgSend(systemModel, SEL_UTF8String).decode() + -+ return system, release, model ++ return system, release, model ++ else: ++ # Return dummy values if we can't call system APIs. ++ return "iOS", "?", "iPhone" diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index 0c2510e161..5567080ba5 100644 --- a/Lib/ctypes/util.py @@ -70,7 +80,7 @@ index 0c2510e161..5567080ba5 100644 def find_library(name): possible = ['lib%s.dylib' % name, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py -index 0019897c94..0356d2ab5d 100644 +index 0019897c94..c11ead2b11 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -52,7 +52,7 @@ @@ -82,7 +92,7 @@ index 0019897c94..0356d2ab5d 100644 _CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY + _CASE_INSENSITIVE_PLATFORMS_STR_KEY) -@@ -1704,6 +1704,59 @@ +@@ -1704,6 +1704,65 @@ return f'FileFinder({self.path!r})' @@ -90,19 +100,20 @@ index 0019897c94..0356d2ab5d 100644 + """A loader for modules that have been packaged as Apple Frameworks for + compatibility with Apple's App Store policies. + -+ For compatibility with the App Store, *all* binary modules must be in .dylibs, -+ contained in a Framework, in the ``Frameworks`` folder of the packaged app. If -+ you're trying to run "from foo import _bar", and _bar is implemented with the binary -+ module "foo/_bar.abi3.dylib" (or any other .dylib extension), this loader will look -+ for "{sys.executable}/Frameworks/foo__bar.framework/_bar.abi3.dylib" (forming the -+ package name by taking the full path of the library, and replacing ``/`` with -+ ``_``). The app packaging tool is responsible for putting the library in this -+ location. -+ -+ However, the ``__file__`` attribute of the _bar module will report as the original -+ location inside the ``foo`` directory. This so that code that depends on walking -+ directory trees will continue to work as expected based on the *original* file -+ location. ++ For compatibility with the App Store, *all* binary modules must be .dylib ++ objects, contained in a Framework, stored in the ``Frameworks`` folder of ++ the packaged app. If you're trying to run "from foo import _bar", and _bar ++ is implemented with the binary module "foo/_bar.abi3.dylib" (or any other ++ .dylib extension), this loader will look for ++ "{sys.executable}/Frameworks/foo._bar.framework/_bar.abi3.dylib" (forming ++ the package name by taking the full path of the library, and replacing ``/`` ++ with ``.``). The app packaging tool is responsible for putting the library ++ in this location. ++ ++ However, the ``__file__`` attribute of the _bar module will report as the ++ original location inside the ``foo`` directory. This so that code that ++ depends on walking directory trees will continue to work as expected based ++ on the *original* file location. + """ + def __init__(self, fullname, dylib_file, path): + super().__init__(fullname, dylib_file) @@ -133,16 +144,21 @@ index 0019897c94..0356d2ab5d 100644 + for extension in EXTENSION_SUFFIXES: + dylib_file = _path_join(self.frameworks_path, f"{fullname}.framework", f"{name}{extension}") + _bootstrap._verbose_message('Looking for Apple Framework dylib {}', dylib_file) -+ if _path_isfile(dylib_file): -+ loader = AppleFrameworkLoader(fullname, dylib_file, path) -+ return _bootstrap.spec_from_loader(fullname, loader) ++ try: ++ dylib_exists = _path_isfile(dylib_file) ++ except ValueError: ++ pass ++ else: ++ if dylib_exists: ++ loader = AppleFrameworkLoader(fullname, dylib_file, path) ++ return _bootstrap.spec_from_loader(fullname, loader) + + return None + # Import setup ############################################################### def _fix_up_module(ns, name, pathname, cpathname=None): -@@ -1753,3 +1806,7 @@ +@@ -1753,3 +1812,7 @@ supported_loaders = _get_supported_file_loaders() sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)]) sys.meta_path.append(PathFinder) @@ -150,15 +166,27 @@ index 0019897c94..0356d2ab5d 100644 + frameworks_folder = _path_join(_path_split(sys.executable)[0], "Frameworks") + _bootstrap._verbose_message('Adding Apple Framework dylib finder at {}', frameworks_folder) + sys.meta_path.append(AppleFrameworkFinder(frameworks_folder)) +diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py +index d9a19a13f7..fbd30b159f 100644 +--- a/Lib/importlib/machinery.py ++++ b/Lib/importlib/machinery.py +@@ -12,6 +12,7 @@ + from ._bootstrap_external import SourceFileLoader + from ._bootstrap_external import SourcelessFileLoader + from ._bootstrap_external import ExtensionFileLoader ++from ._bootstrap_external import AppleFrameworkLoader + from ._bootstrap_external import NamespaceLoader + + diff --git a/Lib/platform.py b/Lib/platform.py -index 7bb222088d..0a5ed0361e 100755 +index 7bb222088d..b4db9749da 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -496,6 +496,26 @@ # If that also doesn't work return the default values return release, versioninfo, machine -+def iOS_ver(): ++def ios_ver(): + """Get iOS/tvOS version information, and return it as a + tuple (system, release, model). All tuple entries are strings. + """ @@ -221,7 +249,7 @@ index 7bb222088d..0a5ed0361e 100755 + # Normalize responses on Apple mobile platforms + if sys.platform in {'ios', 'tvos'}: -+ system, release, model = iOS_ver() ++ system, release, model = ios_ver() + + # On iOS/tvOS simulators, os.uname() reports the machine as something + # like "arm64" or "x86_64". @@ -241,7 +269,7 @@ index 7bb222088d..0a5ed0361e 100755 - system = 'macOS' - release = macos_release + if sys.platform in {'ios', 'tvos'}: -+ system, release, _ = iOS_ver() ++ system, release, _ = ios_ver() + else: + macos_release = mac_ver()[0] + if macos_release: @@ -484,8 +512,32 @@ index 21e8770ab3..67958d247c 100644 def requires_subprocess(): """Used for subprocess, os.spawn calls, fd inheritance""" +diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py +index 821a4b1ffd..517f7b57f4 100644 +--- a/Lib/test/support/os_helper.py ++++ b/Lib/test/support/os_helper.py +@@ -20,7 +20,7 @@ + + # TESTFN_UNICODE is a non-ascii filename + TESTFN_UNICODE = TESTFN_ASCII + "-\xe0\xf2\u0258\u0141\u011f" +-if sys.platform == 'darwin': ++if sys.platform in ('darwin', 'ios', 'tvos', 'watchos'): + # In Mac OS X's VFS API file names are, by definition, canonically + # decomposed Unicode, encoded using UTF-8. See QA1173: + # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html +@@ -46,8 +46,8 @@ + 'encoding (%s). Unicode filename tests may not be effective' + % (TESTFN_UNENCODABLE, sys.getfilesystemencoding())) + TESTFN_UNENCODABLE = None +-# macOS and Emscripten deny unencodable filenames (invalid utf-8) +-elif sys.platform not in {'darwin', 'emscripten', 'wasi'}: ++# Apple and Emscripten deny unencodable filenames (invalid utf-8) ++elif sys.platform not in {'darwin', 'ios', 'tvos', 'watchos', 'emscripten', 'wasi'}: + try: + # ascii and utf-8 cannot encode the byte 0xff + b'\xff'.decode(sys.getfilesystemencoding()) diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py -index b25c097573..7f5f26248f 100644 +index b25c097573..7491782c7f 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py @@ -33,6 +33,7 @@ @@ -496,144 +548,93 @@ index b25c097573..7f5f26248f 100644 from test.support import socket_helper from test.support import threading_helper from test.support import ALWAYS_EQ, LARGEST, SMALLEST -@@ -543,6 +544,7 @@ - self._basetest_create_connection(conn_fut) - - @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_unix_connection(self): - # Issue #20682: On Mac OS X Tiger, getsockname() returns a - # zero-length address for UNIX socket. -@@ -635,6 +637,7 @@ - self.assertEqual(cm.exception.reason, 'CERTIFICATE_VERIFY_FAILED') - - @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_ssl_connection(self): - with test_utils.run_test_server(use_ssl=True) as httpd: - create_connection = functools.partial( -@@ -646,6 +649,7 @@ - - @socket_helper.skip_unless_bind_unix_socket - @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_ssl_unix_connection(self): - # Issue #20682: On Mac OS X Tiger, getsockname() returns a - # zero-length address for UNIX socket. -@@ -927,6 +931,7 @@ - return server, path - - @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_unix_server(self): - proto = MyProto(loop=self.loop) - server, path = self._make_unix_server(lambda: proto) -@@ -955,6 +960,7 @@ - server.close() - - @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_unix_server_path_socket_error(self): - proto = MyProto(loop=self.loop) - sock = socket.socket() -@@ -1020,6 +1026,7 @@ - - @socket_helper.skip_unless_bind_unix_socket - @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_unix_server_ssl(self): - proto = MyProto(loop=self.loop) - server, path = self._make_ssl_unix_server( -@@ -1050,6 +1057,7 @@ - server.close() - - @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_server_ssl_verify_failed(self): - proto = MyProto(loop=self.loop) - server, host, port = self._make_ssl_server( -@@ -1080,6 +1088,7 @@ - - @socket_helper.skip_unless_bind_unix_socket - @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_unix_server_ssl_verify_failed(self): - proto = MyProto(loop=self.loop) - server, path = self._make_ssl_unix_server( -@@ -1140,6 +1149,7 @@ - - @socket_helper.skip_unless_bind_unix_socket - @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_create_unix_server_ssl_verified(self): - proto = MyProto(loop=self.loop) - server, path = self._make_ssl_unix_server( +@@ -1799,6 +1800,7 @@ + next(it) + + ++@support.requires_subprocess() + class SubprocessTestsMixin: + + def check_terminated(self, returncode): diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py -index 9c92e75886..013a414729 100644 +index 9c92e75886..65ee41dbd1 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -18,6 +18,7 @@ import asyncio from test.test_asyncio import utils as test_utils -+from test.support import is_apple_mobile ++from test.support import requires_subprocess def tearDownModule(): -@@ -61,6 +62,7 @@ - self._basetest_open_connection(conn_fut) - - @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_open_unix_connection(self): - with test_utils.run_test_unix_server() as httpd: - conn_fut = asyncio.open_unix_connection(httpd.address) -@@ -92,6 +94,7 @@ - - @socket_helper.skip_unless_bind_unix_socket - @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_open_unix_connection_no_loop_ssl(self): - with test_utils.run_test_unix_server(use_ssl=True) as httpd: - conn_fut = asyncio.open_unix_connection( -@@ -120,6 +123,7 @@ - self._basetest_open_connection_error(conn_fut) - - @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_open_unix_connection_error(self): - with test_utils.run_test_unix_server() as httpd: - conn_fut = asyncio.open_unix_connection(httpd.address) -@@ -638,6 +642,7 @@ - self.assertEqual(messages, []) - - @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_start_unix_server(self): - - class MyServer: -diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py -index d2c8cba6ac..a7bbe1d2b0 100644 ---- a/Lib/test/test_asyncio/test_unix_events.py -+++ b/Lib/test/test_asyncio/test_unix_events.py -@@ -18,6 +18,7 @@ - import warnings - +@@ -771,6 +772,7 @@ + self.assertEqual(msg2, b"hello world 2!\n") + + @unittest.skipIf(sys.platform == 'win32', "Don't have pipes") ++ @requires_subprocess() + def test_read_all_from_pipe_reader(self): + # See asyncio issue 168. This test is derived from the example + # subprocess_attach_read_pipe.py, but we configure the +diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py +index 179c8cb8cc..c8659f6ed6 100644 +--- a/Lib/test/test_asyncio/test_subprocess.py ++++ b/Lib/test/test_asyncio/test_subprocess.py +@@ -11,6 +11,7 @@ + from asyncio import subprocess + from test.test_asyncio import utils as test_utils from test import support +from test.support import is_apple_mobile from test.support import os_helper - from test.support import socket_helper - from test.support import wait_process -@@ -283,6 +284,7 @@ - @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), - 'UNIX Sockets are not supported') -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - class SelectorEventLoopUnixSocketTests(test_utils.TestCase): +@@ -47,6 +48,8 @@ + self._proc.pid = -1 + + ++@unittest.skipIf(is_apple_mobile, ++ f"{sys.platform} doesn't support subprocesses.") + class SubprocessTransportTests(test_utils.TestCase): def setUp(self): + super().setUp() +@@ -110,6 +113,8 @@ + transport.close() + + ++@unittest.skipIf(is_apple_mobile, ++ f"{sys.platform} doesn't support subprocesses.") + class SubprocessMixin: + + def test_stdin_stdout(self): +diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py +index d2c8cba6ac..c3795dede9 100644 +--- a/Lib/test/test_asyncio/test_unix_events.py ++++ b/Lib/test/test_asyncio/test_unix_events.py +@@ -1875,6 +1875,7 @@ + + + @unittest.skipUnless(hasattr(os, 'fork'), 'requires os.fork()') ++@support.requires_subprocess() + class TestFork(unittest.IsolatedAsyncioTestCase): + + async def test_fork_not_share_event_loop(self): +diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py +index 1b58882601..7ae237e6c1 100644 +--- a/Lib/test/test_cmd_line_script.py ++++ b/Lib/test/test_cmd_line_script.py +@@ -560,7 +560,9 @@ + # Python cannot a undecodable bytes argument to a subprocess. + # WASI does not permit invalid UTF-8 names. + if (os_helper.TESTFN_UNDECODABLE +- and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')): ++ and sys.platform not in ( ++ 'win32', 'darwin', 'ios', 'tvos', 'watchos', 'emscripten', 'wasi' ++ )): + name = os.fsdecode(os_helper.TESTFN_UNDECODABLE) + elif os_helper.TESTFN_NONASCII: + name = os_helper.TESTFN_NONASCII diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py -index 203dd6fe57..8e0999ecd7 100644 +index 203dd6fe57..a4e7099da3 100644 --- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py @@ -6,7 +6,7 @@ @@ -641,40 +642,272 @@ index 203dd6fe57..8e0999ecd7 100644 import sys import unittest -from test.support import verbose, cpython_only, get_pagesize -+from test.support import cpython_only, get_pagesize, is_apple_mobile, verbose ++from test.support import cpython_only, get_pagesize, is_apple_mobile, requires_subprocess, verbose from test.support.import_helper import import_module from test.support.os_helper import TESTFN, unlink -@@ -57,7 +57,7 @@ +@@ -57,7 +57,9 @@ start_len = "qq" if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd')) - or sys.platform == 'darwin'): -+ or sys.platform == 'darwin' or is_apple_mobile): ++ or sys.platform == 'darwin' ++ or is_apple_mobile ++ ): if struct.calcsize('l') == 8: off_t = 'l' pid_t = 'i' +@@ -157,6 +159,7 @@ + self.assertRaises(TypeError, fcntl.flock, 'spam', fcntl.LOCK_SH) + + @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError") ++ @requires_subprocess() + def test_lockf_exclusive(self): + self.f = open(TESTFN, 'wb+') + cmd = fcntl.LOCK_EX | fcntl.LOCK_NB +@@ -169,6 +172,7 @@ + self.assertEqual(p.exitcode, 0) + + @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError") ++ @requires_subprocess() + def test_lockf_share(self): + self.f = open(TESTFN, 'wb+') + cmd = fcntl.LOCK_SH | fcntl.LOCK_NB +diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py +index 2f191ea7a4..81115e9db8 100644 +--- a/Lib/test/test_ftplib.py ++++ b/Lib/test/test_ftplib.py +@@ -18,6 +18,7 @@ + + from unittest import TestCase, skipUnless + from test import support ++from test.support import requires_subprocess + from test.support import threading_helper + from test.support import socket_helper + from test.support import warnings_helper +@@ -900,6 +901,7 @@ + + + @skipUnless(ssl, "SSL not available") ++@requires_subprocess() + class TestTLS_FTPClassMixin(TestFTPClass): + """Repeat TestFTPClass tests starting the TLS layer for both control + and data connections first. +@@ -916,6 +918,7 @@ + + + @skipUnless(ssl, "SSL not available") ++@requires_subprocess() + class TestTLS_FTPClass(TestCase): + """Specific TLS_FTP class tests.""" + +diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py +index 4f311c2d49..c0a6a48dea 100644 +--- a/Lib/test/test_genericpath.py ++++ b/Lib/test/test_genericpath.py +@@ -488,7 +488,9 @@ + # invalid UTF-8 name. Windows allows creating a directory with an + # arbitrary bytes name, but fails to enter this directory + # (when the bytes name is used). +- and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')): ++ and sys.platform not in ( ++ 'win32', 'darwin', 'ios', 'tvos', 'watchos', 'emscripten', 'wasi' ++ )): + name = os_helper.TESTFN_UNDECODABLE + elif os_helper.TESTFN_NONASCII: + name = os_helper.TESTFN_NONASCII diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py -index 9fa6ecf9c0..53eccef97f 100644 +index 9fa6ecf9c0..01dc990b1e 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py -@@ -30,6 +30,7 @@ +@@ -30,7 +30,9 @@ import unittest from test import support +from test.support import is_apple_mobile from test.support import os_helper ++from test.support import requires_subprocess from test.support import threading_helper -@@ -422,7 +423,7 @@ + support.requires_working_socket(module=True) +@@ -410,8 +412,8 @@ + reader.close() + return body + +- @unittest.skipIf(sys.platform == 'darwin', +- 'undecodable name cannot always be decoded on macOS') ++ @unittest.skipIf(sys.platform == 'darwin' or is_apple_mobile, ++ 'undecodable name cannot always be decoded on Apple platforms') + @unittest.skipIf(sys.platform == 'win32', + 'undecodable name cannot be decoded on win32') + @unittest.skipUnless(os_helper.TESTFN_UNDECODABLE, +@@ -422,9 +424,9 @@ with open(os.path.join(self.tempdir, filename), 'wb') as f: f.write(os_helper.TESTFN_UNDECODABLE) response = self.request(self.base_url + '/') - if sys.platform == 'darwin': +- # On Mac OS the HFS+ filesystem replaces bytes that aren't valid +- # UTF-8 into a percent-encoded value. + if sys.platform == 'darwin' or is_apple_mobile: - # On Mac OS the HFS+ filesystem replaces bytes that aren't valid - # UTF-8 into a percent-encoded value. ++ # On Apple platforms the HFS+ filesystem replaces bytes that ++ # aren't valid UTF-8 into a percent-encoded value. for name in os.listdir(self.tempdir): + if name != 'test': # Ignore a filename created in setUp(). + filename = name +@@ -697,6 +699,7 @@ + + @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, + "This test can't be run reliably as root (issue #13308).") ++@requires_subprocess() + class CGIHTTPServerTestCase(BaseTestCase): + class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler): + _test_case_self = None # populated by each setUp() method call. +diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py +index aa465c70df..16337bb12b 100644 +--- a/Lib/test/test_import/__init__.py ++++ b/Lib/test/test_import/__init__.py +@@ -5,7 +5,7 @@ + import importlib.util + from importlib._bootstrap_external import _get_sourcefile + from importlib.machinery import ( +- BuiltinImporter, ExtensionFileLoader, FrozenImporter, SourceFileLoader, ++ AppleFrameworkLoader, BuiltinImporter, ExtensionFileLoader, FrozenImporter, SourceFileLoader, + ) + import marshal + import os +@@ -25,7 +25,7 @@ + + from test.support import os_helper + from test.support import ( +- STDLIB_DIR, swap_attr, swap_item, cpython_only, is_emscripten, ++ STDLIB_DIR, swap_attr, swap_item, cpython_only, is_apple_mobile, is_emscripten, + is_wasi, run_in_subinterp, run_in_subinterp_with_config, Py_TRACE_REFS) + from test.support.import_helper import ( + forget, make_legacy_pyc, unlink, unload, ready_to_import, +@@ -66,6 +66,7 @@ + MODULE_KINDS = { + BuiltinImporter: 'built-in', + ExtensionFileLoader: 'extension', ++ AppleFrameworkLoader: 'framework extension', + FrozenImporter: 'frozen', + SourceFileLoader: 'pure Python', + } +@@ -91,7 +92,10 @@ + assert module.__spec__.origin == 'built-in', module.__spec__ + + def require_extension(module, *, skip=False): +- _require_loader(module, ExtensionFileLoader, skip) ++ if is_apple_mobile: ++ _require_loader(module, AppleFrameworkLoader, skip) ++ else: ++ _require_loader(module, ExtensionFileLoader, skip) + + def require_frozen(module, *, skip=True): + module = _require_loader(module, FrozenImporter, skip) +@@ -360,7 +364,7 @@ + self.assertEqual(cm.exception.path, _testcapi.__file__) + self.assertRegex( + str(cm.exception), +- r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|pyd)\)" ++ r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|dylib|pyd)\)" + ) + else: + self.assertEqual( +@@ -1678,6 +1682,12 @@ + os.set_blocking(r, False) + return (r, w) + ++ def create_extension_loader(self, modname, filename): ++ if is_apple_mobile: ++ return AppleFrameworkLoader(modname, filename, None) ++ else: ++ return ExtensionFileLoader(modname, filename) ++ + def import_script(self, name, fd, filename=None, check_override=None): + override_text = '' + if check_override is not None: +@@ -1872,7 +1882,7 @@ + def test_multi_init_extension_non_isolated_compat(self): + modname = '_test_non_isolated' + filename = _testmultiphase.__file__ +- loader = ExtensionFileLoader(modname, filename) ++ loader = self.create_extension_loader(modname, filename) + spec = importlib.util.spec_from_loader(modname, loader) + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) +@@ -1890,7 +1900,7 @@ + def test_multi_init_extension_per_interpreter_gil_compat(self): + modname = '_test_shared_gil_only' + filename = _testmultiphase.__file__ +- loader = ExtensionFileLoader(modname, filename) ++ loader = self.create_extension_loader(modname, filename) + spec = importlib.util.spec_from_loader(modname, loader) + module = importlib.util.module_from_spec(spec) + loader.exec_module(module) +@@ -2020,10 +2030,13 @@ + @classmethod + def setUpClass(cls): + spec = importlib.util.find_spec(cls.NAME) +- from importlib.machinery import ExtensionFileLoader ++ from importlib.machinery import AppleFrameworkLoader, ExtensionFileLoader + cls.FILE = spec.origin + cls.LOADER = type(spec.loader) +- assert cls.LOADER is ExtensionFileLoader ++ if is_apple_mobile: ++ assert cls.LOADER is AppleFrameworkLoader ++ else: ++ assert cls.LOADER is ExtensionFileLoader + + # Start fresh. + cls.clean_up() +@@ -2063,7 +2076,10 @@ + """ + # This is essentially copied from the old imp module. + from importlib._bootstrap import _load +- loader = self.LOADER(name, path) ++ if is_apple_mobile: ++ loader = self.LOADER(name, path, None) ++ else: ++ loader = self.LOADER(name, path) + + # Issue bpo-24748: Skip the sys.modules check in _load_module_shim; + # always load new extension. +diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py +index 1d5b6e7a5d..519a1c536b 100644 +--- a/Lib/test/test_importlib/extension/test_finder.py ++++ b/Lib/test/test_importlib/extension/test_finder.py +@@ -1,3 +1,4 @@ ++from test.support import is_apple_mobile + from test.test_importlib import abc, util + + machinery = util.import_importlib('importlib.machinery') +@@ -11,6 +12,8 @@ + """Test the finder for extension modules.""" + + def setUp(self): ++ if is_apple_mobile: ++ raise unittest.SkipTest(f"{sys.platform} uses a custom finder") + if not self.machinery.EXTENSION_SUFFIXES: + raise unittest.SkipTest("Requires dynamic loading support.") + if util.EXTENSIONS.name in sys.builtin_module_names: +diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py +index 64c8a54851..fe3219c885 100644 +--- a/Lib/test/test_importlib/extension/test_loader.py ++++ b/Lib/test/test_importlib/extension/test_loader.py +@@ -1,3 +1,4 @@ ++from test.support import is_apple_mobile + from test.test_importlib import abc, util + + machinery = util.import_importlib('importlib.machinery') +@@ -16,6 +17,8 @@ + """Test ExtensionFileLoader.""" + + def setUp(self): ++ if is_apple_mobile: ++ raise unittest.SkipTest(f"{sys.platform} uses a custom loader") + if not self.machinery.EXTENSION_SUFFIXES: + raise unittest.SkipTest("Requires dynamic loading support.") + if util.EXTENSIONS.name in sys.builtin_module_names: diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 022cf21a47..67f484d40e 100644 --- a/Lib/test/test_io.py @@ -697,7 +930,7 @@ index 022cf21a47..67f484d40e 100644 'largefile', 'test requires %s bytes and a long time to run' % self.LARGE) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py -index ab969ce26a..9a9cacd6a5 100644 +index ab969ce26a..e6aee6c7de 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -43,6 +43,7 @@ @@ -708,30 +941,6 @@ index ab969ce26a..9a9cacd6a5 100644 from test.support import os_helper from test.support import socket_helper from test.support import threading_helper -@@ -1923,6 +1924,7 @@ - - - @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - class UnixSocketHandlerTest(SocketHandlerTest): - - """Test for SocketHandler with unix sockets.""" -@@ -2003,6 +2005,7 @@ - self.assertEqual(self.log_output, "spam\neggs\n") - - @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - class UnixDatagramHandlerTest(DatagramHandlerTest): - - """Test for DatagramHandler using Unix sockets.""" -@@ -2094,6 +2097,7 @@ - self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00') - - @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - class UnixSysLogHandlerTest(SysLogHandlerTest): - - """Test for SysLogHandler with Unix sockets.""" diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index 3d9d6d5d0a..dfb1d6f84d 100644 --- a/Lib/test/test_marshal.py @@ -784,8 +993,20 @@ index dfcf303942..5aabfac885 100644 requires('largefile', 'test requires %s bytes and a long time to run' % str(0x180000000)) f = open(TESTFN, 'w+b') +diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py +index 398393b233..52b0a2ac23 100644 +--- a/Lib/test/test_os.py ++++ b/Lib/test/test_os.py +@@ -3785,6 +3785,7 @@ + self.assertGreaterEqual(size.columns, 0) + self.assertGreaterEqual(size.lines, 0) + ++ @support.requires_subprocess() + def test_stty_match(self): + """Check if stty returns the same results + diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py -index 2169733503..753a137d66 100644 +index 2169733503..842fed6a67 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -8,7 +8,7 @@ @@ -816,8 +1037,18 @@ index 2169733503..753a137d66 100644 @unittest.skipUnless(sys.platform == 'darwin', "OSX only test") def test_mac_ver_with_fork(self): +@@ -472,7 +475,8 @@ + 'root:xnu-4570.71.2~1/RELEASE_X86_64'), + 'x86_64', 'i386') + arch = ('64bit', '') +- with mock.patch.object(platform, 'uname', return_value=uname), \ ++ with mock.patch.object(sys, "platform", "darwin"), \ ++ mock.patch.object(platform, 'uname', return_value=uname), \ + mock.patch.object(platform, 'architecture', return_value=arch): + for mac_ver, expected_terse, expected in [ + # darwin: mac_ver() returns empty strings diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py -index 9d72dba159..f12e9bb0cb 100644 +index 9d72dba159..a8b50606ac 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py @@ -2,6 +2,7 @@ @@ -873,15 +1104,73 @@ index 9d72dba159..f12e9bb0cb 100644 self.assertRaises(OSError, posix.sched_get_priority_min, -23) self.assertRaises(OSError, posix.sched_get_priority_max, -23) +@@ -1899,11 +1908,13 @@ + + + @unittest.skipUnless(hasattr(os, 'posix_spawn'), "test needs os.posix_spawn") ++@support.requires_subprocess() + class TestPosixSpawn(unittest.TestCase, _PosixSpawnMixin): + spawn_func = getattr(posix, 'posix_spawn', None) + + + @unittest.skipUnless(hasattr(os, 'posix_spawnp'), "test needs os.posix_spawnp") ++@support.requires_subprocess() + class TestPosixSpawnP(unittest.TestCase, _PosixSpawnMixin): + spawn_func = getattr(posix, 'posix_spawnp', None) + +diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py +index f31a68c5d8..062a7524dd 100644 +--- a/Lib/test/test_pty.py ++++ b/Lib/test/test_pty.py +@@ -1,11 +1,15 @@ ++import sys ++import unittest + from test.support import verbose, reap_children ++from test.support import is_apple_mobile, is_emscripten, is_wasi + from test.support.import_helper import import_module + + # Skip these tests if termios or fcntl are not available + import_module('termios') +-# fcntl is a proxy for not being one of the wasm32 platforms even though we +-# don't use this module... a proper check for what crashes those is needed. +-import_module("fcntl") ++ ++# Skip tests on WASM platforms, plus iOS/tvOS/watchOS ++if is_apple_mobile or is_emscripten or is_wasi: ++ raise unittest.SkipTest(f"pty tests not required on {sys.platform}") + + import errno + import os +@@ -16,7 +20,6 @@ + import signal + import socket + import io # readline +-import unittest + import warnings + + TEST_STRING_1 = b"I wish to buy a fish license.\n" +diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py +index 677349c2bf..f4471bdf8c 100644 +--- a/Lib/test/test_selectors.py ++++ b/Lib/test/test_selectors.py +@@ -526,7 +526,7 @@ + try: + fds = s.select() + except OSError as e: +- if e.errno == errno.EINVAL and sys.platform == 'darwin': ++ if e.errno == errno.EINVAL and (sys.platform == 'darwin' or support.is_apple_mobile): + # unexplainable errors on macOS don't need to fail the test + self.skipTest("Invalid argument error calling poll()") + raise diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py -index d231e66b7b..748839cdfb 100644 +index d231e66b7b..182eeaaca4 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py @@ -2051,6 +2051,7 @@ check_chown(dirname, uid, gid) -+@unittest.skipIf(support.has_subprocess_support, 'Test requires support for subprocesses.') ++@support.requires_subprocess() class TestWhich(BaseTest, unittest.TestCase): def setUp(self): @@ -889,12 +1178,59 @@ index d231e66b7b..748839cdfb 100644 self.assertGreaterEqual(size.lines, 0) @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty") -+ @unittest.skipUnless(support.has_subprocess_support, 'Test requires support for subprocesses.') ++ @support.requires_subprocess() @unittest.skipUnless(hasattr(os, 'get_terminal_size'), 'need os.get_terminal_size()') def test_stty_match(self): +diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py +index f2ae28c38d..f1f5c56eb8 100644 +--- a/Lib/test/test_signal.py ++++ b/Lib/test/test_signal.py +@@ -12,6 +12,7 @@ + import time + import unittest + from test import support ++from test.support import is_apple_mobile + from test.support import os_helper + from test.support.script_helper import assert_python_ok, spawn_python + from test.support import threading_helper +@@ -806,7 +807,7 @@ + self.assertEqual(self.hndl_called, True) + + # Issue 3864, unknown if this affects earlier versions of freebsd also +- @unittest.skipIf(sys.platform in ('netbsd5',), ++ @unittest.skipIf(sys.platform in ('netbsd5',) or is_apple_mobile, + 'itimer not reliable (does not mix well with threading) on some BSDs.') + def test_itimer_virtual(self): + self.itimer = signal.ITIMER_VIRTUAL +@@ -1242,6 +1243,8 @@ + + @unittest.skipUnless(hasattr(signal, "setitimer"), + "test needs setitimer()") ++ @unittest.skipIf(is_apple_mobile, ++ f"{sys.platform} doesn't support setitimer().") + def test_stress_delivery_dependent(self): + """ + This test uses dependent signal handlers. +@@ -1288,6 +1291,8 @@ + + @unittest.skipUnless(hasattr(signal, "setitimer"), + "test needs setitimer()") ++ @unittest.skipIf(is_apple_mobile, ++ f"{sys.platform} doesn't support setitimer().") + def test_stress_delivery_simultaneous(self): + """ + This test uses simultaneous signal handlers. +@@ -1321,6 +1326,7 @@ + @unittest.skipUnless(hasattr(signal, "SIGUSR1"), + "test needs SIGUSR1") + @threading_helper.requires_working_threading() ++ @unittest.skipIf(is_apple_mobile, "too stressful for iOS") + def test_stress_modifying_handlers(self): + # bpo-43406: race condition between trip_signal() and signal.signal + signum = signal.SIGUSR1 diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py -index 86701caf05..5f8459beed 100644 +index 86701caf05..155c4c458c 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1,5 +1,6 @@ @@ -958,42 +1294,8 @@ index 86701caf05..5f8459beed 100644 def testFDPassEmpty(self): # Try to pass an empty FD array. Can receive either no array # or an empty array. -@@ -4547,28 +4548,33 @@ - pass - - @requireAttrs(socket.socket, "sendmsg") -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - @requireAttrs(socket, "AF_UNIX") - class SendmsgUnixStreamTest(SendmsgStreamTests, SendrecvmsgUnixStreamTestBase): - pass - - @requireAttrs(socket.socket, "recvmsg") -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - @requireAttrs(socket, "AF_UNIX") - class RecvmsgUnixStreamTest(RecvmsgTests, RecvmsgGenericStreamTests, - SendrecvmsgUnixStreamTestBase): - pass - - @requireAttrs(socket.socket, "recvmsg_into") -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - @requireAttrs(socket, "AF_UNIX") - class RecvmsgIntoUnixStreamTest(RecvmsgIntoTests, RecvmsgGenericStreamTests, - SendrecvmsgUnixStreamTestBase): - pass - - @requireAttrs(socket.socket, "sendmsg", "recvmsg") -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - @requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS") - class RecvmsgSCMRightsStreamTest(SCMRightsTest, SendrecvmsgUnixStreamTestBase): - pass - - @requireAttrs(socket.socket, "sendmsg", "recvmsg_into") -+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - @requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS") - class RecvmsgIntoSCMRightsStreamTest(RecvmsgIntoMixin, SCMRightsTest, - SendrecvmsgUnixStreamTestBase): diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py -index 0f62f9eb20..f7a8a82e1d 100644 +index 0f62f9eb20..d2daf044d6 100644 --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py @@ -8,12 +8,13 @@ @@ -1011,34 +1313,93 @@ index 0f62f9eb20..f7a8a82e1d 100644 from test.support import os_helper from test.support import socket_helper from test.support import threading_helper -@@ -181,12 +182,14 @@ - self.stream_examine) - - @requires_unix_sockets -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_UnixStreamServer(self): - self.run_server(socketserver.UnixStreamServer, - socketserver.StreamRequestHandler, - self.stream_examine) - - @requires_unix_sockets -+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) - def test_ThreadingUnixStreamServer(self): - self.run_server(socketserver.ThreadingUnixStreamServer, - socketserver.StreamRequestHandler, +diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py +index f3efe0f52f..ff29b98a80 100644 +--- a/Lib/test/test_sqlite3/test_dbapi.py ++++ b/Lib/test/test_sqlite3/test_dbapi.py +@@ -31,7 +31,7 @@ + + from test.support import ( + SHORT_TIMEOUT, check_disallow_instantiation, requires_subprocess, +- is_emscripten, is_wasi ++ is_apple_mobile, is_emscripten, is_wasi + ) + from test.support import gc_collect + from test.support import threading_helper +@@ -667,7 +667,7 @@ + cx.execute(self._sql) + + @unittest.skipIf(sys.platform == "win32", "skipped on Windows") +- @unittest.skipIf(sys.platform == "darwin", "skipped on macOS") ++ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipped on Apple platforms") + @unittest.skipIf(is_emscripten or is_wasi, "not supported on Emscripten/WASI") + @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") + def test_open_with_undecodable_path(self): +@@ -713,7 +713,7 @@ + cx.execute(self._sql) + + @unittest.skipIf(sys.platform == "win32", "skipped on Windows") +- @unittest.skipIf(sys.platform == "darwin", "skipped on macOS") ++ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipped on Apple platforms") + @unittest.skipIf(is_emscripten or is_wasi, "not supported on Emscripten/WASI") + @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") + def test_open_undecodable_uri(self): diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index 2a6813f00b..c1a7d6eb08 100644 +index 2a6813f00b..1a65e8f44d 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py -@@ -338,7 +338,7 @@ +@@ -6,7 +6,7 @@ + from copy import copy + + from test.support import ( +- captured_stdout, PythonSymlink, requires_subprocess, is_wasi ++ captured_stdout, PythonSymlink, requires_subprocess, is_apple_mobile, is_wasi + ) + from test.support.import_helper import import_module + from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink, +@@ -333,12 +333,14 @@ + # XXX more platforms to tests here + + @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds") ++ @unittest.skipIf(is_apple_mobile, ++ f"{sys.platform} doesn't distribute config.h in the runtime environment") + def test_get_config_h_filename(self): + config_h = sysconfig.get_config_h_filename() self.assertTrue(os.path.isfile(config_h), config_h) def test_get_scheme_names(self): - wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv'] -+ wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv', 'tvos', 'watchos'] ++ wanted = ['ios', 'nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv', 'tvos', 'watchos'] if HAS_USER_BASE: wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) +@@ -410,6 +412,8 @@ + self.assertTrue(library.startswith(f'python{major}{minor}')) + self.assertTrue(library.endswith('.dll')) + self.assertEqual(library, ldlibrary) ++ elif is_apple_mobile: ++ self.assertEqual(ldlibrary, "Python.framework/Python") + else: + self.assertTrue(library.startswith(f'libpython{major}.{minor}')) + self.assertTrue(library.endswith('.a')) +@@ -460,6 +464,8 @@ + self.assertEqual(my_platform, test_platform) + + @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds") ++ @unittest.skipIf(is_apple_mobile, ++ f"{sys.platform} doesn't distribute config.h in the runtime environment") + def test_srcdir(self): + # See Issues #15322, #15364. + srcdir = sysconfig.get_config_var('srcdir') +@@ -526,6 +532,8 @@ + @unittest.skipIf(sys.platform.startswith('win'), + 'Test is not Windows compatible') + @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds") ++ @unittest.skipIf(is_apple_mobile, ++ f"{sys.platform} doesn't distribute config.h in the runtime environment") + def test_get_makefile_filename(self): + makefile = sysconfig.get_makefile_filename() + self.assertTrue(os.path.isfile(makefile), makefile) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py index 00a64372b3..539db5d7d7 100644 --- a/Lib/test/test_threading.py @@ -1068,6 +1429,86 @@ index 00a64372b3..539db5d7d7 100644 def test_threads_join_2(self): # Same as above, but a delay gets introduced after the thread's # Python code returned but before the thread state is deleted. +diff --git a/Lib/test/test_unicode_file_functions.py b/Lib/test/test_unicode_file_functions.py +index 47619c8807..3f36be1a49 100644 +--- a/Lib/test/test_unicode_file_functions.py ++++ b/Lib/test/test_unicode_file_functions.py +@@ -5,7 +5,7 @@ + import unittest + import warnings + from unicodedata import normalize +-from test.support import os_helper ++from test.support import is_apple_mobile, os_helper + from test import support + + +@@ -23,13 +23,13 @@ + '10_\u1fee\u1ffd', + ] + +-# Mac OS X decomposes Unicode names, using Normal Form D. ++# Apple platforms decompose Unicode names, using Normal Form D. + # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html + # "However, most volume formats do not follow the exact specification for + # these normal forms. For example, HFS Plus uses a variant of Normal Form D + # in which U+2000 through U+2FFF, U+F900 through U+FAFF, and U+2F800 through + # U+2FAFF are not decomposed." +-if sys.platform != 'darwin': ++if sys.platform != 'darwin' and not is_apple_mobile: + filenames.extend([ + # Specific code points: NFC(fn), NFD(fn), NFKC(fn) and NFKD(fn) all different + '11_\u0385\u03d3\u03d4', +@@ -123,7 +123,7 @@ + # NFD (a variant of Unicode NFD form). Normalize the filename to NFC, NFKC, + # NFKD in Python is useless, because darwin will normalize it later and so + # open(), os.stat(), etc. don't raise any exception. +- @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') ++ @unittest.skipIf(sys.platform == 'darwin' or is_apple_mobile, 'irrelevant test on Apple platforms') + @unittest.skipIf( + support.is_emscripten or support.is_wasi, + "test fails on Emscripten/WASI when host platform is macOS." +@@ -145,7 +145,7 @@ + # Skip the test on darwin, because darwin uses a normalization different + # than Python NFD normalization: filenames are different even if we use + # Python NFD normalization. +- @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') ++ @unittest.skipIf(sys.platform == 'darwin' or is_apple_mobile, 'irrelevant test on Apple platforms') + def test_listdir(self): + sf0 = set(self.files) + with warnings.catch_warnings(): +diff --git a/Lib/test/test_unittest/test_break.py b/Lib/test/test_unittest/test_break.py +index 1da98af3e7..d413d5a478 100644 +--- a/Lib/test/test_unittest/test_break.py ++++ b/Lib/test/test_unittest/test_break.py +@@ -11,6 +11,8 @@ + + @unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill") + @unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows") ++@unittest.skipIf(support.is_apple_mobile, ++ f"{sys.platform} doesn't support SIGINT.") + class TestBreak(unittest.TestCase): + int_handler = None + # This number was smart-guessed, previously tests were failing +diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py +index 99c9e24994..fa528a6758 100644 +--- a/Lib/test/test_urllib2.py ++++ b/Lib/test/test_urllib2.py +@@ -1,6 +1,7 @@ + import unittest + from test import support + from test.support import os_helper ++from test.support import requires_subprocess + from test.support import warnings_helper + from test import test_urllib + from unittest import mock +@@ -998,6 +999,7 @@ + + file_obj.close() + ++ @requires_subprocess() + def test_http_body_pipe(self): + # A file reading from a pipe. + # A pipe cannot be seek'ed. There is no way to determine the diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py index 890672c5d2..dce68e1e40 100644 --- a/Lib/test/test_venv.py @@ -1153,7 +1594,7 @@ index 8b0628745c..2d8de8aecb 100755 # # Platform support for Windows diff --git a/Makefile.pre.in b/Makefile.pre.in -index 4996c5c309..24ee442643 100644 +index 4996c5c309..7571c5f4ad 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -184,6 +184,8 @@ @@ -1213,7 +1654,29 @@ index 4996c5c309..24ee442643 100644 # 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) -@@ -1924,7 +1940,7 @@ +@@ -1885,6 +1901,21 @@ + $(RUNSHARED) /usr/libexec/oah/translate \ + ./$(BUILDPYTHON) -E -m test -j 0 -u all $(TESTOPTS) + ++# Run the test suite on the iOS simulator. ++# Must be run on a macOS machine with a full Xcode install that has an iPhone SE ++# (3rd edition) simulator available, after running `make install` on a configuration ++# with --enable-framework="./Tools/iOSTestbed/Python.xcframework/ios-arm64_x86_64-simulator" ++XCRESULT=./build/$(MULTIARCH).$(shell date +%s).xcresult ++.PHONY: testiOS ++testiOS: ++ # Run the test suite for the Xcode project, targeting the iOS simulator. ++ # If the suite fails, extract and print the console output, then re-raise the failure ++ if ! xcodebuild test -project ./Tools/iOSTestbed/iOSTestbed.xcodeproj -scheme "iOSTestbed" -destination "platform=iOS Simulator,name=iPhone SE (3rd Generation)" -resultBundlePath $(XCRESULT) ; then \ ++ xcrun xcresulttool get --path $(XCRESULT) --id $$(xcrun xcresulttool get --path $(XCRESULT) --format json | $(PYTHON_FOR_BUILD) -c "import sys, json; result = json.load(sys.stdin); print(result['actions']['_values'][0]['actionResult']['logRef']['id']['_value'])"); \ ++ echo ; \ ++ exit 1; \ ++ fi ++ + # Like test, but using --slow-ci which enables all test resources and use + # longer timeout. Run an optional pybuildbot.identify script to include + # information about the build environment. +@@ -1924,7 +1955,7 @@ # which can lead to two parallel `./python setup.py build` processes that # step on each others toes. .PHONY: install @@ -1222,7 +1685,7 @@ index 4996c5c309..24ee442643 100644 if test "x$(ENSUREPIP)" != "xno" ; then \ case $(ENSUREPIP) in \ upgrade) ensurepip="--upgrade" ;; \ -@@ -2507,20 +2523,32 @@ +@@ -2507,20 +2538,36 @@ exit 1; \ else true; \ fi @@ -1231,7 +1694,13 @@ index 4996c5c309..24ee442643 100644 - echo "Creating directory $(DESTDIR)$$i"; \ - $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$$i; \ - else true; \ -- fi; \ ++ # iOS/tvOS/watchOS uses a non-versioned framework with Info.plist in the ++ # framework root, no .lproj data, and binaries ++ @if test "$(MACHDEP)" = ios -o "$(MACHDEP)" = tvos -o "$(MACHDEP)" = watchos; then \ ++ if test -d $(PYTHONFRAMEWORKPREFIX)/include; then \ ++ echo "Clearing stale header symlink directory"; \ ++ rm -rf $(PYTHONFRAMEWORKPREFIX)/include; \ + fi; \ - done - $(LN) -fsn include/python$(LDVERSION) $(DESTDIR)$(prefix)/Headers - sed 's/%VERSION%/'"`$(RUNSHARED) ./$(BUILDPYTHON) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(prefix)/Resources/Info.plist @@ -1240,9 +1709,6 @@ index 4996c5c309..24ee442643 100644 - $(LN) -fsn Versions/Current/Headers $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers - $(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 binaries -+ @if test "$(MACHDEP)" = ios -o "$(MACHDEP)" = tvos -o "$(MACHDEP)" = watchos; then \ + $(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); \ @@ -1269,7 +1735,7 @@ index 4996c5c309..24ee442643 100644 # This installs Mac/Lib into the framework # Install a number of symlinks to keep software that expects a normal unix -@@ -2562,6 +2590,15 @@ +@@ -2562,6 +2609,19 @@ frameworkinstallextras: cd Mac && $(MAKE) installextras DESTDIR="$(DESTDIR)" @@ -1279,6 +1745,10 @@ index 4996c5c309..24ee442643 100644 +# 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)" + @@ -1473,7 +1943,7 @@ index a4d9466559..8f51bef22d 100644 sin(pi*x), giving accurate results for all finite x (especially x integral or close to an integer). This is here for use in the diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c -index 650ae4bbd6..95c1b3633c 100644 +index 650ae4bbd6..f1d90ea23b 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -92,6 +92,8 @@ @@ -1485,34 +1955,19 @@ index 650ae4bbd6..95c1b3633c 100644 #if defined(__has_builtin) #if __has_builtin(__builtin_available) #define HAVE_BUILTIN_AVAILABLE 1 -@@ -369,6 +371,26 @@ +@@ -369,6 +371,11 @@ # define fsync _commit #endif /* ! __WATCOMC__ || __QNX__ */ -+// iOS/tvOS/watchOS *define* a number of POSIX functions, but you can't use them -+// because they aren't conventional multiprocess environment. ++// iOS/tvOS/watchOS *define* getgroups, but it returns an error if used. +#if TARGET_OS_IPHONE -+# undef HAVE_EXECV -+# undef HAVE_FORK -+# undef HAVE_FORK1 -+# undef HAVE_FORKPTY +# undef HAVE_GETGROUPS -+# undef HAVE_POSIX_SPAWN -+# undef HAVE_POSIX_SPAWNP -+# undef HAVE_SCHED_H -+# undef HAVE_SENDFILE -+# undef HAVE_SETPRIORITY -+# undef HAVE_SPAWNV -+# undef HAVE_WAIT -+# undef HAVE_WAIT3 -+# undef HAVE_WAIT4 -+# undef HAVE_WAITPID +#endif + /*[clinic input] # one of the few times we lie about this name! module os -@@ -1548,7 +1570,9 @@ +@@ -1548,7 +1555,9 @@ */ #include #elif !defined(_MSC_VER) && (!defined(__WATCOMC__) || defined(__QNX__) || defined(__VXWORKS__)) @@ -1522,7 +1977,7 @@ index 650ae4bbd6..95c1b3633c 100644 #endif /* !_MSC_VER */ static PyObject * -@@ -1564,6 +1588,7 @@ +@@ -1564,6 +1573,7 @@ d = PyDict_New(); if (d == NULL) return NULL; @@ -1530,7 +1985,7 @@ index 650ae4bbd6..95c1b3633c 100644 #ifdef MS_WINDOWS /* _wenviron must be initialized in this way if the program is started through main() instead of wmain(). */ -@@ -1617,6 +1642,7 @@ +@@ -1617,6 +1627,7 @@ Py_DECREF(k); Py_DECREF(v); } @@ -1538,7 +1993,7 @@ index 650ae4bbd6..95c1b3633c 100644 return d; } -@@ -5750,6 +5776,9 @@ +@@ -5750,6 +5761,9 @@ /*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/ { long result; @@ -1548,7 +2003,7 @@ index 650ae4bbd6..95c1b3633c 100644 const char *bytes = PyBytes_AsString(command); if (PySys_Audit("os.system", "(O)", command) < 0) { -@@ -5759,6 +5788,7 @@ +@@ -5759,6 +5773,7 @@ Py_BEGIN_ALLOW_THREADS result = system(bytes); Py_END_ALLOW_THREADS @@ -1556,7 +2011,7 @@ index 650ae4bbd6..95c1b3633c 100644 return result; } #endif -@@ -15000,6 +15030,7 @@ +@@ -15000,6 +15015,7 @@ int is_symlink; int need_stat; #endif @@ -1564,7 +2019,7 @@ index 650ae4bbd6..95c1b3633c 100644 #ifdef MS_WINDOWS unsigned long dir_bits; #endif -@@ -15060,6 +15091,7 @@ +@@ -15060,6 +15076,7 @@ #endif return result; @@ -1634,10 +2089,21 @@ index b7034369c4..a7d63abe5d 100644 "getpwnam(): name not found: %R", name); } diff --git a/Modules/timemodule.c b/Modules/timemodule.c -index 6a872a285d..59b48c0ea4 100644 +index 6a872a285d..197eadf55f 100644 --- a/Modules/timemodule.c +++ b/Modules/timemodule.c -@@ -113,6 +113,11 @@ +@@ -59,6 +59,10 @@ + # define HAVE_CLOCK_GETTIME_RUNTIME 1 + #endif + ++// iOS/tvOS/watchOS *define* clock_settime, but it can't be used ++#if TARGET_OS_IPHONE ++# undef HAVE_CLOCK_SETTIME ++#endif + + #define SEC_TO_NS (1000 * 1000 * 1000) + +@@ -113,6 +117,11 @@ } @@ -1649,21 +2115,7 @@ index 6a872a285d..59b48c0ea4 100644 /* Forward declarations */ static int pysleep(_PyTime_t timeout); -@@ -304,11 +309,13 @@ - if (_PyTime_AsTimespec(t, &tp) == -1) - return NULL; - -+#if !TARGET_OS_IPHONE - ret = clock_settime((clockid_t)clk_id, &tp); - if (ret != 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } -+#endif - Py_RETURN_NONE; - } - -@@ -337,11 +344,13 @@ +@@ -337,11 +346,13 @@ return NULL; } @@ -1810,6 +2262,1035 @@ index 3debe7f7c1..612ba30da1 100644 /* dict ready */ ns = _PyNamespace_New(impl_info); +--- /dev/null ++++ b/Tools/iOSTestbed/Python.xcframework/Info.plist +@@ -0,0 +1,44 @@ ++ ++ ++ ++ ++ AvailableLibraries ++ ++ ++ BinaryPath ++ Python.framework/Python ++ LibraryIdentifier ++ ios-arm64 ++ LibraryPath ++ Python.framework ++ SupportedArchitectures ++ ++ arm64 ++ ++ SupportedPlatform ++ ios ++ ++ ++ BinaryPath ++ Python.framework/Python ++ LibraryIdentifier ++ ios-arm64_x86_64-simulator ++ LibraryPath ++ Python.framework ++ SupportedArchitectures ++ ++ arm64 ++ x86_64 ++ ++ SupportedPlatform ++ ios ++ SupportedPlatformVariant ++ simulator ++ ++ ++ CFBundlePackageType ++ XFWK ++ XCFrameworkFormatVersion ++ 1.0 ++ ++ +--- /dev/null ++++ b/Tools/iOSTestbed/Python.xcframework/ios-arm64/README +@@ -0,0 +1,4 @@ ++This directory is intentionally empty. ++ ++It should be used as a target for `--enable-framework` when compiling an iOS on-device ++build for testing purposes. +--- /dev/null ++++ b/Tools/iOSTestbed/Python.xcframework/ios-arm64_x86_64-simulator/README +@@ -0,0 +1,4 @@ ++This directory is intentionally empty. ++ ++It should be used as a target for `--enable-framework` when compiling an iOS simulator ++build for testing purposes (either x86_64 or ARM64). +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed.xcodeproj/project.pbxproj +@@ -0,0 +1,569 @@ ++// !$*UTF8*$! ++{ ++ archiveVersion = 1; ++ classes = { ++ }; ++ objectVersion = 56; ++ objects = { ++ ++/* Begin PBXBuildFile section */ ++ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66162B0EFA380010BFC8 /* AppDelegate.m */; }; ++ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607A66212B0EFA390010BFC8 /* Assets.xcassets */; }; ++ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */; }; ++ 607A66282B0EFA390010BFC8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66272B0EFA390010BFC8 /* main.m */; }; ++ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */; }; ++ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; ++ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; ++ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; ++ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; ++ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */ = {isa = PBXBuildFile; fileRef = 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */; }; ++/* End PBXBuildFile section */ ++ ++/* Begin PBXContainerItemProxy section */ ++ 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */ = { ++ isa = PBXContainerItemProxy; ++ containerPortal = 607A660A2B0EFA380010BFC8 /* Project object */; ++ proxyType = 1; ++ remoteGlobalIDString = 607A66112B0EFA380010BFC8; ++ remoteInfo = iOSTestbed; ++ }; ++/* End PBXContainerItemProxy section */ ++ ++/* Begin PBXCopyFilesBuildPhase section */ ++ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */ = { ++ isa = PBXCopyFilesBuildPhase; ++ buildActionMask = 2147483647; ++ dstPath = ""; ++ dstSubfolderSpec = 10; ++ files = ( ++ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */, ++ ); ++ name = "Embed Frameworks"; ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */ = { ++ isa = PBXCopyFilesBuildPhase; ++ buildActionMask = 2147483647; ++ dstPath = ""; ++ dstSubfolderSpec = 10; ++ files = ( ++ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */, ++ ); ++ name = "Embed Frameworks"; ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++/* End PBXCopyFilesBuildPhase section */ ++ ++/* Begin PBXFileReference section */ ++ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSTestbed.app; sourceTree = BUILT_PRODUCTS_DIR; }; ++ 607A66152B0EFA380010BFC8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; ++ 607A66162B0EFA380010BFC8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; ++ 607A66212B0EFA390010BFC8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; ++ 607A66242B0EFA390010BFC8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; ++ 607A66272B0EFA390010BFC8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; ++ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSTestbedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; ++ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOSTestbedTests.m; sourceTree = ""; }; ++ 607A664A2B0EFB310010BFC8 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; }; ++ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "dylib-Info-template.plist"; sourceTree = ""; }; ++ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "iOSTestbed-Info.plist"; sourceTree = ""; }; ++/* End PBXFileReference section */ ++ ++/* Begin PBXFrameworksBuildPhase section */ ++ 607A660F2B0EFA380010BFC8 /* Frameworks */ = { ++ isa = PBXFrameworksBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++ 607A662A2B0EFA3A0010BFC8 /* Frameworks */ = { ++ isa = PBXFrameworksBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++/* End PBXFrameworksBuildPhase section */ ++ ++/* Begin PBXGroup section */ ++ 607A66092B0EFA380010BFC8 = { ++ isa = PBXGroup; ++ children = ( ++ 607A664A2B0EFB310010BFC8 /* Python.xcframework */, ++ 607A66142B0EFA380010BFC8 /* iOSTestbed */, ++ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */, ++ 607A66132B0EFA380010BFC8 /* Products */, ++ 607A664F2B0EFFE00010BFC8 /* Frameworks */, ++ ); ++ sourceTree = ""; ++ }; ++ 607A66132B0EFA380010BFC8 /* Products */ = { ++ isa = PBXGroup; ++ children = ( ++ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */, ++ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */, ++ ); ++ name = Products; ++ sourceTree = ""; ++ }; ++ 607A66142B0EFA380010BFC8 /* iOSTestbed */ = { ++ isa = PBXGroup; ++ children = ( ++ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */, ++ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */, ++ 607A66152B0EFA380010BFC8 /* AppDelegate.h */, ++ 607A66162B0EFA380010BFC8 /* AppDelegate.m */, ++ 607A66212B0EFA390010BFC8 /* Assets.xcassets */, ++ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */, ++ 607A66272B0EFA390010BFC8 /* main.m */, ++ ); ++ path = iOSTestbed; ++ sourceTree = ""; ++ }; ++ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */ = { ++ isa = PBXGroup; ++ children = ( ++ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */, ++ ); ++ path = iOSTestbedTests; ++ sourceTree = ""; ++ }; ++ 607A664F2B0EFFE00010BFC8 /* Frameworks */ = { ++ isa = PBXGroup; ++ children = ( ++ ); ++ name = Frameworks; ++ sourceTree = ""; ++ }; ++/* End PBXGroup section */ ++ ++/* Begin PBXNativeTarget section */ ++ 607A66112B0EFA380010BFC8 /* iOSTestbed */ = { ++ isa = PBXNativeTarget; ++ buildConfigurationList = 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */; ++ buildPhases = ( ++ 607A660E2B0EFA380010BFC8 /* Sources */, ++ 607A660F2B0EFA380010BFC8 /* Frameworks */, ++ 607A66102B0EFA380010BFC8 /* Resources */, ++ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */, ++ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */, ++ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */, ++ ); ++ buildRules = ( ++ ); ++ dependencies = ( ++ ); ++ name = iOSTestbed; ++ productName = iOSTestbed; ++ productReference = 607A66122B0EFA380010BFC8 /* iOSTestbed.app */; ++ productType = "com.apple.product-type.application"; ++ }; ++ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */ = { ++ isa = PBXNativeTarget; ++ buildConfigurationList = 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */; ++ buildPhases = ( ++ 607A66292B0EFA3A0010BFC8 /* Sources */, ++ 607A662A2B0EFA3A0010BFC8 /* Frameworks */, ++ 607A662B2B0EFA3A0010BFC8 /* Resources */, ++ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */, ++ ); ++ buildRules = ( ++ ); ++ dependencies = ( ++ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */, ++ ); ++ name = iOSTestbedTests; ++ productName = iOSTestbedTests; ++ productReference = 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */; ++ productType = "com.apple.product-type.bundle.unit-test"; ++ }; ++/* End PBXNativeTarget section */ ++ ++/* Begin PBXProject section */ ++ 607A660A2B0EFA380010BFC8 /* Project object */ = { ++ isa = PBXProject; ++ attributes = { ++ BuildIndependentTargetsInParallel = 1; ++ LastUpgradeCheck = 1500; ++ TargetAttributes = { ++ 607A66112B0EFA380010BFC8 = { ++ CreatedOnToolsVersion = 15.0.1; ++ }; ++ 607A662C2B0EFA3A0010BFC8 = { ++ CreatedOnToolsVersion = 15.0.1; ++ TestTargetID = 607A66112B0EFA380010BFC8; ++ }; ++ }; ++ }; ++ buildConfigurationList = 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */; ++ compatibilityVersion = "Xcode 14.0"; ++ developmentRegion = en; ++ hasScannedForEncodings = 0; ++ knownRegions = ( ++ en, ++ Base, ++ ); ++ mainGroup = 607A66092B0EFA380010BFC8; ++ productRefGroup = 607A66132B0EFA380010BFC8 /* Products */; ++ projectDirPath = ""; ++ projectRoot = ""; ++ targets = ( ++ 607A66112B0EFA380010BFC8 /* iOSTestbed */, ++ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */, ++ ); ++ }; ++/* End PBXProject section */ ++ ++/* Begin PBXResourcesBuildPhase section */ ++ 607A66102B0EFA380010BFC8 /* Resources */ = { ++ isa = PBXResourcesBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */, ++ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */, ++ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++ 607A662B2B0EFA3A0010BFC8 /* Resources */ = { ++ isa = PBXResourcesBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++/* End PBXResourcesBuildPhase section */ ++ ++/* Begin PBXShellScriptBuildPhase section */ ++ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */ = { ++ isa = PBXShellScriptBuildPhase; ++ alwaysOutOfDate = 1; ++ buildActionMask = 2147483647; ++ files = ( ++ ); ++ inputFileListPaths = ( ++ ); ++ inputPaths = ( ++ ); ++ name = "Install Target Specific Python Standard Library"; ++ outputFileListPaths = ( ++ ); ++ outputPaths = ( ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ shellPath = /bin/sh; ++ shellScript = "set -e\n\nmkdir -p \"$CODESIGNING_FOLDER_PATH/python/lib\"\nif [ \"$EFFECTIVE_PLATFORM_NAME\" = \"-iphonesimulator\" ]; then\n echo \"Installing Python modules for iOS Simulator\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nelse\n echo \"Installing Python modules for iOS Device\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nfi\n"; ++ }; ++ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */ = { ++ isa = PBXShellScriptBuildPhase; ++ alwaysOutOfDate = 1; ++ buildActionMask = 2147483647; ++ files = ( ++ ); ++ inputFileListPaths = ( ++ ); ++ inputPaths = ( ++ ); ++ name = "Prepare Python Binary Modules"; ++ outputFileListPaths = ( ++ ); ++ outputPaths = ( ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ shellPath = /bin/sh; ++ shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_DYLIB=$2\n\n # The name of the .dylib file\n DYLIB=$(basename \"$FULL_DYLIB\")\n # The name of the .dylib file, relative to the install base\n RELATIVE_DYLIB=${FULL_DYLIB#$CODESIGNING_FOLDER_PATH/$INSTALL_BASE/}\n # The full dotted name of the binary module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $RELATIVE_DYLIB | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_DYLIB\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n defaults write \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\" CFBundleExecutable -string \"$DYLIB\"\n defaults write \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\" CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \n fi\n \n echo \"Installing binary for $RELATIVE_DYLIB\" \n mv \"$FULL_DYLIB\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n}\n\nPYTHON_VER=$(ls -1 \"$CODESIGNING_FOLDER_PATH/python/lib\")\necho \"Install Python $PYTHON_VER standard library dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib python/lib/$PYTHON_VER/lib-dynload \"$FULL_DYLIB\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$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 \"{}\" \\; \n"; ++ }; ++/* End PBXShellScriptBuildPhase section */ ++ ++/* Begin PBXSourcesBuildPhase section */ ++ 607A660E2B0EFA380010BFC8 /* Sources */ = { ++ isa = PBXSourcesBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */, ++ 607A66282B0EFA390010BFC8 /* main.m in Sources */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++ 607A66292B0EFA3A0010BFC8 /* Sources */ = { ++ isa = PBXSourcesBuildPhase; ++ buildActionMask = 2147483647; ++ files = ( ++ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */, ++ ); ++ runOnlyForDeploymentPostprocessing = 0; ++ }; ++/* End PBXSourcesBuildPhase section */ ++ ++/* Begin PBXTargetDependency section */ ++ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */ = { ++ isa = PBXTargetDependency; ++ target = 607A66112B0EFA380010BFC8 /* iOSTestbed */; ++ targetProxy = 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */; ++ }; ++/* End PBXTargetDependency section */ ++ ++/* Begin PBXVariantGroup section */ ++ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */ = { ++ isa = PBXVariantGroup; ++ children = ( ++ 607A66242B0EFA390010BFC8 /* Base */, ++ ); ++ name = LaunchScreen.storyboard; ++ sourceTree = ""; ++ }; ++/* End PBXVariantGroup section */ ++ ++/* Begin XCBuildConfiguration section */ ++ 607A663F2B0EFA3A0010BFC8 /* Debug */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ ALWAYS_SEARCH_USER_PATHS = NO; ++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ++ CLANG_ANALYZER_NONNULL = YES; ++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; ++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; ++ CLANG_ENABLE_MODULES = YES; ++ CLANG_ENABLE_OBJC_ARC = YES; ++ CLANG_ENABLE_OBJC_WEAK = YES; ++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; ++ CLANG_WARN_BOOL_CONVERSION = YES; ++ CLANG_WARN_COMMA = YES; ++ CLANG_WARN_CONSTANT_CONVERSION = YES; ++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; ++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; ++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; ++ CLANG_WARN_EMPTY_BODY = YES; ++ CLANG_WARN_ENUM_CONVERSION = YES; ++ CLANG_WARN_INFINITE_RECURSION = YES; ++ CLANG_WARN_INT_CONVERSION = YES; ++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; ++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; ++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; ++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; ++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; ++ CLANG_WARN_STRICT_PROTOTYPES = YES; ++ CLANG_WARN_SUSPICIOUS_MOVE = YES; ++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; ++ CLANG_WARN_UNREACHABLE_CODE = YES; ++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ++ COPY_PHASE_STRIP = NO; ++ DEBUG_INFORMATION_FORMAT = dwarf; ++ ENABLE_STRICT_OBJC_MSGSEND = YES; ++ ENABLE_TESTABILITY = YES; ++ ENABLE_USER_SCRIPT_SANDBOXING = YES; ++ GCC_C_LANGUAGE_STANDARD = gnu17; ++ GCC_DYNAMIC_NO_PIC = NO; ++ GCC_NO_COMMON_BLOCKS = YES; ++ GCC_OPTIMIZATION_LEVEL = 0; ++ GCC_PREPROCESSOR_DEFINITIONS = ( ++ "DEBUG=1", ++ "$(inherited)", ++ ); ++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; ++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; ++ GCC_WARN_UNDECLARED_SELECTOR = YES; ++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; ++ GCC_WARN_UNUSED_FUNCTION = YES; ++ GCC_WARN_UNUSED_VARIABLE = YES; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; ++ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; ++ MTL_FAST_MATH = YES; ++ ONLY_ACTIVE_ARCH = YES; ++ SDKROOT = iphoneos; ++ }; ++ name = Debug; ++ }; ++ 607A66402B0EFA3A0010BFC8 /* Release */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ ALWAYS_SEARCH_USER_PATHS = NO; ++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; ++ CLANG_ANALYZER_NONNULL = YES; ++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; ++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; ++ CLANG_ENABLE_MODULES = YES; ++ CLANG_ENABLE_OBJC_ARC = YES; ++ CLANG_ENABLE_OBJC_WEAK = YES; ++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; ++ CLANG_WARN_BOOL_CONVERSION = YES; ++ CLANG_WARN_COMMA = YES; ++ CLANG_WARN_CONSTANT_CONVERSION = YES; ++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; ++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; ++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; ++ CLANG_WARN_EMPTY_BODY = YES; ++ CLANG_WARN_ENUM_CONVERSION = YES; ++ CLANG_WARN_INFINITE_RECURSION = YES; ++ CLANG_WARN_INT_CONVERSION = YES; ++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; ++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; ++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; ++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; ++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; ++ CLANG_WARN_STRICT_PROTOTYPES = YES; ++ CLANG_WARN_SUSPICIOUS_MOVE = YES; ++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; ++ CLANG_WARN_UNREACHABLE_CODE = YES; ++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; ++ COPY_PHASE_STRIP = NO; ++ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ++ ENABLE_NS_ASSERTIONS = NO; ++ ENABLE_STRICT_OBJC_MSGSEND = YES; ++ ENABLE_USER_SCRIPT_SANDBOXING = YES; ++ GCC_C_LANGUAGE_STANDARD = gnu17; ++ GCC_NO_COMMON_BLOCKS = YES; ++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; ++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; ++ GCC_WARN_UNDECLARED_SELECTOR = YES; ++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; ++ GCC_WARN_UNUSED_FUNCTION = YES; ++ GCC_WARN_UNUSED_VARIABLE = YES; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; ++ MTL_ENABLE_DEBUG_INFO = NO; ++ MTL_FAST_MATH = YES; ++ SDKROOT = iphoneos; ++ VALIDATE_PRODUCT = YES; ++ }; ++ name = Release; ++ }; ++ 607A66422B0EFA3A0010BFC8 /* Debug */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ++ CODE_SIGN_STYLE = Automatic; ++ CURRENT_PROJECT_VERSION = 1; ++ DEVELOPMENT_TEAM = 3HEZE76D99; ++ ENABLE_USER_SCRIPT_SANDBOXING = NO; ++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; ++ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist"; ++ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; ++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; ++ INFOPLIST_KEY_UIMainStoryboardFile = Main; ++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; ++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ LD_RUNPATH_SEARCH_PATHS = ( ++ "$(inherited)", ++ "@executable_path/Frameworks", ++ ); ++ MARKETING_VERSION = 3.13.0a1; ++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed; ++ PRODUCT_NAME = "$(TARGET_NAME)"; ++ SWIFT_EMIT_LOC_STRINGS = YES; ++ TARGETED_DEVICE_FAMILY = "1,2"; ++ }; ++ name = Debug; ++ }; ++ 607A66432B0EFA3A0010BFC8 /* Release */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ++ CODE_SIGN_STYLE = Automatic; ++ CURRENT_PROJECT_VERSION = 1; ++ DEVELOPMENT_TEAM = 3HEZE76D99; ++ ENABLE_USER_SCRIPT_SANDBOXING = NO; ++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; ++ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist"; ++ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; ++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; ++ INFOPLIST_KEY_UIMainStoryboardFile = Main; ++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; ++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ LD_RUNPATH_SEARCH_PATHS = ( ++ "$(inherited)", ++ "@executable_path/Frameworks", ++ ); ++ MARKETING_VERSION = 3.13.0a1; ++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed; ++ PRODUCT_NAME = "$(TARGET_NAME)"; ++ SWIFT_EMIT_LOC_STRINGS = YES; ++ TARGETED_DEVICE_FAMILY = "1,2"; ++ }; ++ name = Release; ++ }; ++ 607A66452B0EFA3A0010BFC8 /* Debug */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ BUNDLE_LOADER = "$(TEST_HOST)"; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ++ CODE_SIGN_STYLE = Automatic; ++ CURRENT_PROJECT_VERSION = 1; ++ DEVELOPMENT_TEAM = 3HEZE76D99; ++ GENERATE_INFOPLIST_FILE = YES; ++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ MARKETING_VERSION = 1.0; ++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests; ++ PRODUCT_NAME = "$(TARGET_NAME)"; ++ SWIFT_EMIT_LOC_STRINGS = NO; ++ TARGETED_DEVICE_FAMILY = "1,2"; ++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed"; ++ }; ++ name = Debug; ++ }; ++ 607A66462B0EFA3A0010BFC8 /* Release */ = { ++ isa = XCBuildConfiguration; ++ buildSettings = { ++ BUNDLE_LOADER = "$(TEST_HOST)"; ++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; ++ CODE_SIGN_STYLE = Automatic; ++ CURRENT_PROJECT_VERSION = 1; ++ DEVELOPMENT_TEAM = 3HEZE76D99; ++ GENERATE_INFOPLIST_FILE = YES; ++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; ++ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ++ MARKETING_VERSION = 1.0; ++ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests; ++ PRODUCT_NAME = "$(TARGET_NAME)"; ++ SWIFT_EMIT_LOC_STRINGS = NO; ++ TARGETED_DEVICE_FAMILY = "1,2"; ++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed"; ++ }; ++ name = Release; ++ }; ++/* End XCBuildConfiguration section */ ++ ++/* Begin XCConfigurationList section */ ++ 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */ = { ++ isa = XCConfigurationList; ++ buildConfigurations = ( ++ 607A663F2B0EFA3A0010BFC8 /* Debug */, ++ 607A66402B0EFA3A0010BFC8 /* Release */, ++ ); ++ defaultConfigurationIsVisible = 0; ++ defaultConfigurationName = Release; ++ }; ++ 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */ = { ++ isa = XCConfigurationList; ++ buildConfigurations = ( ++ 607A66422B0EFA3A0010BFC8 /* Debug */, ++ 607A66432B0EFA3A0010BFC8 /* Release */, ++ ); ++ defaultConfigurationIsVisible = 0; ++ defaultConfigurationName = Release; ++ }; ++ 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */ = { ++ isa = XCConfigurationList; ++ buildConfigurations = ( ++ 607A66452B0EFA3A0010BFC8 /* Debug */, ++ 607A66462B0EFA3A0010BFC8 /* Release */, ++ ); ++ defaultConfigurationIsVisible = 0; ++ defaultConfigurationName = Release; ++ }; ++/* End XCConfigurationList section */ ++ }; ++ rootObject = 607A660A2B0EFA380010BFC8 /* Project object */; ++} +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/AppDelegate.h +@@ -0,0 +1,14 @@ ++// ++// AppDelegate.h ++// iOSTestbed ++// ++// Created by Russell Keith-Magee on 23/11/2023. ++// ++ ++#import ++ ++@interface AppDelegate : UIResponder ++ ++ ++@end ++ +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/AppDelegate.m +@@ -0,0 +1,22 @@ ++// ++// AppDelegate.m ++// iOSTestbed ++// ++// Created by Russell Keith-Magee on 23/11/2023. ++// ++ ++#import "AppDelegate.h" ++ ++@interface AppDelegate () ++ ++@end ++ ++@implementation AppDelegate ++ ++ ++- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ++ // Override point for customization after application launch. ++ return YES; ++} ++ ++@end +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/Assets.xcassets/AccentColor.colorset/Contents.json +@@ -0,0 +1,11 @@ ++{ ++ "colors" : [ ++ { ++ "idiom" : "universal" ++ } ++ ], ++ "info" : { ++ "author" : "xcode", ++ "version" : 1 ++ } ++} +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/Assets.xcassets/AppIcon.appiconset/Contents.json +@@ -0,0 +1,13 @@ ++{ ++ "images" : [ ++ { ++ "idiom" : "universal", ++ "platform" : "ios", ++ "size" : "1024x1024" ++ } ++ ], ++ "info" : { ++ "author" : "xcode", ++ "version" : 1 ++ } ++} +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/Assets.xcassets/Contents.json +@@ -0,0 +1,6 @@ ++{ ++ "info" : { ++ "author" : "xcode", ++ "version" : 1 ++ } ++} +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/Base.lproj/LaunchScreen.storyboard +@@ -0,0 +1,9 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/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 ++ ++ +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist.in +@@ -0,0 +1,54 @@ ++ ++ ++ ++ ++ CFBundleDevelopmentRegion ++ en ++ CFBundleDisplayName ++ ${PRODUCT_NAME} ++ CFBundleExecutable ++ ${EXECUTABLE_NAME} ++ CFBundleIdentifier ++ org.python.iOSTestbed ++ CFBundleInfoDictionaryVersion ++ 6.0 ++ CFBundleName ++ ${PRODUCT_NAME} ++ CFBundlePackageType ++ APPL ++ CFBundleShortVersionString ++ @VERSION@ ++ CFBundleSignature ++ ???? ++ CFBundleVersion ++ 1 ++ LSRequiresIPhoneOS ++ ++ UIRequiresFullScreen ++ ++ UILaunchStoryboardName ++ Launch Screen ++ UISupportedInterfaceOrientations ++ ++ UIInterfaceOrientationPortrait ++ UIInterfaceOrientationLandscapeLeft ++ UIInterfaceOrientationLandscapeRight ++ ++ UISupportedInterfaceOrientations~ipad ++ ++ UIInterfaceOrientationPortrait ++ UIInterfaceOrientationPortraitUpsideDown ++ UIInterfaceOrientationLandscapeLeft ++ UIInterfaceOrientationLandscapeRight ++ ++ MainModule ++ ios ++ UIApplicationSceneManifest ++ ++ UIApplicationSupportsMultipleScenes ++ ++ UISceneConfigurations ++ ++ ++ ++ +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbed/main.m +@@ -0,0 +1,23 @@ ++// ++// main.m ++// iOSTestbed ++// ++// Created by Russell Keith-Magee on 23/11/2023. ++// ++ ++#import ++#import "AppDelegate.h" ++ ++int main(int argc, char * argv[]) { ++ NSString * appDelegateClassName; ++ @autoreleasepool { ++ // Setup code that might create autoreleased objects goes here. ++ appDelegateClassName = NSStringFromClass([AppDelegate class]); ++ } ++ ++ // iOS doesn't like uncaught signals. ++ signal(SIGPIPE, SIG_IGN); ++ signal(SIGXFSZ, SIG_IGN); ++ ++ return UIApplicationMain(argc, argv, nil, appDelegateClassName); ++} +--- /dev/null ++++ b/Tools/iOSTestbed/iOSTestbedTests/iOSTestbedTests.m +@@ -0,0 +1,188 @@ ++#import ++#import ++ ++@interface iOSTestbedTests : XCTestCase ++ ++@end ++ ++@implementation iOSTestbedTests ++ ++ ++- (void)testPython { ++ // Arguments to pass into the test suite runner. ++ // argv[0] must identify the process; any subsequent arg ++ // will be handled as if it were an argument to `python -m test` ++ const char *argv[] = { ++ "iOSTestbed", // argv[0] is the process that is running. ++ "-uall,-subprocess,-gui,-curses", // Enable most resources ++ "-v", // run in verbose mode so we get test failure information ++ // To run a subset of tests, add the test names below; e.g., ++ // "test_os", ++ // "test_sys", ++ }; ++ ++ // Start a Python interpreter. ++ int success = -1; ++ PyStatus status; ++ PyPreConfig preconfig; ++ PyConfig config; ++ NSString *python_home; ++ NSString *path; ++ wchar_t *wtmp_str; ++ ++ PyObject *app_module; ++ PyObject *module; ++ PyObject *module_attr; ++ PyObject *method_args; ++ PyObject *result; ++ PyObject *exc_type; ++ PyObject *exc_value; ++ PyObject *exc_traceback; ++ PyObject *systemExit_code; ++ ++ NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; ++ ++ // Extract Python version from bundle ++ NSString *py_version_string = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; ++ ++ // Generate an isolated Python configuration. ++ NSLog(@"Configuring isolated Python %@...", py_version_string); ++ PyPreConfig_InitIsolatedConfig(&preconfig); ++ PyConfig_InitIsolatedConfig(&config); ++ ++ // Configure the Python interpreter: ++ // Enforce UTF-8 encoding for stderr, stdout, file-system encoding and locale. ++ // See https://docs.python.org/3/library/os.html#python-utf-8-mode. ++ preconfig.utf8_mode = 1; ++ // Don't buffer stdio. We want output to appears in the log immediately ++ config.buffered_stdio = 0; ++ // Don't write bytecode; we can't modify the app bundle ++ // after it has been signed. ++ config.write_bytecode = 0; ++ // Disable the user site module ++ config.site_import = 0; ++ // For debugging - enable verbose mode. ++ // config.verbose = 1; ++ ++ NSLog(@"Pre-initializing Python runtime..."); ++ status = Py_PreInitialize(&preconfig); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to pre-initialize Python interpreter: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ ++ // Set the home for the Python interpreter ++ python_home = [NSString stringWithFormat:@"%@/python", resourcePath, nil]; ++ NSLog(@"PythonHome: %@", python_home); ++ wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL); ++ status = PyConfig_SetString(&config, &config.home, wtmp_str); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to set PYTHONHOME: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ PyMem_RawFree(wtmp_str); ++ ++ // Set the stdlib location for the Python interpreter ++ path = [NSString stringWithFormat:@"%@/python/lib/python%@", resourcePath, py_version_string, nil]; ++ NSLog(@"Stdlib dir: %@", path); ++ wtmp_str = Py_DecodeLocale([path UTF8String], NULL); ++ status = PyConfig_SetString(&config, &config.stdlib_dir, wtmp_str); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to set stdlib dir: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ PyMem_RawFree(wtmp_str); ++ ++ // Read the site config ++ status = PyConfig_Read(&config); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to read site config: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ ++ NSLog(@"Configure argc/argv..."); ++ status = PyConfig_SetBytesArgv(&config, sizeof(argv) / sizeof(char *), (char**) argv); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to configure argc/argv: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ ++ NSLog(@"Initializing Python runtime..."); ++ status = Py_InitializeFromConfig(&config); ++ if (PyStatus_Exception(status)) { ++ XCTFail(@"Unable to initialize Python interpreter: %s", status.err_msg); ++ PyConfig_Clear(&config); ++ return; ++ } ++ ++ // Start the test suite. ++ // ++ // From here to Py_ObjectCall(runmodule...) is effectively ++ // a copy of Py_RunMain() (and, more specifically, the ++ // pymain_run_module() method); we need to re-implement it ++ // because we need to be able to inspect the error state of ++ // the interpreter, not just the return code of the module. ++ NSLog(@"Running CPython test suite"); ++ module = PyImport_ImportModule("runpy"); ++ if (module == NULL) { ++ XCTFail(@"Could not import runpy module"); ++ } ++ ++ module_attr = PyObject_GetAttrString(module, "_run_module_as_main"); ++ if (module_attr == NULL) { ++ XCTFail(@"Could not access runpy._run_module_as_main"); ++ } ++ ++ app_module = PyUnicode_FromString("test"); ++ if (app_module == NULL) { ++ XCTFail(@"Could not convert module name to unicode"); ++ } ++ ++ method_args = Py_BuildValue("(Oi)", app_module, 0); ++ if (method_args == NULL) { ++ XCTFail(@"Could not create arguments for runpy._run_module_as_main"); ++ } ++ ++ // Print a separator to differentiate Python startup logs from app logs ++ NSLog(@"---------------------------------------------------------------------------"); ++ ++ // Invoke the app module ++ result = PyObject_Call(module_attr, method_args, NULL); ++ ++ NSLog(@"---------------------------------------------------------------------------"); ++ ++ // The test method doesn't return an object of any interest; ++ // but if the call returns NULL, there's been a problem. ++ if (result == NULL) { ++ // Retrieve the current error state of the interpreter. ++ PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); ++ PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback); ++ ++ if (exc_traceback == NULL) { ++ XCTFail(@"Could not retrieve traceback"); ++ } ++ ++ if (PyErr_GivenExceptionMatches(exc_value, PyExc_SystemExit)) { ++ systemExit_code = PyObject_GetAttrString(exc_value, "code"); ++ if (systemExit_code == NULL) { ++ XCTFail(@"Could not determine exit code"); ++ } ++ else { ++ success = (int) PyLong_AsLong(systemExit_code); ++ XCTAssertEqual(success, 0, @"Python test suite did not pass"); ++ } ++ } else { ++ PyErr_DisplayException(exc_value); ++ XCTFail(@"Test suite generated exception"); ++ } ++ } ++ Py_Finalize(); ++} ++ ++ ++@end diff --git a/config.sub b/config.sub index d74fb6deac..09ebc4287c 100755 --- a/config.sub @@ -1842,7 +3323,7 @@ index d74fb6deac..09ebc4287c 100755 # Blank kernel with real OS is always fine. ;; diff --git a/configure b/configure -index c87f518382..ad0cd39350 100755 +index c87f518382..0e24298436 100755 --- a/configure +++ b/configure @@ -963,10 +963,13 @@ @@ -1980,7 +3461,7 @@ index c87f518382..ad0cd39350 100755 if test "x${prefix}" = "xNONE"; then FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" else -@@ -4128,65 +4218,112 @@ +@@ -4128,65 +4218,114 @@ PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR FRAMEWORKINSTALLFIRST="frameworkinstallstructure" FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure " @@ -2018,12 +3499,7 @@ index c87f518382..ad0cd39350 100755 - /Library*) - FRAMEWORKINSTALLAPPSPREFIX="/Applications" - ;; -+ ;; -+ tvOS) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ac_config_files="$ac_config_files Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist" - */Library/Frameworks) - MDIR="`dirname "${enableval}"`" @@ -2040,27 +3516,34 @@ index c87f518382..ad0cd39350 100755 - FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" - fi - ;; -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=tvOS/Resources ++ ;; ++ tvOS) : ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" - *) - FRAMEWORKINSTALLAPPSPREFIX="/Applications" - ;; - esac -+ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources - prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION ++ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" + +- # Add files for Mac specific code to the list of output +- # files: +- ac_config_files="$ac_config_files Mac/Makefile" + ;; + watchOS) : + FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" + FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" + FRAMEWORKPYTHONW= + INSTALLTARGETS="libinstall inclinstall sharedinstall" - -- # Add files for Mac specific code to the list of output -- # files: -- ac_config_files="$ac_config_files Mac/Makefile" ++ + prefix=$PYTHONFRAMEWORKPREFIX + PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" + RESSRCDIR=watchOS/Resources @@ -2140,7 +3623,7 @@ index c87f518382..ad0cd39350 100755 else $as_nop -@@ -4194,6 +4331,8 @@ +@@ -4194,6 +4333,8 @@ PYTHONFRAMEWORKDIR=no-framework PYTHONFRAMEWORKPREFIX= PYTHONFRAMEWORKINSTALLDIR= @@ -2149,15 +3632,15 @@ index c87f518382..ad0cd39350 100755 FRAMEWORKINSTALLFIRST= FRAMEWORKINSTALLLAST= FRAMEWORKALTINSTALLFIRST= -@@ -4223,79 +4362,11 @@ +@@ -4223,79 +4364,11 @@ -printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h - - +- +- -# Set name for machine-dependent library files - +- -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5 -printf %s "checking MACHDEP... " >&6; } -if test -z "$MACHDEP" @@ -2206,7 +3689,7 @@ index c87f518382..ad0cd39350 100755 - ac_md_release=`echo $ac_sys_release | - tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'` - MACHDEP="$ac_md_system$ac_md_release" -- + - case $MACHDEP in - aix*) MACHDEP="aix";; - linux*) MACHDEP="linux";; @@ -2214,12 +3697,12 @@ index c87f518382..ad0cd39350 100755 - darwin*) MACHDEP="darwin";; - '') MACHDEP="unknown";; - esac -- + - if test "$ac_sys_system" = "SunOS"; then - # For Solaris, there isn't an OS version specific macro defined - # in most compilers, so we define one here. - SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\(0-9\)$!.0\1!g' | tr -d '.'` -- + -printf "%s\n" "#define Py_SUNOS_VERSION $SUNOS_VERSION" >>confdefs.h +printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h @@ -2230,7 +3713,7 @@ index c87f518382..ad0cd39350 100755 if test "$cross_compiling" = yes; then -@@ -4303,27 +4374,102 @@ +@@ -4303,27 +4376,102 @@ *-*-linux*) case "$host_cpu" in arm*) @@ -2339,7 +3822,7 @@ index c87f518382..ad0cd39350 100755 fi # Some systems cannot stand _XOPEN_SOURCE being defined at all; they -@@ -4390,6 +4536,13 @@ +@@ -4390,6 +4538,13 @@ define_xopen_source=no;; Darwin/[12][0-9].*) define_xopen_source=no;; @@ -2353,7 +3836,7 @@ index c87f518382..ad0cd39350 100755 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -4484,6 +4637,32 @@ +@@ -4484,6 +4639,32 @@ ;; esac @@ -2386,7 +3869,7 @@ index c87f518382..ad0cd39350 100755 if test "$ac_sys_system" = "Darwin" then # Extract the first word of "xcrun", so it can be a program name with args. -@@ -6746,6 +6925,12 @@ +@@ -6746,6 +6927,12 @@ case $ac_sys_system in #( Darwin*) : MULTIARCH="" ;; #( @@ -2399,7 +3882,7 @@ index c87f518382..ad0cd39350 100755 FreeBSD*) : MULTIARCH="" ;; #( *) : -@@ -6753,8 +6938,6 @@ +@@ -6753,8 +6940,6 @@ ;; esac @@ -2408,7 +3891,7 @@ index c87f518382..ad0cd39350 100755 if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then if test x$PLATFORM_TRIPLET != x$MULTIARCH; then -@@ -6764,6 +6947,16 @@ +@@ -6764,6 +6949,16 @@ MULTIARCH=$PLATFORM_TRIPLET fi @@ -2425,7 +3908,7 @@ index c87f518382..ad0cd39350 100755 if test x$MULTIARCH != x; then MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" -@@ -6807,6 +7000,12 @@ +@@ -6807,6 +7002,12 @@ PY_SUPPORT_TIER=3 ;; #( x86_64-*-freebsd*/clang) : PY_SUPPORT_TIER=3 ;; #( @@ -2438,7 +3921,7 @@ index c87f518382..ad0cd39350 100755 *) : PY_SUPPORT_TIER=0 ;; -@@ -7257,17 +7456,23 @@ +@@ -7257,17 +7458,23 @@ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDLIBRARY" >&5 printf %s "checking LDLIBRARY... " >&6; } @@ -2466,7 +3949,7 @@ index c87f518382..ad0cd39350 100755 else BLDLIBRARY='$(LDLIBRARY)' fi -@@ -7317,12 +7522,16 @@ +@@ -7317,12 +7524,16 @@ ;; Darwin*) LDLIBRARY='libpython$(LDVERSION).dylib' @@ -2487,7 +3970,7 @@ index c87f518382..ad0cd39350 100755 ;; esac -@@ -12515,6 +12724,7 @@ +@@ -12515,6 +12726,7 @@ esac ;; CYGWIN*) SHLIB_SUFFIX=.dll;; @@ -2495,7 +3978,7 @@ index c87f518382..ad0cd39350 100755 *) SHLIB_SUFFIX=.so;; esac fi -@@ -12597,6 +12807,11 @@ +@@ -12597,6 +12809,11 @@ BLDSHARED="$LDSHARED" fi ;; @@ -2507,7 +3990,7 @@ index c87f518382..ad0cd39350 100755 Emscripten|WASI) LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; -@@ -12750,6 +12965,24 @@ +@@ -12750,6 +12967,24 @@ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' fi LINKFORSHARED="$LINKFORSHARED";; @@ -2532,7 +4015,7 @@ index c87f518382..ad0cd39350 100755 OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";; SCO_SV*) LINKFORSHARED="-Wl,-Bexport";; ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";; -@@ -14138,6 +14371,10 @@ +@@ -14138,6 +14373,10 @@ ctypes_malloc_closure=yes ;; #( @@ -2543,7 +4026,7 @@ index c87f518382..ad0cd39350 100755 sunos5) : as_fn_append LIBFFI_LIBS " -mimpure-text" ;; #( -@@ -23651,7 +23888,7 @@ +@@ -23651,7 +23890,7 @@ printf "%s\n" "$ABIFLAGS" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking SOABI" >&5 printf %s "checking SOABI... " >&6; } @@ -2552,7 +4035,7 @@ index c87f518382..ad0cd39350 100755 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SOABI" >&5 printf "%s\n" "$SOABI" >&6; } -@@ -23660,7 +23897,7 @@ +@@ -23660,7 +23899,7 @@ if test "$Py_DEBUG" = 'true'; then # Similar to SOABI but remove "d" flag from ABIFLAGS @@ -2561,7 +4044,7 @@ index c87f518382..ad0cd39350 100755 printf "%s\n" "#define ALT_SOABI \"${ALT_SOABI}\"" >>confdefs.h -@@ -27949,6 +28186,28 @@ +@@ -27949,6 +28188,28 @@ ;; #( Darwin) : ;; #( @@ -2590,11 +4073,12 @@ index c87f518382..ad0cd39350 100755 CYGWIN*) : -@@ -31528,10 +31787,13 @@ +@@ -31528,10 +31789,14 @@ do case $ac_config_target in "pyconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS pyconfig.h" ;; + "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; ++ "Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist") CONFIG_FILES="$CONFIG_FILES Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist" ;; + "tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES tvOS/Resources/Info.plist" ;; + "watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES watchOS/Resources/Info.plist" ;; "Mac/Makefile") CONFIG_FILES="$CONFIG_FILES Mac/Makefile" ;; @@ -2606,7 +4090,7 @@ index c87f518382..ad0cd39350 100755 "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 cd69f0ede5..9306e1270b 100644 +index cd69f0ede5..0a3321d9f5 100644 --- a/configure.ac +++ b/configure.ac @@ -310,6 +310,83 @@ @@ -2709,7 +4193,7 @@ index cd69f0ede5..9306e1270b 100644 if test "x${prefix}" = "xNONE"; then FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" else -@@ -444,66 +525,112 @@ +@@ -444,66 +525,113 @@ PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR FRAMEWORKINSTALLFIRST="frameworkinstallstructure" FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure " @@ -2743,6 +4227,7 @@ index cd69f0ede5..9306e1270b 100644 - fi - ;; + AC_CONFIG_FILES([iOS/Resources/Info.plist]) ++ AC_CONFIG_FILES([Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist]) + ;; + tvOS) : + FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" @@ -2869,7 +4354,7 @@ index cd69f0ede5..9306e1270b 100644 FRAMEWORKINSTALLFIRST= FRAMEWORKINSTALLLAST= FRAMEWORKALTINSTALLFIRST= -@@ -522,6 +649,8 @@ +@@ -522,6 +650,8 @@ AC_SUBST([PYTHONFRAMEWORKDIR]) AC_SUBST([PYTHONFRAMEWORKPREFIX]) AC_SUBST([PYTHONFRAMEWORKINSTALLDIR]) @@ -2878,7 +4363,7 @@ index cd69f0ede5..9306e1270b 100644 AC_SUBST([FRAMEWORKINSTALLFIRST]) AC_SUBST([FRAMEWORKINSTALLLAST]) AC_SUBST([FRAMEWORKALTINSTALLFIRST]) -@@ -529,105 +658,113 @@ +@@ -529,105 +659,113 @@ AC_SUBST([FRAMEWORKPYTHONW]) AC_SUBST([FRAMEWORKUNIXTOOLSPREFIX]) AC_SUBST([FRAMEWORKINSTALLAPPSPREFIX]) @@ -3066,7 +4551,7 @@ index cd69f0ede5..9306e1270b 100644 fi # Some systems cannot stand _XOPEN_SOURCE being defined at all; they -@@ -693,6 +830,13 @@ +@@ -693,6 +831,13 @@ define_xopen_source=no;; Darwin/@<:@[12]@:>@@<:@0-9@:>@.*) define_xopen_source=no;; @@ -3080,7 +4565,7 @@ index cd69f0ede5..9306e1270b 100644 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -783,6 +927,26 @@ +@@ -783,6 +928,26 @@ ], ) @@ -3107,7 +4592,7 @@ index cd69f0ede5..9306e1270b 100644 if test "$ac_sys_system" = "Darwin" then dnl look for SDKROOT -@@ -941,11 +1105,13 @@ +@@ -941,11 +1106,13 @@ AC_MSG_CHECKING([for multiarch]) AS_CASE([$ac_sys_system], [Darwin*], [MULTIARCH=""], @@ -3122,7 +4607,7 @@ index cd69f0ede5..9306e1270b 100644 if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then if test x$PLATFORM_TRIPLET != x$MULTIARCH; then -@@ -955,6 +1121,12 @@ +@@ -955,6 +1122,12 @@ MULTIARCH=$PLATFORM_TRIPLET fi AC_SUBST([PLATFORM_TRIPLET]) @@ -3135,7 +4620,7 @@ index cd69f0ede5..9306e1270b 100644 if test x$MULTIARCH != x; then MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" -@@ -985,6 +1157,9 @@ +@@ -985,6 +1158,9 @@ [wasm32-unknown-emscripten/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly Emscripten [wasm32-unknown-wasi/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly System Interface [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64 @@ -3145,7 +4630,7 @@ index cd69f0ede5..9306e1270b 100644 [PY_SUPPORT_TIER=0] ) -@@ -1298,17 +1473,23 @@ +@@ -1298,17 +1474,23 @@ AC_MSG_CHECKING([LDLIBRARY]) @@ -3173,7 +4658,7 @@ index cd69f0ede5..9306e1270b 100644 else BLDLIBRARY='$(LDLIBRARY)' fi -@@ -1357,12 +1538,16 @@ +@@ -1357,12 +1539,16 @@ ;; Darwin*) LDLIBRARY='libpython$(LDVERSION).dylib' @@ -3194,7 +4679,7 @@ index cd69f0ede5..9306e1270b 100644 ;; esac -@@ -3085,6 +3270,7 @@ +@@ -3085,6 +3271,7 @@ esac ;; CYGWIN*) SHLIB_SUFFIX=.dll;; @@ -3202,7 +4687,7 @@ index cd69f0ede5..9306e1270b 100644 *) SHLIB_SUFFIX=.so;; esac fi -@@ -3165,6 +3351,11 @@ +@@ -3165,6 +3352,11 @@ BLDSHARED="$LDSHARED" fi ;; @@ -3214,7 +4699,7 @@ index cd69f0ede5..9306e1270b 100644 Emscripten|WASI) LDSHARED='$(CC) -shared' LDCXXSHARED='$(CXX) -shared';; -@@ -3309,6 +3500,24 @@ +@@ -3309,6 +3501,24 @@ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' fi LINKFORSHARED="$LINKFORSHARED";; @@ -3239,7 +4724,7 @@ index cd69f0ede5..9306e1270b 100644 OpenUNIX*|UnixWare*) LINKFORSHARED="-Wl,-Bexport";; SCO_SV*) LINKFORSHARED="-Wl,-Bexport";; ReliantUNIX*) LINKFORSHARED="-W1 -Blargedynsym";; -@@ -3682,6 +3891,9 @@ +@@ -3682,6 +3892,9 @@ dnl when do we need USING_APPLE_OS_LIBFFI? ctypes_malloc_closure=yes ], @@ -3249,7 +4734,7 @@ index cd69f0ede5..9306e1270b 100644 [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])] ) AS_VAR_IF([ctypes_malloc_closure], [yes], [ -@@ -5714,7 +5926,7 @@ +@@ -5714,7 +5927,7 @@ AC_MSG_CHECKING([ABIFLAGS]) AC_MSG_RESULT([$ABIFLAGS]) AC_MSG_CHECKING([SOABI]) @@ -3258,7 +4743,7 @@ index cd69f0ede5..9306e1270b 100644 AC_MSG_RESULT([$SOABI]) # Release build, debug build (Py_DEBUG), and trace refs build (Py_TRACE_REFS) -@@ -5722,7 +5934,7 @@ +@@ -5722,7 +5935,7 @@ if test "$Py_DEBUG" = 'true'; then # Similar to SOABI but remove "d" flag from ABIFLAGS AC_SUBST([ALT_SOABI]) @@ -3267,7 +4752,7 @@ index cd69f0ede5..9306e1270b 100644 AC_DEFINE_UNQUOTED([ALT_SOABI], ["${ALT_SOABI}"], [Alternative SOABI used in debug build to load C extensions built in release mode]) fi -@@ -7068,6 +7280,29 @@ +@@ -7068,6 +7281,29 @@ [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])], dnl The _scproxy module is available on macOS [Darwin], [], @@ -3299,7 +4784,7 @@ index cd69f0ede5..9306e1270b 100644 [FreeBSD*], [PY_STDLIB_MOD_SET_NA([_scproxy])], --- /dev/null +++ b/iOS/README.rst -@@ -0,0 +1,107 @@ +@@ -0,0 +1,354 @@ +==================== +Python on iOS README +==================== @@ -3310,12 +4795,19 @@ index cd69f0ede5..9306e1270b 100644 +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, on the -+most recently released macOS. ++recommended that you use the most recent stable release of Xcode, on the most ++recently released macOS. + +iOS specific arguments to configure +=================================== @@ -3329,9 +4821,8 @@ index cd69f0ede5..9306e1270b 100644 + + Specify the name for the python framework, defaults to ``Python``. + -+ -+Building and using Python on iOS -+================================ ++Building Python on iOS ++====================== + +ABIs and Architectures +---------------------- @@ -3339,46 +4830,79 @@ index cd69f0ede5..9306e1270b 100644 +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. ++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 support ed architecture on physical devices - ARM64. ++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.) ++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. ++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. + +How do I build Python for iOS? +------------------------------ + -+The Python build system will build a ``Python.framework`` that supports a -+*single* ABI with a *single* architecture. If you want to use Python in an iOS -+project, you need to: ++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. + -+1. Produce multiple ``Python.framework`` builds, one for each ABI and architecture; -+2. Merge the binaries for each architecture on a given ABI into a single "fat" binary; -+3. Merge the "fat" frameworks for each ABI into a single XCframework. ++If you want to use Python in a real iOS project, you need to: ++ ++1. Produce multiple ``Python.framework`` builds, one for each ABI and ++ architecture; ++2. Merge the binaries for each architecture on a given ABI into a single "fat" ++ binary. This can be done using the ``lipo`` tool, provide by Xcode: ++ ++ $ lipo -create -output module.dylib path/to/x86_64/module.dylib path/to/arm64/module.dylib ++ ++3. Merge the headers for each architecture. The header files will be identical on each platform, ++ 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 into the merged headers folder. ++ This will allow the two Python architectures to share header files. ++4. Merge the "fat" frameworks for each ABI into a single XCframework. + +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:: + -+The build also requires the use of cross-compilation. The commands for building -+Python for iOS will look somethign like:: -+ ++ $ export PATH=`pwd`/iOS/Resources/bin:$PATH + $ ./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 \ ++ --host=aarch64-apple-ios-simulator \ + --build=aarch64-apple-darwin \ -+ --with-build-python=/path/to/python.exe ++ --with-build-python=/path/to/python.exe \ ++ ac_cv_file__dev_ptmx=no \ ++ ac_cv_file__dev_ptc=no + $ 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; howver, ``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. ++ +* ``/path/to/install`` is the location where the final Python.framework will be + output. + @@ -3405,8 +4929,216 @@ index cd69f0ede5..9306e1270b 100644 + you need to provide an external Python interpreter. This interpreter must be + the version as the Python that is being compiled. + -+Using a framework-based Python on iOS -+===================================== ++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). ++ ++How do I test 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. ++ ++How do I debug 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. ++ ++Using Python on iOS ++=================== ++ ++To add Python to an iOS Xcode project: ++ ++1. Build Python for each architecture that you want to support. 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`. This will ++ produce a ``Python.framework``, plus a ``bin`` and ``lib`` folder in the same ++ directory as the ``Python.framework``. ++ ++2. Create an XCframework from the individual single-platform frameworks. The ++ basic structure can be compiled from the individual ``Python.framework`` ++ outputs:: ++ ++ 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-simulator ++ cp path/to/iphonesimulator/lib Python.xcframework/ios-arm64-simulator ++ ++ Note that the name of the architecture-specific slice for the simulator will ++ depend on the CPU architecture that you build. ++ ++3. Add symbolic links to "common" platform names for each slice:: ++ ++ ln -si ios-arm64 Python.xcframework/iphoneos ++ ln -si ios-arm64-simulator Python.xcframework/iphonesimulator ++ ++4. 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. ++ ++5. Drag the ``iOS/Resources/dylib-Info-template.plist`` file into your project, ++ and ensure it is associated with the app target. ++ ++6. Select the app target by selecting the root node of your Xcode project, then ++ the target name in the sidebar that appears. ++ ++7. In the "General" settings, under "Frameworks, Libraries and Embedded ++ Content", Add ``Python.xcframework``, with "Embed & Sign" selected. ++ ++8. In the "Build Settings" tab, modify the following: ++ ++ - Build Options ++ * User script sandboxing: No ++ - 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 ++ ++9. 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 ++ ++10. 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" ++ defaults write "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" CFBundleExecutable -string "$DYLIB" ++ defaults write "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" ++ 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 "{}" \; ++ ++11. 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. --- /dev/null +++ b/iOS/Resources/Info.plist.in @@ -0,0 +1,34 @@ @@ -3435,7 +5167,7 @@ index cd69f0ede5..9306e1270b 100644 + CFBundleSignature + ???? + CFBundleVersion -+ %VERSION% ++ 1 + CFBundleSupportedPlatforms + + iPhoneOS @@ -3490,6 +5222,45 @@ index cd69f0ede5..9306e1270b 100644 +#!/bin/bash +xcrun --sdk iphonesimulator clang -target x86_64-apple-ios-simulator -E $@ --- /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 ++ ++ +--- /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 +--- /dev/null +++ b/tvOS/README.rst @@ -0,0 +1,108 @@ +===================== @@ -3683,6 +5454,45 @@ index cd69f0ede5..9306e1270b 100644 +#!/bin/bash +xcrun --sdk appletvsimulator clang -target x86_64-apple-tvos-simulator -E $@ --- /dev/null ++++ b/tvOS/Resources/dylib-Info-template.plist +@@ -0,0 +1,26 @@ ++ ++ ++ ++ ++ CFBundleDevelopmentRegion ++ en ++ CFBundleExecutable ++ ++ CFBundleIdentifier ++ ++ CFBundleInfoDictionaryVersion ++ 6.0 ++ CFBundlePackageType ++ APPL ++ CFBundleShortVersionString ++ 1.0 ++ CFBundleSupportedPlatforms ++ ++ tvOS ++ ++ MinimumOSVersion ++ 9.0 ++ CFBundleVersion ++ 1 ++ ++ +--- /dev/null ++++ b/tvOS/Resources/pyconfig.h +@@ -0,0 +1,7 @@ ++#ifdef __arm64__ ++#include "pyconfig-arm64.h" ++#endif ++ ++#ifdef __x86_64__ ++#include "pyconfig-x86_64.h" ++#endif +--- /dev/null +++ b/watchOS/README.rst @@ -0,0 +1,108 @@ +======================== @@ -3875,3 +5685,46 @@ index cd69f0ede5..9306e1270b 100644 @@ -0,0 +1,2 @@ +#!/bin/bash +xcrun --sdk watchsimulator clang -target x86_64-apple-watchos-simulator -E $@ +--- /dev/null ++++ b/watchOS/Resources/dylib-Info-template.plist +@@ -0,0 +1,26 @@ ++ ++ ++ ++ ++ CFBundleDevelopmentRegion ++ en ++ CFBundleExecutable ++ ++ CFBundleIdentifier ++ ++ CFBundleInfoDictionaryVersion ++ 6.0 ++ CFBundlePackageType ++ APPL ++ CFBundleShortVersionString ++ 1.0 ++ CFBundleSupportedPlatforms ++ ++ watchOS ++ ++ MinimumOSVersion ++ 4.0 ++ CFBundleVersion ++ 1 ++ ++ +--- /dev/null ++++ b/watchOS/Resources/pyconfig.h +@@ -0,0 +1,11 @@ ++#ifdef __arm64__ ++# ifdef __LP64__ ++#include "pyconfig-arm64.h" ++# else ++#include "pyconfig-arm64_32.h" ++# endif ++#endif ++ ++#ifdef __x86_64__ ++#include "pyconfig-x86_64.h" ++#endif diff --git a/patch/Python/pyconfig-iOS.h b/patch/Python/pyconfig-iOS.h deleted file mode 100644 index 4acff2c..0000000 --- a/patch/Python/pyconfig-iOS.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifdef __arm64__ -#include "pyconfig-arm64.h" -#endif - -#ifdef __x86_64__ -#include "pyconfig-x86_64.h" -#endif diff --git a/patch/Python/pyconfig-tvOS.h b/patch/Python/pyconfig-tvOS.h deleted file mode 100644 index d4afe05..0000000 --- a/patch/Python/pyconfig-tvOS.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifdef __arm64__ -#include "pyconfig-arm64.h" -#endif - -#ifdef __x86_64__ -#include "pyconfig-x86_64.h" -#endif \ No newline at end of file diff --git a/patch/Python/pyconfig-watchOS.h b/patch/Python/pyconfig-watchOS.h deleted file mode 100644 index f842b98..0000000 --- a/patch/Python/pyconfig-watchOS.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifdef __arm64__ -# ifdef __LP64__ -#include "pyconfig-arm64.h" -# else -#include "pyconfig-arm64_32.h" -# endif -#endif - -#ifdef __x86_64__ -#include "pyconfig-x86_64.h" -#endif diff --git a/patch/Python/test.exclude b/patch/Python/test.exclude deleted file mode 100644 index add994a..0000000 --- a/patch/Python/test.exclude +++ /dev/null @@ -1,7 +0,0 @@ -# This is a list of Python standard library path patterns -# we exclude from the embedded device Python-Apple-support test tarballs. -# It is used by `tar -X` during the Makefile build. -# -# Remove pyc files. These take up space, but since most stdlib modules are -# never imported by user code, they mostly have no value. -*/__pycache__ \ No newline at end of file From c53d7bd328256ed511c1fdbbc09641d042f86d95 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 26 Jul 2024 08:44:16 +0800 Subject: [PATCH 11/13] Update to final state of PEP730 patches. --- Makefile | 66 +- README.rst | 59 +- USAGE.md | 174 +- patch/Python/Python.patch | 6374 ++++++---------------------- patch/Python/release.macOS.exclude | 14 +- patch/make-macho-standalone.py | 10 - patch/make-relocatable.sh | 27 + patch/make-xcrun-alias | 10 - 8 files changed, 1436 insertions(+), 5298 deletions(-) delete mode 100644 patch/make-macho-standalone.py create mode 100755 patch/make-relocatable.sh delete mode 100755 patch/make-xcrun-alias diff --git a/Makefile b/Makefile index 59bea0a..5d1c4b7 100644 --- a/Makefile +++ b/Makefile @@ -15,16 +15,17 @@ BUILD_NUMBER=custom # PYTHON_VERSION is the full version number (e.g., 3.10.0b3) # PYTHON_MICRO_VERSION is the full version number, without any alpha/beta/rc suffix. (e.g., 3.10.0) # PYTHON_VER is the major/minor version (e.g., 3.10) -PYTHON_VERSION=3.13.0a1 +PYTHON_VERSION=3.13.0b4 PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+") PYTHON_VER=$(basename $(PYTHON_VERSION)) # The binary releases of dependencies, published at: # https://github.com/beeware/cpython-apple-source-deps/releases BZIP2_VERSION=1.0.8-1 -XZ_VERSION=5.4.4-1 -OPENSSL_VERSION=3.0.12-1 -LIBFFI_VERSION=3.4.4-1 +MPDECIMAL_VERSION=4.0.0-1 +OPENSSL_VERSION=3.0.14-1 +XZ_VERSION=5.4.7-1 +LIBFFI_VERSION=3.4.6-1 # Supported OS OS_LIST=macOS iOS tvOS watchOS @@ -37,17 +38,15 @@ VERSION_MIN-macOS=11.0 # iOS targets TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64 -VERSION_MIN-iOS=12.0 +VERSION_MIN-iOS=13.0 # tvOS targets TARGETS-tvOS=appletvsimulator.x86_64 appletvsimulator.arm64 appletvos.arm64 -VERSION_MIN-tvOS=9.0 -PYTHON_CONFIGURE-tvOS=ac_cv_func_sigaltstack=no +VERSION_MIN-tvOS=12.0 # watchOS targets TARGETS-watchOS=watchsimulator.x86_64 watchsimulator.arm64 watchos.arm64_32 VERSION_MIN-watchOS=4.0 -PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no # The architecture of the machine doing the build HOST_ARCH=$(shell uname -m) @@ -82,7 +81,7 @@ update-patch: # call if [ -z "$(PYTHON_REPO_DIR)" ]; then echo "\n\nPYTHON_REPO_DIR must be set to the root of your Python github checkout\n\n"; fi cd $(PYTHON_REPO_DIR) && \ - git diff -D v$(PYTHON_VERSION) $(PYTHON_VER) \ + git diff -D v$(PYTHON_VERSION) $(PYTHON_VER)-patched \ | PATH="/usr/local/bin:/opt/homebrew/bin:$(PATH)" filterdiff \ -X $(PROJECT_DIR)/patch/Python/diff.exclude -p 1 --clean \ > $(PROJECT_DIR)/patch/Python/Python.patch @@ -122,8 +121,6 @@ OS_LOWER-$(target)=$(shell echo $(os) | tr '[:upper:]' '[:lower:]') SDK-$(target)=$$(basename $(target)) ARCH-$(target)=$$(subst .,,$$(suffix $(target))) -WHEEL_TAG-$(target)=py3-none-$$(shell echo $$(OS_LOWER-$(target))_$$(VERSION_MIN-$(os))_$(target) | sed "s/\./_/g") - ifneq ($(os),macOS) ifeq ($$(findstring simulator,$$(SDK-$(target))),) TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))$$(VERSION_MIN-$(os)) @@ -176,6 +173,26 @@ $$(XZ_LIB-$(target)): downloads/xz-$(XZ_VERSION)-$(target).tar.gz # Ensure the target is marked as clean. touch $$(XZ_LIB-$(target)) +########################################################################### +# Target: mpdecimal +########################################################################### + +MPDECIMAL_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/mpdecimal-$(MPDECIMAL_VERSION) +MPDECIMAL_LIB-$(target)=$$(MPDECIMAL_INSTALL-$(target))/lib/libmpdec.a + +downloads/mpdecimal-$(MPDECIMAL_VERSION)-$(target).tar.gz: + @echo ">>> Download mpdecimal for $(target)" + mkdir -p downloads + curl $(CURL_FLAGS) -o $$@ \ + https://github.com/beeware/cpython-apple-source-deps/releases/download/mpdecimal-$(MPDECIMAL_VERSION)/mpdecimal-$(MPDECIMAL_VERSION)-$(target).tar.gz + +$$(MPDECIMAL_LIB-$(target)): downloads/mpdecimal-$(MPDECIMAL_VERSION)-$(target).tar.gz + @echo ">>> Install mpdecimal for $(target)" + mkdir -p $$(MPDECIMAL_INSTALL-$(target)) + cd $$(MPDECIMAL_INSTALL-$(target)) && tar zxvf $(PROJECT_DIR)/downloads/mpdecimal-$(MPDECIMAL_VERSION)-$(target).tar.gz + # Ensure the target is marked as clean. + touch $$(MPDECIMAL_LIB-$(target)) + ########################################################################### # Target: OpenSSL ########################################################################### @@ -245,6 +262,7 @@ $$(PYTHON_SRCDIR-$(target))/configure: \ $$(BZIP2_LIB-$(target)) \ $$(XZ_LIB-$(target)) \ $$(OPENSSL_SSL_LIB-$(target)) \ + $$(MPDECIMAL_LIB-$(target)) \ $$(LIBFFI_LIB-$(target)) @echo ">>> Unpack and configure Python for $(target)" mkdir -p $$(PYTHON_SRCDIR-$(target)) @@ -270,6 +288,8 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ LIBLZMA_LIBS="-L$$(XZ_INSTALL-$(target))/lib -llzma" \ BZIP2_CFLAGS="-I$$(BZIP2_INSTALL-$(target))/include" \ BZIP2_LIBS="-L$$(BZIP2_INSTALL-$(target))/lib -lbz2" \ + LIBMPDEC_CFLAGS="-I$$(MPDECIMAL_INSTALL-$(target))/include" \ + LIBMPDEC_LIBS="-L$$(MPDECIMAL_INSTALL-$(target))/lib -lmpdec" \ LIBFFI_CFLAGS="-I$$(LIBFFI_INSTALL-$(target))/include" \ LIBFFI_LIBS="-L$$(LIBFFI_INSTALL-$(target))/lib -lffi" \ --host=$$(TARGET_TRIPLE-$(target)) \ @@ -277,18 +297,15 @@ $$(PYTHON_SRCDIR-$(target))/Makefile: \ --with-build-python=$(HOST_PYTHON) \ --enable-ipv6 \ --with-openssl="$$(OPENSSL_INSTALL-$(target))" \ - --without-ensurepip \ --enable-framework="$$(PYTHON_INSTALL-$(target))" \ - ac_cv_file__dev_ptmx=no \ - ac_cv_file__dev_ptc=no \ - $$(PYTHON_CONFIGURE-$(os)) \ + --with-system-libmpdec \ 2>&1 | tee -a ../python-$(PYTHON_VERSION).config.log $$(PYTHON_SRCDIR-$(target))/python.exe: $$(PYTHON_SRCDIR-$(target))/Makefile @echo ">>> Build Python for $(target)" cd $$(PYTHON_SRCDIR-$(target)) && \ PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/$(os)/Resources/bin:$(PATH)" \ - make all \ + make -j8 all \ 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log $$(PYTHON_LIB-$(target)): $$(PYTHON_SRCDIR-$(target))/python.exe @@ -308,7 +325,7 @@ $$(PYTHON_SITECUSTOMIZE-$(target)): cat $(PROJECT_DIR)/patch/Python/sitecustomize.$(os).py \ | sed -e "s/{{os}}/$(os)/g" \ | sed -e "s/{{arch}}/$$(ARCH-$(target))/g" \ - | sed -e "s/{{tag}}/$$(OS_LOWER-$(target))-$$(VERSION_MIN-$(os))-$$(SDK-$(target))-$$(ARCH-$(target))/g" \ + | sed -e "s/{{tag}}/$$(OS_LOWER-$(target))-$$(VERSION_MIN-$(os))-$$(ARCH-$(target))-$$(SDK-$(target))/g" \ > $$(PYTHON_SITECUSTOMIZE-$(target)) $(target): $$(PYTHON_SITECUSTOMIZE-$(target)) $$(PYTHON_LIB-$(target)) @@ -329,6 +346,8 @@ vars-$(target): @echo "XZ_LIB-$(target): $$(XZ_LIB-$(target))" @echo "OPENSSL_INSTALL-$(target): $$(OPENSSL_INSTALL-$(target))" @echo "OPENSSL_SSL_LIB-$(target): $$(OPENSSL_SSL_LIB-$(target))" + @echo "MPDECIMAL_INSTALL-$(target): $$(MPDECIMAL_INSTALL-$(target))" + @echo "MPDECIMAL_LIB-$(target): $$(MPDECIMAL_LIB-$(target))" @echo "LIBFFI_INSTALL-$(target): $$(LIBFFI_INSTALL-$(target))" @echo "LIBFFI_LIB-$(target): $$(LIBFFI_LIB-$(target))" @echo "PYTHON_SRCDIR-$(target): $$(PYTHON_SRCDIR-$(target))" @@ -524,20 +543,14 @@ $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \ tar zxf build/macOS/macosx/python-$(PYTHON_VERSION)/Python_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/Payload -C $$(PYTHON_FRAMEWORK-macosx) -X patch/Python/release.macOS.exclude # Rewrite the framework to make it standalone - python3 patch/make-macho-standalone.py $$(PYTHON_FRAMEWORK-macosx) \ - 2>&1 | tee $$(PYTHON_INSTALL-macosx)/python-$(PY_VERSION).make-macho-standalone.log - - # Remove the "development" versions of the libs - rm -f $$(PYTHON_INSTALL_VERSION-macosx)/lib/*.dylib - rm -f $$(PYTHON_INSTALL_VERSION-macosx)/lib/*.a - rm -rf $$(PYTHON_INSTALL_VERSION-macosx)/lib/python$(PY_VERSION)/config-* + patch/make-relocatable.sh $$(PYTHON_INSTALL_VERSION-macosx) 2>&1 > /dev/null # Re-apply the signature on the binaries. codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f $$(PYTHON_LIB-macosx) \ 2>&1 | tee $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log - find install/macOS/macosx/python-3.13.0a1/Python.framework -name "*.dylib" -type f -exec codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \; \ + find $$(PYTHON_FRAMEWORK-macosx) -name "*.dylib" -type f -exec codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \; \ 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log - find install/macOS/macosx/python-3.13.0a1/Python.framework -name "*.so" -type f -exec codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \; \ + find $$(PYTHON_FRAMEWORK-macosx) -name "*.so" -type f -exec codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \; \ 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f $$(PYTHON_FRAMEWORK-macosx) \ 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log @@ -588,6 +601,7 @@ $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \ echo "libFFI: $(LIBFFI_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS echo "BZip2: $(BZIP2_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS echo "OpenSSL: $(OPENSSL_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS + echo "mpdecimal: $(MPDECIMAL_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS echo "XZ: $(XZ_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz: \ diff --git a/README.rst b/README.rst index ae9d2ae..88b52ab 100644 --- a/README.rst +++ b/README.rst @@ -8,39 +8,28 @@ into a macOS, iOS, tvOS or watchOS project. Other Python versions are available by cloning other branches of the main repository: -* `Python 3.8 `__ * `Python 3.9 `__ * `Python 3.10 `__ * `Python 3.11 `__ * `Python 3.12 `__ +* `Python 3.13 `__ -It works by downloading, patching, and building a fat binary of Python and selected -pre-requisites, and packaging them as static libraries that can be incorporated into an -XCode project. The binary modules in the Python standard library are statically -compiled, but are distributed as objects that can be dynamically loaded at runtime. +It works by downloading, patching, and building a fat binary of Python and +selected pre-requisites, and packaging them as frameworks that can be +incorporated into an XCode project. The binary modules in the Python standard +library are distributed as binaries that can be dynamically loaded at runtime. The macOS package is a re-bundling of the official macOS binary, modified so that -it is relocatable. - -The iOS, tvOS and watchOS packages are compiled by this project. They expose -*almost* all the modules in the Python standard library except for: - -* ``curses`` -* ``dbm.gnu`` -* ``grp`` -* ``multiprocessing`` -* ``nis`` (Deprecated by PEP594) -* ``ossaudiodev`` (Deprecated by PEP594) -* ``posixshmem`` -* ``posixsubprocess`` -* ``readline`` -* ``spwd`` (Deprecated by PEP594) -* ``syslog`` -* ``tkinter`` +it is relocatable, with the IDLE, Tkinter and turtle packages removed. + +The iOS, tvOS and watchOS packages compiled by this project use the official +`PEP 730 `__ code that is part of Python 3.13 +to provide iOS support; the relevant patches have been backported to 3.9-3.12. +Additional patches have been applied to add tvOS and watchOS support. The binaries support x86_64 and arm64 for macOS; arm64 for iOS and appleTV -devices; and arm64_32 for watchOS. It also supports device simulators on both -x86_64 and M1 hardware. This should enable the code to run on: +devices; and arm64_32 for watchOS devices. It also supports device simulators on +both x86_64 and M1 hardware. This should enable the code to run on: * macOS 11 (Big Sur) or later, on: * MacBook (including MacBooks using Apple Silicon) @@ -48,14 +37,14 @@ x86_64 and M1 hardware. This should enable the code to run on: * Mac Mini (including Apple Silicon Mac minis) * Mac Studio (all models) * Mac Pro (all models) -* iOS 12.0 or later, on: +* iOS 13.0 or later, on: * iPhone (6s or later) * iPad (5th gen or later) * iPad Air (all models) * iPad Mini (2 or later) * iPad Pro (all models) * iPod Touch (7th gen or later) -* tvOS 9.0 or later, on: +* tvOS 12.0 or later, on: * Apple TV (4th gen or later) * watchOS 4.0 or later, on: * Apple Watch (4th gen or later) @@ -121,18 +110,11 @@ see the `usage guide <./USAGE.md>`__ Building binary wheels ---------------------- -When building binary wheels, you may need to use the libraries built by this -project as inputs (e.g., the `cffi` module uses `libffi`). To support this, this -project is able to package these dependencies as "wheels" that can be added to -the ``dist`` directory of the `Mobile Forge -project `__. - -To build these wheels, run: - -* ``make wheels`` to make all wheels for all mobile platforms -* ``make wheels-iOS`` to build all the iOS wheels -* ``make wheels-tvOS`` to build all the tvOS wheels -* ``make wheels-watchOS`` to build all the watchOS wheels +This project packages the Python standard library, but does not address building +binary wheels. Binary wheels for macOS can be obtained from PyPI. `Mobile Forge +`__ is a project that provides the +tooling to build build binary wheels for iOS (and potentially for tvOS and +watchOS, although that hasn't been tested). Historical support ------------------ @@ -145,3 +127,4 @@ maintained: * `Python 3.5 `__ (EOL February 2021) * `Python 3.6 `__ (EOL December 2021) * `Python 3.7 `__ (EOL September 2022) +* `Python 3.8 `__ (EOL October 2024) diff --git a/USAGE.md b/USAGE.md index 8b6b9ac..12bc1dc 100644 --- a/USAGE.md +++ b/USAGE.md @@ -9,179 +9,21 @@ pre-build stub application, in the case of macOS). ## The manual way -The Python support package *can* be manually added to any Xcode project; -however, you'll need to perform some steps manually (essentially reproducing what -Briefcase is doing) - **NOTE** Briefcase usage is the officially supported approach for using this support package. If you are experiencing diffculties, one approach for debugging is to generate a "Hello World" project with Briefcase, and compare the project that Briefcase has generated with your own project. -To add this support package to your own project: - -1. [Download a release tarball for your desired Python version and Apple - platform](https://github.com/beeware/Python-Apple-support/releases) - -2. Add `Python.xcframework` to your Xcode project. You can put it anywhere in your - project that you want; the following instructions assume it has been put in a - folder named "Support". - -3. In Xcode, select the root node of the project tree, and select the target you - want to build. - -4. Select "General" -> "Frameworks, Libraries and Embedded Content", and ensure - that `Python.xcframework` is on the list of frameworks. It should be marked - "Embed and sign". - -5. Select "General" -> "Build Settings", and set the following values: - - Linking - General: - - `@executable_path/Frameworks` - - Search paths: - - Framework Search paths: `"$(PROJECT_DIR)/Support"` - - Header Search paths: `"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers"` - -6. Add a new "Run script" build phase named "Install target specific Python - Modules". This script will install the standard library for your target. The - script should have the following content: - -```bash -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/Support/Python.xcframework/iphonesimulator/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" - # Also install any user-provided modules - # rsync -au --delete "$PROJECT_DIR/Testbed/app_packages.iphonesimulator/" "$CODESIGNING_FOLDER_PATH/app_packages" -else - echo "Installing Python modules for iOS Device" - rsync -au --delete "$PROJECT_DIR/Support/Python.xcframework/iphoneos/lib/" "$CODESIGNING_FOLDER_PATH/python/lib" - # Also install any user-provided modules - # rsync -au --delete "$PROJECT_DIR/Testbed/app_packages.iphoneos/" "$CODESIGNING_FOLDER_PATH/app_packages" -fi -``` - -7. Add a new "Run script" build phase named "Sign Python Binary Modules". - - The iOS App Store requires that binary modules *must* be contained inside frameworks. - This script will move every `.dylib` file in the `lib-dynload` folder to a unique - framework in the `Frameworks` folder of your packaged binary, then sign the new - framework. The script should have the following content: - -```bash -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" - defaults write "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" CFBundleExecutable -string "$DYLIB" - defaults write "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" - fi - - echo "Installing binary for $RELATIVE_DYLIB" - mv "$FULL_DYLIB" "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER" -} - -# Make sure to update the Python version version reference here -echo "Install standard library dylibs..." -find "$CODESIGNING_FOLDER_PATH/python/lib/python3.13/lib-dynload" -name "*.dylib" | while read FULL_DYLIB; do - install_dylib python/lib/python3.13/lib-dynload "$FULL_DYLIB" -done -# Also install any user-provided dynamic modules; e.g., -# echo "Install app package dylibs..." -# find "$CODESIGNING_FOLDER_PATH/app_packages" -name "*.dylib" | while read FULL_DYLIB; do -# install_dylib app_packages "$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 "{}" \; -``` - - Make sure that you update these scripts to update the references to the - Python version, and include any user-provided code that you want to bundle. - If you use the ``rsync`` approach above, user-provided code should *not* be - included as part of the "Copy Bundle Resources" step. - - You'll also need to add a file named `dylib-Info-template.plist` to your Xcode - project, and make it a member of any target that needs to use Python. The template - should have the following content: - -```xml - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - - CFBundleIdentifier - - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSupportedPlatforms - - iPhoneOS - - MinimumOSVersion - 12.0 - CFBundleVersion - 1 - - -``` - - macOS projects don't require `.dylib` files be moved like this, so you can use a much - simpler signing script: - -```bash -set -e -echo "Signing as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)" -find "$CODESIGNING_FOLDER_PATH/Contents/Resources/python-stdlib/lib-dynload" -name "*.so" -exec /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der {} \; -``` - -8. Disable dead code removal. As of March 2024 Xcode has "Dead Code Stripping" enabled by default. This _will_ remove functions from linked Python library that linker found unused. - Navigate to Build Settings -> Linkin - General. Find "Dead Code Stripping" and select "No" - -You will now be able to access the Python runtime in your Python code. - -If you are on iOS, you will be able to deploy to an iOS simulator without specifying -development team; however, you will need to specify a valid development team to sign -the binaries for deployment onto a physical device (or for submission to the App Store). +The Python support package *can* be manually added to any Xcode project; +however, you'll need to perform some steps manually (essentially reproducing +what Briefcase is doing). The steps required are documented in the CPython usage +guides: -If you are on macOS, you will need to specify a valid development team to run -the app. If you don't want to specify a development team in your project, you -will also need to enable the "Disable Library Validation" entitlement under -"Signing & Capabilities" -> "Hardened Runtime" for your project. +* [macOS](https://docs.python.org/3/using/mac.html) +* [iOS](https://docs.python.org/3.14/using/ios.html) -If you have any third party dependencies with binary components, they'll also need to go -through the processing of the scripts in steps 6 and 7. +For tvOS and watchOS, you should be able to broadly follow the instructions in +the iOS guide. ## Accessing the Python runtime diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index 24f7d21..aca98f6 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -1,3834 +1,662 @@ -diff --git a/Include/internal/pycore_faulthandler.h b/Include/internal/pycore_faulthandler.h -index 6dd7d8d7ca..836c8a3fcf 100644 ---- a/Include/internal/pycore_faulthandler.h -+++ b/Include/internal/pycore_faulthandler.h -@@ -12,6 +12,14 @@ - # include // sigaction - #endif - -+#ifdef __APPLE__ -+# include "TargetConditionals.h" -+#endif /* __APPLE__ */ -+ -+// tvOS and watchOS don't provide a number of important POSIX functions. -+#if TARGET_OS_TV || TARGET_OS_WATCH -+# undef HAVE_SIGALTSTACK -+#endif /* TVOS || WATCHOS */ - - #ifndef MS_WINDOWS - /* register() is useless on Windows, because only SIGSEGV, SIGABRT and ---- /dev/null -+++ b/Lib/_ios_support.py -@@ -0,0 +1,46 @@ -+try: -+ from ctypes import cdll, c_void_p, c_char_p -+ from ctypes import util -+except ImportError: -+ # ctypes is an optional module. If it's not present, we're limited in what -+ # we can tell about the system, but we don't want to prevent the platform -+ # module from working. -+ cdll = None -+ -+ -+def get_platform_ios(): -+ if cdll: -+ objc = cdll.LoadLibrary(util.find_library(b'objc')) -+ -+ objc.objc_getClass.restype = c_void_p -+ objc.objc_getClass.argtypes = [c_char_p] -+ objc.objc_msgSend.restype = c_void_p -+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p] -+ objc.sel_registerName.restype = c_void_p -+ objc.sel_registerName.argtypes = [c_char_p] -+ -+ UIDevice = c_void_p(objc.objc_getClass(b'UIDevice')) -+ SEL_currentDevice = c_void_p(objc.sel_registerName(b'currentDevice')) -+ device = c_void_p(objc.objc_msgSend(UIDevice, SEL_currentDevice)) -+ -+ SEL_systemVersion = c_void_p(objc.sel_registerName(b'systemVersion')) -+ systemVersion = c_void_p(objc.objc_msgSend(device, SEL_systemVersion)) -+ -+ SEL_systemName = c_void_p(objc.sel_registerName(b'systemName')) -+ systemName = c_void_p(objc.objc_msgSend(device, SEL_systemName)) -+ -+ SEL_model = c_void_p(objc.sel_registerName(b'model')) -+ systemModel = c_void_p(objc.objc_msgSend(device, SEL_model)) -+ -+ # UTF8String returns a const char*; -+ SEL_UTF8String = c_void_p(objc.sel_registerName(b'UTF8String')) -+ objc.objc_msgSend.restype = c_char_p -+ -+ system = objc.objc_msgSend(systemName, SEL_UTF8String).decode() -+ release = objc.objc_msgSend(systemVersion, SEL_UTF8String).decode() -+ model = objc.objc_msgSend(systemModel, SEL_UTF8String).decode() -+ -+ return system, release, model -+ else: -+ # Return dummy values if we can't call system APIs. -+ return "iOS", "?", "iPhone" -diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py -index 0c2510e161..5567080ba5 100644 ---- a/Lib/ctypes/util.py -+++ b/Lib/ctypes/util.py -@@ -67,7 +67,7 @@ - return fname - return None - --elif os.name == "posix" and sys.platform == "darwin": -+elif os.name == "posix" and sys.platform in {'darwin', 'ios', 'tvos', 'watchos'}: - from ctypes.macholib.dyld import dyld_find as _dyld_find - def find_library(name): - possible = ['lib%s.dylib' % name, -diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py -index 0019897c94..c11ead2b11 100644 ---- a/Lib/importlib/_bootstrap_external.py -+++ b/Lib/importlib/_bootstrap_external.py -@@ -52,7 +52,7 @@ - - # Bootstrap-related code ###################################################### - _CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win', --_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin' -+_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos' - _CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY - + _CASE_INSENSITIVE_PLATFORMS_STR_KEY) - -@@ -1704,6 +1704,65 @@ - return f'FileFinder({self.path!r})' - - -+class AppleFrameworkLoader(ExtensionFileLoader): -+ """A loader for modules that have been packaged as Apple Frameworks for -+ compatibility with Apple's App Store policies. -+ -+ For compatibility with the App Store, *all* binary modules must be .dylib -+ objects, contained in a Framework, stored in the ``Frameworks`` folder of -+ the packaged app. If you're trying to run "from foo import _bar", and _bar -+ is implemented with the binary module "foo/_bar.abi3.dylib" (or any other -+ .dylib extension), this loader will look for -+ "{sys.executable}/Frameworks/foo._bar.framework/_bar.abi3.dylib" (forming -+ the package name by taking the full path of the library, and replacing ``/`` -+ with ``.``). The app packaging tool is responsible for putting the library -+ in this location. -+ -+ However, the ``__file__`` attribute of the _bar module will report as the -+ original location inside the ``foo`` directory. This so that code that -+ depends on walking directory trees will continue to work as expected based -+ on the *original* file location. -+ """ -+ def __init__(self, fullname, dylib_file, path): -+ super().__init__(fullname, dylib_file) -+ self.parent_paths = path -+ -+ def create_module(self, spec): -+ mod = super().create_module(spec) -+ if self.parent_paths: -+ for parent_path in self.parent_paths: -+ if _path_isdir(parent_path): -+ mod.__file__ = _path_join(parent_path, _path_split(self.path)[-1]) -+ continue -+ return mod -+ -+ -+class AppleFrameworkFinder: -+ """A finder for modules that have been packaged as Apple Frameworks -+ for compatibility with Apple's App Store policies. +diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst +index 27909b763e9..fb5353e1895 100644 +--- a/Doc/library/urllib.parse.rst ++++ b/Doc/library/urllib.parse.rst +@@ -22,11 +22,19 @@ + + The module has been designed to match the internet RFC on Relative Uniform + Resource Locators. It supports the following URL schemes: ``file``, ``ftp``, +-``gopher``, ``hdl``, ``http``, ``https``, ``imap``, ``mailto``, ``mms``, ++``gopher``, ``hdl``, ``http``, ``https``, ``imap``, ``itms-services``, ``mailto``, ``mms``, + ``news``, ``nntp``, ``prospero``, ``rsync``, ``rtsp``, ``rtsps``, ``rtspu``, + ``sftp``, ``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``, + ``telnet``, ``wais``, ``ws``, ``wss``. + ++.. impl-detail:: ++ ++ The inclusion of the ``itms-services`` URL scheme can prevent an app from ++ passing Apple's App Store review process for the macOS and iOS App Stores. ++ Handling for the ``itms-services`` scheme is always removed on iOS; on ++ macOS, it *may* be removed if CPython has been built with the ++ :option:`--with-app-store-compliance` option. ++ + The :mod:`urllib.parse` module defines functions that fall into two broad + categories: URL parsing and URL quoting. These are covered in detail in + the following sections. +diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst +index 8eaba84e159..2c73c224e4e 100644 +--- a/Doc/using/configure.rst ++++ b/Doc/using/configure.rst +@@ -945,6 +945,17 @@ + Specify the name for the python framework on macOS only valid when + :option:`--enable-framework` is set (default: ``Python``). + ++.. option:: --with-app-store-compliance ++.. option:: --with-app-store-compliance=PATCH-FILE ++ ++ The Python standard library contains strings that are known to trigger ++ automated inspection tool errors when submitted for distribution by ++ the macOS and iOS App Stores. If enabled, this option will apply the list of ++ patches that are known to correct app store compliance. A custom patch ++ file can also be specified. This option is disabled by default. ++ ++ .. versionadded:: 3.13 ++ + iOS Options + ----------- + +diff --git a/Doc/using/ios.rst b/Doc/using/ios.rst +index 70a81fd8a53..5d0924be8d9 100644 +--- a/Doc/using/ios.rst ++++ b/Doc/using/ios.rst +@@ -323,3 +323,21 @@ + + * If you're using a separate folder for third-party packages, ensure that folder + is included as part of the ``PYTHONPATH`` configuration in step 10. ++ ++App Store Compliance ++==================== + -+ See AppleFrameworkLoader for details. -+ """ -+ def __init__(self, path): -+ self.frameworks_path = path -+ -+ def find_spec(self, fullname, path, target=None): -+ name = fullname.split(".")[-1] -+ -+ for extension in EXTENSION_SUFFIXES: -+ dylib_file = _path_join(self.frameworks_path, f"{fullname}.framework", f"{name}{extension}") -+ _bootstrap._verbose_message('Looking for Apple Framework dylib {}', dylib_file) -+ try: -+ dylib_exists = _path_isfile(dylib_file) -+ except ValueError: -+ pass -+ else: -+ if dylib_exists: -+ loader = AppleFrameworkLoader(fullname, dylib_file, path) -+ return _bootstrap.spec_from_loader(fullname, loader) -+ -+ return None -+ - # Import setup ############################################################### - - def _fix_up_module(ns, name, pathname, cpathname=None): -@@ -1753,3 +1812,7 @@ - supported_loaders = _get_supported_file_loaders() - sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)]) - sys.meta_path.append(PathFinder) -+ if sys.platform in {"ios", "tvos", "watchos"}: -+ frameworks_folder = _path_join(_path_split(sys.executable)[0], "Frameworks") -+ _bootstrap._verbose_message('Adding Apple Framework dylib finder at {}', frameworks_folder) -+ sys.meta_path.append(AppleFrameworkFinder(frameworks_folder)) -diff --git a/Lib/importlib/machinery.py b/Lib/importlib/machinery.py -index d9a19a13f7..fbd30b159f 100644 ---- a/Lib/importlib/machinery.py -+++ b/Lib/importlib/machinery.py -@@ -12,6 +12,7 @@ - from ._bootstrap_external import SourceFileLoader - from ._bootstrap_external import SourcelessFileLoader - from ._bootstrap_external import ExtensionFileLoader -+from ._bootstrap_external import AppleFrameworkLoader - from ._bootstrap_external import NamespaceLoader - ++The only mechanism for distributing apps to third-party iOS devices is to ++submit the app to the iOS App Store; apps submitted for distribution must pass ++Apple's app review process. This process includes a set of automated validation ++rules that inspect the submitted application bundle for problematic code. ++ ++The Python standard library contains some code that is known to violate these ++automated rules. While these violations appear to be false positives, Apple's ++review rules cannot be challenged; so, it is necessary to modify the Python ++standard library for an app to pass App Store review. ++ ++The Python source tree contains ++:source:`a patch file ` that will remove ++all code that is known to cause issues with the App Store review process. This ++patch is applied automatically when building for iOS. +diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst +index 31d37aad2a7..44fb00de373 100644 +--- a/Doc/using/mac.rst ++++ b/Doc/using/mac.rst +@@ -188,6 +188,28 @@ + * `PyInstaller `__: A cross-platform packaging tool that creates + a single file or folder as a distributable artifact. + ++App Store Compliance ++-------------------- ++ ++Apps submitted for distribution through the macOS App Store must pass Apple's ++app review process. This process includes a set of automated validation rules ++that inspect the submitted application bundle for problematic code. ++ ++The Python standard library contains some code that is known to violate these ++automated rules. While these violations appear to be false positives, Apple's ++review rules cannot be challenged. Therefore, it is necessary to modify the ++Python standard library for an app to pass App Store review. ++ ++The Python source tree contains ++:source:`a patch file ` that will remove ++all code that is known to cause issues with the App Store review process. This ++patch is applied automatically when CPython is configured with the ++:option:`--with-app-store-compliance` option. ++ ++This patch is not normally required to use CPython on a Mac; nor is it required ++if you are distributing an app *outside* the macOS App Store. It is *only* ++required if you are using the macOS App Store as a distribution channel. ++ + Other Resources + =============== diff --git a/Lib/platform.py b/Lib/platform.py -index 7bb222088d..b4db9749da 100755 +index 5958382276e..5db5eb276a2 100755 --- a/Lib/platform.py +++ b/Lib/platform.py -@@ -496,6 +496,26 @@ - # If that also doesn't work return the default values - return release, versioninfo, machine +@@ -521,6 +521,54 @@ + return IOSVersionInfo(system, release, model, is_simulator) -+def ios_ver(): -+ """Get iOS/tvOS version information, and return it as a -+ tuple (system, release, model). All tuple entries are strings. + ++# A namedtuple for tvOS version information. ++TVOSVersionInfo = collections.namedtuple( ++ "TVOSVersionInfo", ++ ["system", "release", "model", "is_simulator"] ++) ++ ++ ++def tvos_ver(system="", release="", model="", is_simulator=False): ++ """Get tvOS version information, and return it as a namedtuple: ++ (system, release, model, is_simulator). ++ ++ If values can't be determined, they are set to values provided as ++ parameters. + """ -+ import _ios_support -+ return _ios_support.get_platform_ios() ++ if sys.platform == "tvos": ++ # TODO: Can the iOS implementation be used here? ++ import _ios_support ++ result = _ios_support.get_platform_ios() ++ if result is not None: ++ return TVOSVersionInfo(*result) + -+def is_simulator(): -+ """Determine if the current platform is a device simulator. ++ return TVOSVersionInfo(system, release, model, is_simulator) + -+ Only useful when working with iOS, tvOS or watchOS, because -+ Apple provides simulator platforms for those devices. + -+ If the platform is actual hardware, returns False. Will also -+ return False for device *emulators*, which are indistinguishable -+ from actual devices because they are reproducing actual device -+ properties. ++# A namedtuple for watchOS version information. ++WatchOSVersionInfo = collections.namedtuple( ++ "WatchOSVersionInfo", ++ ["system", "release", "model", "is_simulator"] ++) ++ ++ ++def watchos_ver(system="", release="", model="", is_simulator=False): ++ """Get watchOS version information, and return it as a namedtuple: ++ (system, release, model, is_simulator). ++ ++ If values can't be determined, they are set to values provided as ++ parameters. + """ -+ return getattr(sys.implementation, "_simulator", False) ++ if sys.platform == "watchos": ++ # TODO: Can the iOS implementation be used here? ++ import _ios_support ++ result = _ios_support.get_platform_ios() ++ if result is not None: ++ return WatchOSVersionInfo(*result) ++ ++ return WatchOSVersionInfo(system, release, model, is_simulator) ++ + def _java_getprop(name, default): - + """This private helper is deprecated in 3.13 and will be removed in 3.15""" from java.lang import System -@@ -652,7 +672,7 @@ - default in case the command should fail. - - """ -- if sys.platform in ('dos', 'win32', 'win16'): -+ if sys.platform in {'dos', 'win32', 'win16', 'ios', 'tvos', 'watchos'}: - # XXX Others too ? - return default - -@@ -814,6 +834,24 @@ +@@ -884,14 +932,25 @@ csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0) return 'Alpha' if cpu_number >= 128 else 'VAX' -+ # On iOS, tvOS and watchOS, os.uname returns the architecture -+ # as uname.machine. On device it doesn't; but there's only -+ # on CPU architecture on device -+ def get_ios(): -+ if getattr(sys.implementation, "_simulator", False): -+ return os.uname().machine -+ return 'arm64' -+ +- # On the iOS simulator, os.uname returns the architecture as uname.machine. +- # On device it returns the model name for some reason; but there's only one +- # CPU architecture for iOS devices, so we know the right answer. ++ # On the iOS/tvOS/watchOS simulator, os.uname returns the architecture as ++ # uname.machine. On device it returns the model name for some reason; but ++ # there's only one CPU architecture for devices, so we know the right ++ # answer. + def get_ios(): + if sys.implementation._multiarch.endswith("simulator"): + return os.uname().machine + return 'arm64' + + def get_tvos(): -+ if getattr(sys.implementation, "_simulator", False): ++ if sys.implementation._multiarch.endswith("simulator"): + return os.uname().machine + return 'arm64' + + def get_watchos(): -+ if getattr(sys.implementation, "_simulator", False): ++ if sys.implementation._multiarch.endswith("simulator"): + return os.uname().machine + return 'arm64_32' + def from_subprocess(): """ Fall back to `uname -p` -@@ -968,6 +1006,15 @@ - system = 'Windows' - release = 'Vista' +@@ -1051,9 +1110,13 @@ + system = 'Android' + release = android_ver().release +- # Normalize responses on iOS + # Normalize responses on Apple mobile platforms -+ if sys.platform in {'ios', 'tvos'}: -+ system, release, model = ios_ver() -+ -+ # On iOS/tvOS simulators, os.uname() reports the machine as something -+ # like "arm64" or "x86_64". -+ if getattr(sys.implementation, "_simulator", False): -+ machine = f'{model}Simulator' -+ + if sys.platform == 'ios': + system, release, _, _ = ios_ver() ++ if sys.platform == 'tvos': ++ system, release, _, _ = tvos_ver() ++ if sys.platform == 'watchos': ++ system, release, _, _ = watchos_ver() + vals = system, node, release, version, machine # Replace 'unknown' values with the more portable '' - _uname_cache = uname_result(*map(_unknown_as_blank, vals)) -@@ -1247,11 +1294,13 @@ - system, release, version = system_alias(system, release, version) - - if system == 'Darwin': -- # macOS (darwin kernel) -- macos_release = mac_ver()[0] -- if macos_release: -- system = 'macOS' -- release = macos_release -+ if sys.platform in {'ios', 'tvos'}: -+ system, release, _ = ios_ver() -+ else: -+ macos_release = mac_ver()[0] -+ if macos_release: -+ system = 'macOS' -+ release = macos_release - - if system == 'Windows': - # MS platforms -diff --git a/Lib/site.py b/Lib/site.py -index 672fa7b000..9fd399e990 100644 ---- a/Lib/site.py -+++ b/Lib/site.py -@@ -294,6 +294,9 @@ - - if sys.platform == 'darwin' and sys._framework: - return f'{userbase}/lib/python/site-packages' -+ elif sys.platform in ('ios', 'tvos', 'watchos'): -+ from sysconfig import get_path -+ return get_path('purelib', sys.platform) - - return f'{userbase}/lib/python{version[0]}.{version[1]}/site-packages' - -diff --git a/Lib/subprocess.py b/Lib/subprocess.py -index 6df5dd551e..597da09643 100644 ---- a/Lib/subprocess.py -+++ b/Lib/subprocess.py -@@ -74,8 +74,8 @@ - else: - _mswindows = True - --# wasm32-emscripten and wasm32-wasi do not support processes --_can_fork_exec = sys.platform not in {"emscripten", "wasi"} -+# some platforms do not support processes -+_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos"} - - if _mswindows: - import _winapi -@@ -103,18 +103,22 @@ - if _can_fork_exec: - from _posixsubprocess import fork_exec as _fork_exec - # used in methods that are called by __del__ -- _waitpid = os.waitpid -- _waitstatus_to_exitcode = os.waitstatus_to_exitcode -- _WIFSTOPPED = os.WIFSTOPPED -- _WSTOPSIG = os.WSTOPSIG -- _WNOHANG = os.WNOHANG -+ class _del_safe: -+ waitpid = os.waitpid -+ waitstatus_to_exitcode = os.waitstatus_to_exitcode -+ WIFSTOPPED = os.WIFSTOPPED -+ WSTOPSIG = os.WSTOPSIG -+ WNOHANG = os.WNOHANG -+ ECHILD = errno.ECHILD - else: -- _fork_exec = None -- _waitpid = None -- _waitstatus_to_exitcode = None -- _WIFSTOPPED = None -- _WSTOPSIG = None -- _WNOHANG = None -+ class _del_safe: -+ waitpid = None -+ waitstatus_to_exitcode = None -+ WIFSTOPPED = None -+ WSTOPSIG = None -+ WNOHANG = None -+ ECHILD = errno.ECHILD -+ - import select - import selectors - -@@ -1951,20 +1955,16 @@ - raise child_exception_type(err_msg) - - -- def _handle_exitstatus(self, sts, -- _waitstatus_to_exitcode=_waitstatus_to_exitcode, -- _WIFSTOPPED=_WIFSTOPPED, -- _WSTOPSIG=_WSTOPSIG): -+ def _handle_exitstatus(self, sts, _del_safe=_del_safe): - """All callers to this function MUST hold self._waitpid_lock.""" - # This method is called (indirectly) by __del__, so it cannot - # refer to anything outside of its local scope. -- if _WIFSTOPPED(sts): -- self.returncode = -_WSTOPSIG(sts) -+ if _del_safe.WIFSTOPPED(sts): -+ self.returncode = -_del_safe.WSTOPSIG(sts) - else: -- self.returncode = _waitstatus_to_exitcode(sts) -+ self.returncode = _del_safe.waitstatus_to_exitcode(sts) - -- def _internal_poll(self, _deadstate=None, _waitpid=_waitpid, -- _WNOHANG=_WNOHANG, _ECHILD=errno.ECHILD): -+ def _internal_poll(self, _deadstate=None, _del_safe=_del_safe): - """Check if child process has terminated. Returns returncode - attribute. - -@@ -1980,13 +1980,13 @@ - try: - if self.returncode is not None: - return self.returncode # Another thread waited. -- pid, sts = _waitpid(self.pid, _WNOHANG) -+ pid, sts = _del_safe.waitpid(self.pid, _del_safe.WNOHANG) - if pid == self.pid: - self._handle_exitstatus(sts) - except OSError as e: - if _deadstate is not None: - self.returncode = _deadstate -- elif e.errno == _ECHILD: -+ elif e.errno == _del_safe.ECHILD: - # This happens if SIGCLD is set to be ignored or - # waiting for child processes has otherwise been - # disabled for our process. This child is dead, we +@@ -1343,6 +1406,10 @@ + # macOS and iOS both report as a "Darwin" kernel + if sys.platform == "ios": + system, release, _, _ = ios_ver() ++ elif sys.platform == "tvos": ++ system, release, _, _ = tvos_ver() ++ elif sys.platform == "watchos": ++ system, release, _, _ = watchos_ver() + else: + macos_release = mac_ver()[0] + if macos_release: diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py -index 68d30c0f9e..4a8a27b6d0 100644 +index 83e057c177f..d18a7564866 100644 --- a/Lib/sysconfig/__init__.py +++ b/Lib/sysconfig/__init__.py -@@ -96,6 +96,33 @@ - 'scripts': '{base}/Scripts', - 'data': '{base}', - }, -+ 'ios': { -+ 'stdlib': '{installed_base}/lib/python{py_version_short}', -+ 'platstdlib': '{installed_base}/lib/python{py_version_short}', -+ 'purelib': '{installed_base}/lib/python{py_version_short}/site-packages', -+ 'platlib': '{installed_base}/lib/python{py_version_short}/site-packages', -+ 'include': '{installed_base}/include', -+ 'scripts': '{installed_base}/bin', -+ 'data': '{installed_base}/Resources', -+ }, -+ 'tvos': { -+ 'stdlib': '{installed_base}/lib/python{py_version_short}', -+ 'platstdlib': '{installed_base}/lib/python{py_version_short}', -+ 'purelib': '{installed_base}/lib/python{py_version_short}/site-packages', -+ 'platlib': '{installed_base}/lib/python{py_version_short}/site-packages', -+ 'include': '{installed_base}/include', -+ 'scripts': '{installed_base}/bin', -+ 'data': '{installed_base}/Resources', -+ }, -+ 'watchos': { -+ 'stdlib': '{installed_base}/lib/python{py_version_short}', -+ 'platstdlib': '{installed_base}/lib/python{py_version_short}', -+ 'purelib': '{installed_base}/lib/python{py_version_short}/site-packages', -+ 'platlib': '{installed_base}/lib/python{py_version_short}/site-packages', -+ 'include': '{installed_base}/include', -+ 'scripts': '{installed_base}/bin', -+ 'data': '{installed_base}/Resources', -+ }, - } - - # For the OS-native venv scheme, we essentially provide an alias: -@@ -282,12 +309,19 @@ - 'home': 'posix_home', - 'user': 'nt_user', - } -+ if sys.platform in ('ios', 'tvos', 'watchos'): -+ return { -+ 'prefix': sys.platform, -+ 'home': sys.platform, -+ 'user': sys.platform, -+ } - if sys.platform == 'darwin' and sys._framework: - return { - 'prefix': 'posix_prefix', - 'home': 'posix_home', - 'user': 'osx_framework_user', - } -+ - return { - 'prefix': 'posix_prefix', - 'home': 'posix_home', -@@ -619,10 +653,16 @@ - if m: +@@ -642,7 +642,15 @@ release = m.group() elif osname[:6] == "darwin": -- import _osx_support -- osname, release, machine = _osx_support.get_platform_osx( -- get_config_vars(), -- osname, release, machine) -+ if sys.platform in ("ios", "tvos", "watchos"): -+ import _ios_support -+ _, release, _ = _ios_support.get_platform_ios() + if sys.platform == "ios": +- release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "12.0") ++ release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0") + osname = sys.platform + machine = sys.implementation._multiarch -+ else: -+ import _osx_support -+ osname, release, machine = _osx_support.get_platform_osx( -+ get_config_vars(), -+ osname, release, machine) - - return f"{osname}-{release}-{machine}" - -diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py -index 21e8770ab3..67958d247c 100644 ---- a/Lib/test/support/__init__.py -+++ b/Lib/test/support/__init__.py -@@ -46,7 +46,7 @@ - "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer", - "requires_limited_api", "requires_specialization", - # sys -- "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", -+ "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", "is_apple_mobile", - "check_impl_detail", "unix_shell", "setswitchinterval", - # os - "get_pagesize", -@@ -520,7 +520,7 @@ - - is_android = hasattr(sys, 'getandroidapilevel') - --if sys.platform not in ('win32', 'vxworks'): -+if sys.platform not in ('win32', 'vxworks', 'ios', 'tvos', 'watchos'): - unix_shell = '/system/bin/sh' if is_android else '/bin/sh' - else: - unix_shell = None -@@ -530,12 +530,25 @@ - is_emscripten = sys.platform == "emscripten" - is_wasi = sys.platform == "wasi" - --has_fork_support = hasattr(os, "fork") and not is_emscripten and not is_wasi -+# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not -+# have subprocess or fork support. -+is_apple_mobile = sys.platform in ('ios', 'tvos', 'watchos') -+ -+has_fork_support = ( -+ hasattr(os, "fork") -+ and not is_emscripten -+ and not is_wasi -+ and not is_apple_mobile -+) - - def requires_fork(): - return unittest.skipUnless(has_fork_support, "requires working os.fork()") - --has_subprocess_support = not is_emscripten and not is_wasi -+has_subprocess_support = ( -+ not is_emscripten -+ and not is_wasi -+ and not is_apple_mobile -+) - - def requires_subprocess(): - """Used for subprocess, os.spawn calls, fd inheritance""" -diff --git a/Lib/test/support/os_helper.py b/Lib/test/support/os_helper.py -index 821a4b1ffd..517f7b57f4 100644 ---- a/Lib/test/support/os_helper.py -+++ b/Lib/test/support/os_helper.py -@@ -20,7 +20,7 @@ - - # TESTFN_UNICODE is a non-ascii filename - TESTFN_UNICODE = TESTFN_ASCII + "-\xe0\xf2\u0258\u0141\u011f" --if sys.platform == 'darwin': -+if sys.platform in ('darwin', 'ios', 'tvos', 'watchos'): - # In Mac OS X's VFS API file names are, by definition, canonically - # decomposed Unicode, encoded using UTF-8. See QA1173: - # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html -@@ -46,8 +46,8 @@ - 'encoding (%s). Unicode filename tests may not be effective' - % (TESTFN_UNENCODABLE, sys.getfilesystemencoding())) - TESTFN_UNENCODABLE = None --# macOS and Emscripten deny unencodable filenames (invalid utf-8) --elif sys.platform not in {'darwin', 'emscripten', 'wasi'}: -+# Apple and Emscripten deny unencodable filenames (invalid utf-8) -+elif sys.platform not in {'darwin', 'ios', 'tvos', 'watchos', 'emscripten', 'wasi'}: - try: - # ascii and utf-8 cannot encode the byte 0xff - b'\xff'.decode(sys.getfilesystemencoding()) -diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py -index b25c097573..7491782c7f 100644 ---- a/Lib/test/test_asyncio/test_events.py -+++ b/Lib/test/test_asyncio/test_events.py -@@ -33,6 +33,7 @@ - from multiprocessing.util import _cleanup_tests as multiprocessing_cleanup_tests - from test.test_asyncio import utils as test_utils - from test import support -+from test.support import is_apple_mobile - from test.support import socket_helper - from test.support import threading_helper - from test.support import ALWAYS_EQ, LARGEST, SMALLEST -@@ -1799,6 +1800,7 @@ - next(it) - - -+@support.requires_subprocess() - class SubprocessTestsMixin: - - def check_terminated(self, returncode): -diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py -index 9c92e75886..65ee41dbd1 100644 ---- a/Lib/test/test_asyncio/test_streams.py -+++ b/Lib/test/test_asyncio/test_streams.py -@@ -18,6 +18,7 @@ - - import asyncio - from test.test_asyncio import utils as test_utils -+from test.support import requires_subprocess - - - def tearDownModule(): -@@ -771,6 +772,7 @@ - self.assertEqual(msg2, b"hello world 2!\n") - - @unittest.skipIf(sys.platform == 'win32', "Don't have pipes") -+ @requires_subprocess() - def test_read_all_from_pipe_reader(self): - # See asyncio issue 168. This test is derived from the example - # subprocess_attach_read_pipe.py, but we configure the -diff --git a/Lib/test/test_asyncio/test_subprocess.py b/Lib/test/test_asyncio/test_subprocess.py -index 179c8cb8cc..c8659f6ed6 100644 ---- a/Lib/test/test_asyncio/test_subprocess.py -+++ b/Lib/test/test_asyncio/test_subprocess.py -@@ -11,6 +11,7 @@ - from asyncio import subprocess - from test.test_asyncio import utils as test_utils - from test import support -+from test.support import is_apple_mobile - from test.support import os_helper - - -@@ -47,6 +48,8 @@ - self._proc.pid = -1 - - -+@unittest.skipIf(is_apple_mobile, -+ f"{sys.platform} doesn't support subprocesses.") - class SubprocessTransportTests(test_utils.TestCase): - def setUp(self): - super().setUp() -@@ -110,6 +113,8 @@ - transport.close() - - -+@unittest.skipIf(is_apple_mobile, -+ f"{sys.platform} doesn't support subprocesses.") - class SubprocessMixin: - - def test_stdin_stdout(self): -diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py -index d2c8cba6ac..c3795dede9 100644 ---- a/Lib/test/test_asyncio/test_unix_events.py -+++ b/Lib/test/test_asyncio/test_unix_events.py -@@ -1875,6 +1875,7 @@ - - - @unittest.skipUnless(hasattr(os, 'fork'), 'requires os.fork()') -+@support.requires_subprocess() - class TestFork(unittest.IsolatedAsyncioTestCase): - - async def test_fork_not_share_event_loop(self): -diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py -index 1b58882601..7ae237e6c1 100644 ---- a/Lib/test/test_cmd_line_script.py -+++ b/Lib/test/test_cmd_line_script.py -@@ -560,7 +560,9 @@ - # Python cannot a undecodable bytes argument to a subprocess. - # WASI does not permit invalid UTF-8 names. - if (os_helper.TESTFN_UNDECODABLE -- and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')): -+ and sys.platform not in ( -+ 'win32', 'darwin', 'ios', 'tvos', 'watchos', 'emscripten', 'wasi' -+ )): - name = os.fsdecode(os_helper.TESTFN_UNDECODABLE) - elif os_helper.TESTFN_NONASCII: - name = os_helper.TESTFN_NONASCII -diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py -index 203dd6fe57..a4e7099da3 100644 ---- a/Lib/test/test_fcntl.py -+++ b/Lib/test/test_fcntl.py -@@ -6,7 +6,7 @@ - import struct - import sys - import unittest --from test.support import verbose, cpython_only, get_pagesize -+from test.support import cpython_only, get_pagesize, is_apple_mobile, requires_subprocess, verbose - from test.support.import_helper import import_module - from test.support.os_helper import TESTFN, unlink - -@@ -57,7 +57,9 @@ - start_len = "qq" - - if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd')) -- or sys.platform == 'darwin'): -+ or sys.platform == 'darwin' -+ or is_apple_mobile -+ ): - if struct.calcsize('l') == 8: - off_t = 'l' - pid_t = 'i' -@@ -157,6 +159,7 @@ - self.assertRaises(TypeError, fcntl.flock, 'spam', fcntl.LOCK_SH) - - @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError") -+ @requires_subprocess() - def test_lockf_exclusive(self): - self.f = open(TESTFN, 'wb+') - cmd = fcntl.LOCK_EX | fcntl.LOCK_NB -@@ -169,6 +172,7 @@ - self.assertEqual(p.exitcode, 0) - - @unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError") -+ @requires_subprocess() - def test_lockf_share(self): - self.f = open(TESTFN, 'wb+') - cmd = fcntl.LOCK_SH | fcntl.LOCK_NB -diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py -index 2f191ea7a4..81115e9db8 100644 ---- a/Lib/test/test_ftplib.py -+++ b/Lib/test/test_ftplib.py -@@ -18,6 +18,7 @@ - - from unittest import TestCase, skipUnless - from test import support -+from test.support import requires_subprocess - from test.support import threading_helper - from test.support import socket_helper - from test.support import warnings_helper -@@ -900,6 +901,7 @@ - - - @skipUnless(ssl, "SSL not available") -+@requires_subprocess() - class TestTLS_FTPClassMixin(TestFTPClass): - """Repeat TestFTPClass tests starting the TLS layer for both control - and data connections first. -@@ -916,6 +918,7 @@ - - - @skipUnless(ssl, "SSL not available") -+@requires_subprocess() - class TestTLS_FTPClass(TestCase): - """Specific TLS_FTP class tests.""" - -diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py -index 4f311c2d49..c0a6a48dea 100644 ---- a/Lib/test/test_genericpath.py -+++ b/Lib/test/test_genericpath.py -@@ -488,7 +488,9 @@ - # invalid UTF-8 name. Windows allows creating a directory with an - # arbitrary bytes name, but fails to enter this directory - # (when the bytes name is used). -- and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')): -+ and sys.platform not in ( -+ 'win32', 'darwin', 'ios', 'tvos', 'watchos', 'emscripten', 'wasi' -+ )): - name = os_helper.TESTFN_UNDECODABLE - elif os_helper.TESTFN_NONASCII: - name = os_helper.TESTFN_NONASCII -diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py -index 9fa6ecf9c0..01dc990b1e 100644 ---- a/Lib/test/test_httpservers.py -+++ b/Lib/test/test_httpservers.py -@@ -30,7 +30,9 @@ - - import unittest - from test import support -+from test.support import is_apple_mobile - from test.support import os_helper -+from test.support import requires_subprocess - from test.support import threading_helper - - support.requires_working_socket(module=True) -@@ -410,8 +412,8 @@ - reader.close() - return body - -- @unittest.skipIf(sys.platform == 'darwin', -- 'undecodable name cannot always be decoded on macOS') -+ @unittest.skipIf(sys.platform == 'darwin' or is_apple_mobile, -+ 'undecodable name cannot always be decoded on Apple platforms') - @unittest.skipIf(sys.platform == 'win32', - 'undecodable name cannot be decoded on win32') - @unittest.skipUnless(os_helper.TESTFN_UNDECODABLE, -@@ -422,9 +424,9 @@ - with open(os.path.join(self.tempdir, filename), 'wb') as f: - f.write(os_helper.TESTFN_UNDECODABLE) - response = self.request(self.base_url + '/') -- if sys.platform == 'darwin': -- # On Mac OS the HFS+ filesystem replaces bytes that aren't valid -- # UTF-8 into a percent-encoded value. -+ if sys.platform == 'darwin' or is_apple_mobile: -+ # On Apple platforms the HFS+ filesystem replaces bytes that -+ # aren't valid UTF-8 into a percent-encoded value. - for name in os.listdir(self.tempdir): - if name != 'test': # Ignore a filename created in setUp(). - filename = name -@@ -697,6 +699,7 @@ - - @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, - "This test can't be run reliably as root (issue #13308).") -+@requires_subprocess() - class CGIHTTPServerTestCase(BaseTestCase): - class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler): - _test_case_self = None # populated by each setUp() method call. -diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py -index aa465c70df..16337bb12b 100644 ---- a/Lib/test/test_import/__init__.py -+++ b/Lib/test/test_import/__init__.py -@@ -5,7 +5,7 @@ - import importlib.util - from importlib._bootstrap_external import _get_sourcefile - from importlib.machinery import ( -- BuiltinImporter, ExtensionFileLoader, FrozenImporter, SourceFileLoader, -+ AppleFrameworkLoader, BuiltinImporter, ExtensionFileLoader, FrozenImporter, SourceFileLoader, - ) - import marshal - import os -@@ -25,7 +25,7 @@ - - from test.support import os_helper - from test.support import ( -- STDLIB_DIR, swap_attr, swap_item, cpython_only, is_emscripten, -+ STDLIB_DIR, swap_attr, swap_item, cpython_only, is_apple_mobile, is_emscripten, - is_wasi, run_in_subinterp, run_in_subinterp_with_config, Py_TRACE_REFS) - from test.support.import_helper import ( - forget, make_legacy_pyc, unlink, unload, ready_to_import, -@@ -66,6 +66,7 @@ - MODULE_KINDS = { - BuiltinImporter: 'built-in', - ExtensionFileLoader: 'extension', -+ AppleFrameworkLoader: 'framework extension', - FrozenImporter: 'frozen', - SourceFileLoader: 'pure Python', - } -@@ -91,7 +92,10 @@ - assert module.__spec__.origin == 'built-in', module.__spec__ - - def require_extension(module, *, skip=False): -- _require_loader(module, ExtensionFileLoader, skip) -+ if is_apple_mobile: -+ _require_loader(module, AppleFrameworkLoader, skip) -+ else: -+ _require_loader(module, ExtensionFileLoader, skip) - - def require_frozen(module, *, skip=True): - module = _require_loader(module, FrozenImporter, skip) -@@ -360,7 +364,7 @@ - self.assertEqual(cm.exception.path, _testcapi.__file__) - self.assertRegex( - str(cm.exception), -- r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|pyd)\)" -+ r"cannot import name 'i_dont_exist' from '_testcapi' \(.*\.(so|dylib|pyd)\)" - ) - else: - self.assertEqual( -@@ -1678,6 +1682,12 @@ - os.set_blocking(r, False) - return (r, w) - -+ def create_extension_loader(self, modname, filename): -+ if is_apple_mobile: -+ return AppleFrameworkLoader(modname, filename, None) -+ else: -+ return ExtensionFileLoader(modname, filename) -+ - def import_script(self, name, fd, filename=None, check_override=None): - override_text = '' - if check_override is not None: -@@ -1872,7 +1882,7 @@ - def test_multi_init_extension_non_isolated_compat(self): - modname = '_test_non_isolated' - filename = _testmultiphase.__file__ -- loader = ExtensionFileLoader(modname, filename) -+ loader = self.create_extension_loader(modname, filename) - spec = importlib.util.spec_from_loader(modname, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) -@@ -1890,7 +1900,7 @@ - def test_multi_init_extension_per_interpreter_gil_compat(self): - modname = '_test_shared_gil_only' - filename = _testmultiphase.__file__ -- loader = ExtensionFileLoader(modname, filename) -+ loader = self.create_extension_loader(modname, filename) - spec = importlib.util.spec_from_loader(modname, loader) - module = importlib.util.module_from_spec(spec) - loader.exec_module(module) -@@ -2020,10 +2030,13 @@ - @classmethod - def setUpClass(cls): - spec = importlib.util.find_spec(cls.NAME) -- from importlib.machinery import ExtensionFileLoader -+ from importlib.machinery import AppleFrameworkLoader, ExtensionFileLoader - cls.FILE = spec.origin - cls.LOADER = type(spec.loader) -- assert cls.LOADER is ExtensionFileLoader -+ if is_apple_mobile: -+ assert cls.LOADER is AppleFrameworkLoader -+ else: -+ assert cls.LOADER is ExtensionFileLoader - - # Start fresh. - cls.clean_up() -@@ -2063,7 +2076,10 @@ - """ - # This is essentially copied from the old imp module. - from importlib._bootstrap import _load -- loader = self.LOADER(name, path) -+ if is_apple_mobile: -+ loader = self.LOADER(name, path, None) -+ else: -+ loader = self.LOADER(name, path) - - # Issue bpo-24748: Skip the sys.modules check in _load_module_shim; - # always load new extension. -diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py -index 1d5b6e7a5d..519a1c536b 100644 ---- a/Lib/test/test_importlib/extension/test_finder.py -+++ b/Lib/test/test_importlib/extension/test_finder.py -@@ -1,3 +1,4 @@ -+from test.support import is_apple_mobile - from test.test_importlib import abc, util - - machinery = util.import_importlib('importlib.machinery') -@@ -11,6 +12,8 @@ - """Test the finder for extension modules.""" - - def setUp(self): -+ if is_apple_mobile: -+ raise unittest.SkipTest(f"{sys.platform} uses a custom finder") - if not self.machinery.EXTENSION_SUFFIXES: - raise unittest.SkipTest("Requires dynamic loading support.") - if util.EXTENSIONS.name in sys.builtin_module_names: -diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py -index 64c8a54851..fe3219c885 100644 ---- a/Lib/test/test_importlib/extension/test_loader.py -+++ b/Lib/test/test_importlib/extension/test_loader.py -@@ -1,3 +1,4 @@ -+from test.support import is_apple_mobile - from test.test_importlib import abc, util - - machinery = util.import_importlib('importlib.machinery') -@@ -16,6 +17,8 @@ - """Test ExtensionFileLoader.""" - - def setUp(self): -+ if is_apple_mobile: -+ raise unittest.SkipTest(f"{sys.platform} uses a custom loader") - if not self.machinery.EXTENSION_SUFFIXES: - raise unittest.SkipTest("Requires dynamic loading support.") - if util.EXTENSIONS.name in sys.builtin_module_names: -diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py -index 022cf21a47..67f484d40e 100644 ---- a/Lib/test/test_io.py -+++ b/Lib/test/test_io.py -@@ -40,6 +40,7 @@ - from test.support.script_helper import ( - assert_python_ok, assert_python_failure, run_python_until_end) - from test.support import import_helper -+from test.support import is_apple_mobile - from test.support import os_helper - from test.support import threading_helper - from test.support import warnings_helper -@@ -605,7 +606,7 @@ - # On Windows and Mac OSX this test consumes large resources; It takes - # a long time to build the >2 GiB file and takes >2 GiB of disk space - # therefore the resource must be enabled to run this test. -- if sys.platform[:3] == 'win' or sys.platform == 'darwin': -+ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or is_apple_mobile: - support.requires( - 'largefile', - 'test requires %s bytes and a long time to run' % self.LARGE) -diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py -index ab969ce26a..e6aee6c7de 100644 ---- a/Lib/test/test_logging.py -+++ b/Lib/test/test_logging.py -@@ -43,6 +43,7 @@ - import tempfile - from test.support.script_helper import assert_python_ok, assert_python_failure - from test import support -+from test.support import is_apple_mobile - from test.support import os_helper - from test.support import socket_helper - from test.support import threading_helper -diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py -index 3d9d6d5d0a..dfb1d6f84d 100644 ---- a/Lib/test/test_marshal.py -+++ b/Lib/test/test_marshal.py -@@ -1,5 +1,5 @@ - from test import support --from test.support import os_helper, requires_debug_ranges -+from test.support import os_helper, requires_debug_ranges, is_apple_mobile - from test.support.script_helper import assert_python_ok - import array - import io -@@ -263,7 +263,10 @@ - elif sys.platform == 'wasi': - MAX_MARSHAL_STACK_DEPTH = 1500 - else: -- MAX_MARSHAL_STACK_DEPTH = 2000 -+ if is_apple_mobile: -+ MAX_MARSHAL_STACK_DEPTH = 1500 -+ else: -+ MAX_MARSHAL_STACK_DEPTH = 2000 - for i in range(MAX_MARSHAL_STACK_DEPTH - 2): - last.append([0]) - last = last[-1] -diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py -index dfcf303942..5aabfac885 100644 ---- a/Lib/test/test_mmap.py -+++ b/Lib/test/test_mmap.py -@@ -1,5 +1,5 @@ - from test.support import ( -- requires, _2G, _4G, gc_collect, cpython_only, is_emscripten -+ requires, _2G, _4G, gc_collect, cpython_only, is_emscripten, is_apple_mobile - ) - from test.support.import_helper import import_module - from test.support.os_helper import TESTFN, unlink -@@ -245,7 +245,7 @@ - with open(TESTFN, "r+b") as f: - self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4) - -- if os.name == "posix": -+ if os.name == "posix" and not is_apple_mobile: - # Try incompatible flags, prot and access parameters. - with open(TESTFN, "r+b") as f: - self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, -@@ -1007,7 +1007,7 @@ - unlink(TESTFN) - - def _make_test_file(self, num_zeroes, tail): -- if sys.platform[:3] == 'win' or sys.platform == 'darwin': -+ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or is_apple_mobile: - requires('largefile', - 'test requires %s bytes and a long time to run' % str(0x180000000)) - f = open(TESTFN, 'w+b') -diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py -index 398393b233..52b0a2ac23 100644 ---- a/Lib/test/test_os.py -+++ b/Lib/test/test_os.py -@@ -3785,6 +3785,7 @@ - self.assertGreaterEqual(size.columns, 0) - self.assertGreaterEqual(size.lines, 0) - -+ @support.requires_subprocess() - def test_stty_match(self): - """Check if stty returns the same results - -diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py -index 2169733503..842fed6a67 100644 ---- a/Lib/test/test_platform.py -+++ b/Lib/test/test_platform.py -@@ -8,7 +8,7 @@ - from unittest import mock - - from test import support --from test.support import os_helper -+from test.support import os_helper, is_apple_mobile - - FEDORA_OS_RELEASE = """\ - NAME=Fedora -@@ -328,7 +328,7 @@ - def test_mac_ver(self): - res = platform.mac_ver() - -- if platform.uname().system == 'Darwin': -+ if platform.uname().system == 'Darwin' and not is_apple_mobile: - # We are on a macOS system, check that the right version - # information is returned - output = subprocess.check_output(['sw_vers'], text=True) -@@ -360,6 +360,9 @@ - else: - self.assertEqual(res[2], 'PowerPC') - -+ @unittest.skipUnless(is_apple_mobile, 'iOS/tvOS/watchOS only test') -+ def test_ios_ver(self): -+ res = platform.ios_ver() - - @unittest.skipUnless(sys.platform == 'darwin', "OSX only test") - def test_mac_ver_with_fork(self): -@@ -472,7 +475,8 @@ - 'root:xnu-4570.71.2~1/RELEASE_X86_64'), - 'x86_64', 'i386') - arch = ('64bit', '') -- with mock.patch.object(platform, 'uname', return_value=uname), \ -+ with mock.patch.object(sys, "platform", "darwin"), \ -+ mock.patch.object(platform, 'uname', return_value=uname), \ - mock.patch.object(platform, 'architecture', return_value=arch): - for mac_ver, expected_terse, expected in [ - # darwin: mac_ver() returns empty strings -diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py -index 9d72dba159..a8b50606ac 100644 ---- a/Lib/test/test_posix.py -+++ b/Lib/test/test_posix.py -@@ -2,6 +2,7 @@ - - from test import support - from test.support import import_helper -+from test.support import is_apple_mobile - from test.support import os_helper - from test.support import warnings_helper - from test.support.script_helper import assert_python_ok -@@ -69,12 +70,19 @@ - "getpid", "getpgrp", "getppid", "getuid", "sync", - ] - -+ # getgroups can't be invoked on iOS/tvOS/watchOS. -+ if is_apple_mobile: -+ NO_ARG_FUNCTIONS.append("getgroups") -+ - for name in NO_ARG_FUNCTIONS: - posix_func = getattr(posix, name, None) - if posix_func is not None: - with self.subTest(name): -- posix_func() -- self.assertRaises(TypeError, posix_func, 1) -+ try: -+ posix_func() -+ self.assertRaises(TypeError, posix_func, 1) -+ except Exception as e: -+ self.fail('Problem invoking %s: %s' % (name, e)) - - @unittest.skipUnless(hasattr(posix, 'getresuid'), - 'test needs posix.getresuid()') -@@ -779,9 +787,10 @@ - check_stat(uid, gid) - self.assertRaises(OSError, chown_func, first_param, 0, -1) - check_stat(uid, gid) -- if 0 not in os.getgroups(): -- self.assertRaises(OSError, chown_func, first_param, -1, 0) -- check_stat(uid, gid) -+ if hasattr(os, 'getgroups') and not is_apple_mobile: -+ if 0 not in os.getgroups(): -+ self.assertRaises(OSError, chown_func, first_param, -1, 0) -+ check_stat(uid, gid) - # test illegal types - for t in str, float: - self.assertRaises(TypeError, chown_func, first_param, t(uid), gid) -@@ -1129,7 +1138,7 @@ - self.assertIsInstance(hi, int) - self.assertGreaterEqual(hi, lo) - # OSX evidently just returns 15 without checking the argument. -- if sys.platform != "darwin": -+ if sys.platform != 'darwin' and not is_apple_mobile: - self.assertRaises(OSError, posix.sched_get_priority_min, -23) - self.assertRaises(OSError, posix.sched_get_priority_max, -23) - -@@ -1899,11 +1908,13 @@ - - - @unittest.skipUnless(hasattr(os, 'posix_spawn'), "test needs os.posix_spawn") -+@support.requires_subprocess() - class TestPosixSpawn(unittest.TestCase, _PosixSpawnMixin): - spawn_func = getattr(posix, 'posix_spawn', None) - - - @unittest.skipUnless(hasattr(os, 'posix_spawnp'), "test needs os.posix_spawnp") -+@support.requires_subprocess() - class TestPosixSpawnP(unittest.TestCase, _PosixSpawnMixin): - spawn_func = getattr(posix, 'posix_spawnp', None) - -diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py -index f31a68c5d8..062a7524dd 100644 ---- a/Lib/test/test_pty.py -+++ b/Lib/test/test_pty.py -@@ -1,11 +1,15 @@ -+import sys -+import unittest - from test.support import verbose, reap_children -+from test.support import is_apple_mobile, is_emscripten, is_wasi - from test.support.import_helper import import_module - - # Skip these tests if termios or fcntl are not available - import_module('termios') --# fcntl is a proxy for not being one of the wasm32 platforms even though we --# don't use this module... a proper check for what crashes those is needed. --import_module("fcntl") -+ -+# Skip tests on WASM platforms, plus iOS/tvOS/watchOS -+if is_apple_mobile or is_emscripten or is_wasi: -+ raise unittest.SkipTest(f"pty tests not required on {sys.platform}") - - import errno - import os -@@ -16,7 +20,6 @@ - import signal - import socket - import io # readline --import unittest - import warnings - - TEST_STRING_1 = b"I wish to buy a fish license.\n" -diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py -index 677349c2bf..f4471bdf8c 100644 ---- a/Lib/test/test_selectors.py -+++ b/Lib/test/test_selectors.py -@@ -526,7 +526,7 @@ - try: - fds = s.select() - except OSError as e: -- if e.errno == errno.EINVAL and sys.platform == 'darwin': -+ if e.errno == errno.EINVAL and (sys.platform == 'darwin' or support.is_apple_mobile): - # unexplainable errors on macOS don't need to fail the test - self.skipTest("Invalid argument error calling poll()") - raise -diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py -index d231e66b7b..182eeaaca4 100644 ---- a/Lib/test/test_shutil.py -+++ b/Lib/test/test_shutil.py -@@ -2051,6 +2051,7 @@ - check_chown(dirname, uid, gid) - - -+@support.requires_subprocess() - class TestWhich(BaseTest, unittest.TestCase): - - def setUp(self): -@@ -3055,6 +3056,7 @@ - self.assertGreaterEqual(size.lines, 0) - - @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty") -+ @support.requires_subprocess() - @unittest.skipUnless(hasattr(os, 'get_terminal_size'), - 'need os.get_terminal_size()') - def test_stty_match(self): -diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py -index f2ae28c38d..f1f5c56eb8 100644 ---- a/Lib/test/test_signal.py -+++ b/Lib/test/test_signal.py -@@ -12,6 +12,7 @@ - import time - import unittest - from test import support -+from test.support import is_apple_mobile - from test.support import os_helper - from test.support.script_helper import assert_python_ok, spawn_python - from test.support import threading_helper -@@ -806,7 +807,7 @@ - self.assertEqual(self.hndl_called, True) - - # Issue 3864, unknown if this affects earlier versions of freebsd also -- @unittest.skipIf(sys.platform in ('netbsd5',), -+ @unittest.skipIf(sys.platform in ('netbsd5',) or is_apple_mobile, - 'itimer not reliable (does not mix well with threading) on some BSDs.') - def test_itimer_virtual(self): - self.itimer = signal.ITIMER_VIRTUAL -@@ -1242,6 +1243,8 @@ - - @unittest.skipUnless(hasattr(signal, "setitimer"), - "test needs setitimer()") -+ @unittest.skipIf(is_apple_mobile, -+ f"{sys.platform} doesn't support setitimer().") - def test_stress_delivery_dependent(self): - """ - This test uses dependent signal handlers. -@@ -1288,6 +1291,8 @@ - - @unittest.skipUnless(hasattr(signal, "setitimer"), - "test needs setitimer()") -+ @unittest.skipIf(is_apple_mobile, -+ f"{sys.platform} doesn't support setitimer().") - def test_stress_delivery_simultaneous(self): - """ - This test uses simultaneous signal handlers. -@@ -1321,6 +1326,7 @@ - @unittest.skipUnless(hasattr(signal, "SIGUSR1"), - "test needs SIGUSR1") - @threading_helper.requires_working_threading() -+ @unittest.skipIf(is_apple_mobile, "too stressful for iOS") - def test_stress_modifying_handlers(self): - # bpo-43406: race condition between trip_signal() and signal.signal - signum = signal.SIGUSR1 -diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py -index 86701caf05..155c4c458c 100644 ---- a/Lib/test/test_socket.py -+++ b/Lib/test/test_socket.py -@@ -1,5 +1,6 @@ - import unittest - from test import support -+from test.support import is_apple_mobile - from test.support import os_helper - from test.support import socket_helper - from test.support import threading_helper -@@ -1154,7 +1155,7 @@ - # I've ordered this by protocols that have both a tcp and udp - # protocol, at least for modern Linuxes. - if (sys.platform.startswith(('freebsd', 'netbsd', 'gnukfreebsd')) -- or sys.platform in ('linux', 'darwin')): -+ or sys.platform in ('linux', 'darwin') or is_apple_mobile): - # avoid the 'echo' service on this platform, as there is an - # assumption breaking non-standard port/protocol entry - services = ('daytime', 'qotd', 'domain') -@@ -3665,7 +3666,7 @@ - def _testFDPassCMSG_LEN(self): - self.createAndSendFDs(1) - -- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") -+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958") - @unittest.skipIf(AIX, "skipping, see issue #22397") - @requireAttrs(socket, "CMSG_SPACE") - def testFDPassSeparate(self): -@@ -3676,7 +3677,7 @@ - maxcmsgs=2) - - @testFDPassSeparate.client_skip -- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") -+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958") - @unittest.skipIf(AIX, "skipping, see issue #22397") - def _testFDPassSeparate(self): - fd0, fd1 = self.newFDs(2) -@@ -3689,7 +3690,7 @@ - array.array("i", [fd1]))]), - len(MSG)) - -- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") -+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958") - @unittest.skipIf(AIX, "skipping, see issue #22397") - @requireAttrs(socket, "CMSG_SPACE") - def testFDPassSeparateMinSpace(self): -@@ -3703,7 +3704,7 @@ - maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC) - - @testFDPassSeparateMinSpace.client_skip -- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") -+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958") - @unittest.skipIf(AIX, "skipping, see issue #22397") - def _testFDPassSeparateMinSpace(self): - fd0, fd1 = self.newFDs(2) -@@ -3727,7 +3728,7 @@ - nbytes = self.sendmsgToServer([msg]) - self.assertEqual(nbytes, len(msg)) - -- @unittest.skipIf(sys.platform == "darwin", "see issue #24725") -+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958") - def testFDPassEmpty(self): - # Try to pass an empty FD array. Can receive either no array - # or an empty array. -diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py -index 0f62f9eb20..d2daf044d6 100644 ---- a/Lib/test/test_socketserver.py -+++ b/Lib/test/test_socketserver.py -@@ -8,12 +8,13 @@ - import select - import signal - import socket -+import sys - import threading - import unittest - import socketserver - - import test.support --from test.support import reap_children, verbose -+from test.support import is_apple_mobile, reap_children, verbose - from test.support import os_helper - from test.support import socket_helper - from test.support import threading_helper -diff --git a/Lib/test/test_sqlite3/test_dbapi.py b/Lib/test/test_sqlite3/test_dbapi.py -index f3efe0f52f..ff29b98a80 100644 ---- a/Lib/test/test_sqlite3/test_dbapi.py -+++ b/Lib/test/test_sqlite3/test_dbapi.py -@@ -31,7 +31,7 @@ - - from test.support import ( - SHORT_TIMEOUT, check_disallow_instantiation, requires_subprocess, -- is_emscripten, is_wasi -+ is_apple_mobile, is_emscripten, is_wasi - ) - from test.support import gc_collect - from test.support import threading_helper -@@ -667,7 +667,7 @@ - cx.execute(self._sql) - - @unittest.skipIf(sys.platform == "win32", "skipped on Windows") -- @unittest.skipIf(sys.platform == "darwin", "skipped on macOS") -+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipped on Apple platforms") - @unittest.skipIf(is_emscripten or is_wasi, "not supported on Emscripten/WASI") - @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") - def test_open_with_undecodable_path(self): -@@ -713,7 +713,7 @@ - cx.execute(self._sql) - - @unittest.skipIf(sys.platform == "win32", "skipped on Windows") -- @unittest.skipIf(sys.platform == "darwin", "skipped on macOS") -+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipped on Apple platforms") - @unittest.skipIf(is_emscripten or is_wasi, "not supported on Emscripten/WASI") - @unittest.skipUnless(TESTFN_UNDECODABLE, "only works if there are undecodable paths") - def test_open_undecodable_uri(self): -diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index 2a6813f00b..1a65e8f44d 100644 ---- a/Lib/test/test_sysconfig.py -+++ b/Lib/test/test_sysconfig.py -@@ -6,7 +6,7 @@ - from copy import copy - - from test.support import ( -- captured_stdout, PythonSymlink, requires_subprocess, is_wasi -+ captured_stdout, PythonSymlink, requires_subprocess, is_apple_mobile, is_wasi - ) - from test.support.import_helper import import_module - from test.support.os_helper import (TESTFN, unlink, skip_unless_symlink, -@@ -333,12 +333,14 @@ - # XXX more platforms to tests here - - @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds") -+ @unittest.skipIf(is_apple_mobile, -+ f"{sys.platform} doesn't distribute config.h in the runtime environment") - def test_get_config_h_filename(self): - config_h = sysconfig.get_config_h_filename() - self.assertTrue(os.path.isfile(config_h), config_h) - - def test_get_scheme_names(self): -- wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv'] -+ wanted = ['ios', 'nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv', 'tvos', 'watchos'] - if HAS_USER_BASE: - wanted.extend(['nt_user', 'osx_framework_user', 'posix_user']) - self.assertEqual(get_scheme_names(), tuple(sorted(wanted))) -@@ -410,6 +412,8 @@ - self.assertTrue(library.startswith(f'python{major}{minor}')) - self.assertTrue(library.endswith('.dll')) - self.assertEqual(library, ldlibrary) -+ elif is_apple_mobile: -+ self.assertEqual(ldlibrary, "Python.framework/Python") ++ elif sys.platform == "tvos": ++ release = get_config_vars().get("TVOS_DEPLOYMENT_TARGET", "9.0") ++ osname = sys.platform ++ machine = sys.implementation._multiarch ++ elif sys.platform == "watchos": ++ release = get_config_vars().get("WATCHOS_DEPLOYMENT_TARGET", "4.0") + osname = sys.platform + machine = sys.implementation._multiarch else: - self.assertTrue(library.startswith(f'libpython{major}.{minor}')) - self.assertTrue(library.endswith('.a')) -@@ -460,6 +464,8 @@ - self.assertEqual(my_platform, test_platform) - - @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds") -+ @unittest.skipIf(is_apple_mobile, -+ f"{sys.platform} doesn't distribute config.h in the runtime environment") - def test_srcdir(self): - # See Issues #15322, #15364. - srcdir = sysconfig.get_config_var('srcdir') -@@ -526,6 +532,8 @@ - @unittest.skipIf(sys.platform.startswith('win'), - 'Test is not Windows compatible') - @unittest.skipIf(is_wasi, "Incompatible with WASI mapdir and OOT builds") -+ @unittest.skipIf(is_apple_mobile, -+ f"{sys.platform} doesn't distribute config.h in the runtime environment") - def test_get_makefile_filename(self): - makefile = sysconfig.get_makefile_filename() - self.assertTrue(os.path.isfile(makefile), makefile) -diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py -index 00a64372b3..539db5d7d7 100644 ---- a/Lib/test/test_threading.py -+++ b/Lib/test/test_threading.py -@@ -3,7 +3,7 @@ - """ - - import test.support --from test.support import threading_helper, requires_subprocess -+from test.support import threading_helper, requires_subprocess, is_apple_mobile - from test.support import verbose, cpython_only, os_helper - from test.support.import_helper import import_module - from test.support.script_helper import assert_python_ok, assert_python_failure -@@ -1250,6 +1250,7 @@ - os.set_blocking(r, False) - return (r, w) - -+ @unittest.skipIf(is_apple_mobile, "%s doesn't have os.pipe" % sys.platform) - def test_threads_join(self): - # Non-daemon threads should be joined at subinterpreter shutdown - # (issue #18808) -@@ -1278,6 +1279,7 @@ - # The thread was joined properly. - self.assertEqual(os.read(r, 1), b"x") - -+ @unittest.skipIf(is_apple_mobile, "%s doesn't have os.pipe" % sys.platform) - def test_threads_join_2(self): - # Same as above, but a delay gets introduced after the thread's - # Python code returned but before the thread state is deleted. -diff --git a/Lib/test/test_unicode_file_functions.py b/Lib/test/test_unicode_file_functions.py -index 47619c8807..3f36be1a49 100644 ---- a/Lib/test/test_unicode_file_functions.py -+++ b/Lib/test/test_unicode_file_functions.py -@@ -5,7 +5,7 @@ - import unittest - import warnings - from unicodedata import normalize --from test.support import os_helper -+from test.support import is_apple_mobile, os_helper - from test import support - - -@@ -23,13 +23,13 @@ - '10_\u1fee\u1ffd', - ] - --# Mac OS X decomposes Unicode names, using Normal Form D. -+# Apple platforms decompose Unicode names, using Normal Form D. - # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html - # "However, most volume formats do not follow the exact specification for - # these normal forms. For example, HFS Plus uses a variant of Normal Form D - # in which U+2000 through U+2FFF, U+F900 through U+FAFF, and U+2F800 through - # U+2FAFF are not decomposed." --if sys.platform != 'darwin': -+if sys.platform != 'darwin' and not is_apple_mobile: - filenames.extend([ - # Specific code points: NFC(fn), NFD(fn), NFKC(fn) and NFKD(fn) all different - '11_\u0385\u03d3\u03d4', -@@ -123,7 +123,7 @@ - # NFD (a variant of Unicode NFD form). Normalize the filename to NFC, NFKC, - # NFKD in Python is useless, because darwin will normalize it later and so - # open(), os.stat(), etc. don't raise any exception. -- @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') -+ @unittest.skipIf(sys.platform == 'darwin' or is_apple_mobile, 'irrelevant test on Apple platforms') - @unittest.skipIf( - support.is_emscripten or support.is_wasi, - "test fails on Emscripten/WASI when host platform is macOS." -@@ -145,7 +145,7 @@ - # Skip the test on darwin, because darwin uses a normalization different - # than Python NFD normalization: filenames are different even if we use - # Python NFD normalization. -- @unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X') -+ @unittest.skipIf(sys.platform == 'darwin' or is_apple_mobile, 'irrelevant test on Apple platforms') - def test_listdir(self): - sf0 = set(self.files) - with warnings.catch_warnings(): -diff --git a/Lib/test/test_unittest/test_break.py b/Lib/test/test_unittest/test_break.py -index 1da98af3e7..d413d5a478 100644 ---- a/Lib/test/test_unittest/test_break.py -+++ b/Lib/test/test_unittest/test_break.py -@@ -11,6 +11,8 @@ - - @unittest.skipUnless(hasattr(os, 'kill'), "Test requires os.kill") - @unittest.skipIf(sys.platform =="win32", "Test cannot run on Windows") -+@unittest.skipIf(support.is_apple_mobile, -+ f"{sys.platform} doesn't support SIGINT.") - class TestBreak(unittest.TestCase): - int_handler = None - # This number was smart-guessed, previously tests were failing -diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py -index 99c9e24994..fa528a6758 100644 ---- a/Lib/test/test_urllib2.py -+++ b/Lib/test/test_urllib2.py -@@ -1,6 +1,7 @@ - import unittest - from test import support - from test.support import os_helper -+from test.support import requires_subprocess - from test.support import warnings_helper - from test import test_urllib - from unittest import mock -@@ -998,6 +999,7 @@ - - file_obj.close() - -+ @requires_subprocess() - def test_http_body_pipe(self): - # A file reading from a pipe. - # A pipe cannot be seek'ed. There is no way to determine the -diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py -index 890672c5d2..dce68e1e40 100644 ---- a/Lib/test/test_venv.py -+++ b/Lib/test/test_venv.py -@@ -19,7 +19,7 @@ - import tempfile - from test.support import (captured_stdout, captured_stderr, - skip_if_broken_multiprocessing_synchronize, verbose, -- requires_subprocess, is_emscripten, is_wasi, -+ requires_subprocess, is_apple_mobile, is_emscripten, is_wasi, - requires_venv_with_pip, TEST_HOME_DIR, - requires_resource, copy_python_src_ignore) - from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree) -@@ -41,6 +41,8 @@ - - if is_emscripten or is_wasi: - raise unittest.SkipTest("venv is not available on Emscripten/WASI.") -+if is_apple_mobile: -+ raise unittest.SkipTest("venv is not available on mobile Apple platforms.") - - @requires_subprocess() - def check_output(cmd, encoding=None): -diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py -index 8b0628745c..2d8de8aecb 100755 ---- a/Lib/webbrowser.py -+++ b/Lib/webbrowser.py -@@ -541,6 +541,57 @@ - - # what to do if _tryorder is now empty? - -+# -+# Platform support for iOS -+# -+if sys.platform == 'ios': -+ class MobileSafari(BaseBrowser): -+ def open(self, url, new=0, autoraise=True): -+ # This code is the equivalent of: -+ # NSURL *nsurl = [NSURL URLWithString:url]; -+ # [[UIApplication sharedApplication] openURL:nsurl]; -+ from ctypes import cdll, c_void_p, c_char_p, c_uint32 -+ from ctypes import util -+ objc = cdll.LoadLibrary(util.find_library(b'objc')) -+ cf = cdll.LoadLibrary(util.find_library(b'CoreFoundation')) -+ objc.objc_getClass.restype = c_void_p -+ objc.objc_getClass.argtypes = [c_char_p] -+ objc.sel_registerName.restype = c_void_p -+ objc.sel_registerName.argtypes = [c_char_p] -+ cf.CFStringCreateWithCString.restype = c_void_p -+ cf.CFStringCreateWithCString.argtypes = [c_void_p, c_char_p, c_uint32] -+ -+ # Get an NSString describing the URL -+ kCFStringEncodingUTF8 = 0x08000100 -+ url = c_void_p(cf.CFStringCreateWithCString(None, url.encode('utf-8'), kCFStringEncodingUTF8)) -+ autorelease = c_void_p(objc.sel_registerName(b'autorelease')) -+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p] -+ objc.objc_msgSend.restype = c_void_p -+ objc.objc_msgSend(url, autorelease) -+ -+ # Get an NSURL object representing the URL -+ NSURL = c_void_p(objc.objc_getClass(b'NSURL')) -+ urlWithString_ = c_void_p(objc.sel_registerName(b'URLWithString:')) -+ objc.objc_msgSend.restype = c_void_p -+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p] -+ nsurl = c_void_p(objc.objc_msgSend(NSURL, urlWithString_, url)) -+ -+ # Get the shared UIApplication instance -+ UIApplication = c_void_p(objc.objc_getClass(b'UIApplication')) -+ sharedApplication = c_void_p(objc.sel_registerName(b'sharedApplication')) -+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p] -+ objc.objc_msgSend.restype = c_void_p -+ shared_app = c_void_p(objc.objc_msgSend(UIApplication, sharedApplication)) -+ -+ # Open the URL on the shared application -+ openURL_ = c_void_p(objc.sel_registerName(b'openURL:')) -+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p] -+ objc.objc_msgSend.restype = None -+ objc.objc_msgSend(shared_app, openURL_, nsurl) -+ -+ return True -+ -+ register("mobilesafari", None, MobileSafari(), preferred=True) - - # - # Platform support for Windows +--- /dev/null ++++ b/Mac/Resources/app-store-compliance.patch +@@ -0,0 +1,29 @@ ++diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py ++index d6c83a75c1c..19ed4e01091 100644 ++--- a/Lib/test/test_urlparse.py +++++ b/Lib/test/test_urlparse.py ++@@ -237,11 +237,6 @@ def test_roundtrips(self): ++ '','',''), ++ ('git+ssh', 'git@github.com','/user/project.git', ++ '', '')), ++- ('itms-services://?action=download-manifest&url=https://example.com/app', ++- ('itms-services', '', '', '', ++- 'action=download-manifest&url=https://example.com/app', ''), ++- ('itms-services', '', '', ++- 'action=download-manifest&url=https://example.com/app', '')), ++ ('+scheme:path/to/file', ++ ('', '', '+scheme:path/to/file', '', '', ''), ++ ('', '', '+scheme:path/to/file', '', '')), ++diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py ++index 8f724f907d4..148caf742c9 100644 ++--- a/Lib/urllib/parse.py +++++ b/Lib/urllib/parse.py ++@@ -59,7 +59,7 @@ ++ 'imap', 'wais', 'file', 'mms', 'https', 'shttp', ++ 'snews', 'prospero', 'rtsp', 'rtsps', 'rtspu', 'rsync', ++ 'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh', ++- 'ws', 'wss', 'itms-services'] +++ 'ws', 'wss'] ++ ++ uses_params = ['', 'ftp', 'hdl', 'prospero', 'http', 'imap', ++ 'https', 'shttp', 'rtsp', 'rtsps', 'rtspu', 'sip', diff --git a/Makefile.pre.in b/Makefile.pre.in -index 4996c5c309..7571c5f4ad 100644 +index 76653f399f4..ab2a67040d1 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in -@@ -184,6 +184,8 @@ - PYTHONFRAMEWORKDIR= @PYTHONFRAMEWORKDIR@ - PYTHONFRAMEWORKPREFIX= @PYTHONFRAMEWORKPREFIX@ - PYTHONFRAMEWORKINSTALLDIR= @PYTHONFRAMEWORKINSTALLDIR@ -+PYTHONFRAMEWORKINSTALLNAMEPREFIX= @PYTHONFRAMEWORKINSTALLNAMEPREFIX@ -+RESSRCDIR= @RESSRCDIR@ - # Deployment target selected during configure, to be checked - # by distutils. The export statement is needed to ensure that the - # deployment target is active during build. -@@ -843,7 +845,7 @@ - $(BLDSHARED) $(NO_AS_NEEDED) -o $@ -Wl,-h$@ $^ - - libpython$(LDVERSION).dylib: $(LIBRARY_OBJS) -- $(CC) -dynamiclib -Wl,-single_module $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \ -+ $(CC) -dynamiclib $(PY_CORE_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/lib/libpython$(LDVERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(DTRACE_OBJS) $(SHLIBS) $(LIBC) $(LIBM); \ - - - libpython$(VERSION).sl: $(LIBRARY_OBJS) -@@ -868,14 +870,13 @@ - # This rule is here for OPENSTEP/Rhapsody/MacOSX. It builds a temporary - # minimal framework (not including the Lib directory and such) in the current - # directory. --RESSRCDIR=Mac/Resources/framework - $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK): \ - $(LIBRARY) \ - $(RESSRCDIR)/Info.plist - $(INSTALL) -d -m $(DIRMODE) $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION) - $(CC) -o $(LDLIBRARY) $(PY_CORE_LDFLAGS) -dynamiclib \ -- -all_load $(LIBRARY) -Wl,-single_module \ -- -install_name $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \ -+ -all_load $(LIBRARY) \ -+ -install_name $(PYTHONFRAMEWORKINSTALLNAMEPREFIX)/Versions/$(VERSION)/$(PYTHONFRAMEWORK) \ - -compatibility_version $(VERSION) \ - -current_version $(VERSION) \ - -framework CoreFoundation $(LIBS); -@@ -887,6 +888,21 @@ - $(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) -@@ -1885,6 +1901,21 @@ - $(RUNSHARED) /usr/libexec/oah/translate \ - ./$(BUILDPYTHON) -E -m test -j 0 -u all $(TESTOPTS) - -+# Run the test suite on the iOS simulator. -+# Must be run on a macOS machine with a full Xcode install that has an iPhone SE -+# (3rd edition) simulator available, after running `make install` on a configuration -+# with --enable-framework="./Tools/iOSTestbed/Python.xcframework/ios-arm64_x86_64-simulator" -+XCRESULT=./build/$(MULTIARCH).$(shell date +%s).xcresult -+.PHONY: testiOS -+testiOS: -+ # Run the test suite for the Xcode project, targeting the iOS simulator. -+ # If the suite fails, extract and print the console output, then re-raise the failure -+ if ! xcodebuild test -project ./Tools/iOSTestbed/iOSTestbed.xcodeproj -scheme "iOSTestbed" -destination "platform=iOS Simulator,name=iPhone SE (3rd Generation)" -resultBundlePath $(XCRESULT) ; then \ -+ xcrun xcresulttool get --path $(XCRESULT) --id $$(xcrun xcresulttool get --path $(XCRESULT) --format json | $(PYTHON_FOR_BUILD) -c "import sys, json; result = json.load(sys.stdin); print(result['actions']['_values'][0]['actionResult']['logRef']['id']['_value'])"); \ -+ echo ; \ -+ exit 1; \ -+ fi -+ - # Like test, but using --slow-ci which enables all test resources and use - # longer timeout. Run an optional pybuildbot.identify script to include - # information about the build environment. -@@ -1924,7 +1955,7 @@ - # which can lead to two parallel `./python setup.py build` processes that - # step on each others toes. - .PHONY: install --install: @FRAMEWORKINSTALLFIRST@ commoninstall bininstall maninstall @FRAMEWORKINSTALLLAST@ -+install: @FRAMEWORKINSTALLFIRST@ @INSTALLTARGETS@ @FRAMEWORKINSTALLLAST@ - if test "x$(ENSUREPIP)" != "xno" ; then \ - case $(ENSUREPIP) in \ - upgrade) ensurepip="--upgrade" ;; \ -@@ -2507,20 +2538,36 @@ +@@ -179,6 +179,9 @@ + EXE= @EXEEXT@ + BUILDEXE= @BUILDEXEEXT@ + ++# Name of the patch file to apply for app store compliance ++APP_STORE_COMPLIANCE_PATCH=@APP_STORE_COMPLIANCE_PATCH@ ++ + # Short name and location for Mac OS X Python framework + UNIVERSALSDK=@UNIVERSALSDK@ + PYTHONFRAMEWORK= @PYTHONFRAMEWORK@ +@@ -692,7 +695,7 @@ + @grep -E '^[A-Za-z][-A-Za-z0-9]+:' Makefile | awk -F : '{print $$1}' + + .PHONY: build_all +-build_all: check-clean-src $(BUILDPYTHON) platform sharedmods \ ++build_all: check-clean-src check-app-store-compliance $(BUILDPYTHON) platform sharedmods \ + gdbhooks Programs/_testembed scripts checksharedmods rundsymutil + + .PHONY: build_wasm +@@ -715,6 +718,16 @@ exit 1; \ - else true; \ fi -- @for i in $(prefix)/Resources/English.lproj $(prefix)/lib; do\ -- if test ! -d $(DESTDIR)$$i; then \ -- echo "Creating directory $(DESTDIR)$$i"; \ -- $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$$i; \ -- else true; \ -+ # iOS/tvOS/watchOS uses a non-versioned framework with Info.plist in the -+ # framework root, no .lproj data, and binaries -+ @if test "$(MACHDEP)" = ios -o "$(MACHDEP)" = tvos -o "$(MACHDEP)" = watchos; then \ -+ if test -d $(PYTHONFRAMEWORKPREFIX)/include; then \ -+ echo "Clearing stale header symlink directory"; \ -+ rm -rf $(PYTHONFRAMEWORKPREFIX)/include; \ - fi; \ -- done -- $(LN) -fsn include/python$(LDVERSION) $(DESTDIR)$(prefix)/Headers -- sed 's/%VERSION%/'"`$(RUNSHARED) ./$(BUILDPYTHON) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(prefix)/Resources/Info.plist -- $(LN) -fsn $(VERSION) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/Current -- $(LN) -fsn Versions/Current/$(PYTHONFRAMEWORK) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/$(PYTHONFRAMEWORK) -- $(LN) -fsn Versions/Current/Headers $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers -- $(LN) -fsn Versions/Current/Resources $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Resources -- $(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY) -+ $(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; \ -+ else \ -+ for i in $(prefix)/Resources/English.lproj $(prefix)/lib; do \ -+ if test ! -d $(DESTDIR)$$i; then \ -+ echo "Creating directory $(DESTDIR)$$i"; \ -+ $(INSTALL) -d -m $(DIRMODE) $(DESTDIR)$$i; \ -+ else true; \ -+ fi; \ -+ done; \ -+ $(LN) -fsn include/python$(LDVERSION) $(DESTDIR)$(prefix)/Headers; \ -+ sed 's/%VERSION%/'"`$(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(prefix)/Resources/Info.plist; \ -+ $(LN) -fsn $(VERSION) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/Current; \ -+ $(LN) -fsn Versions/Current/$(PYTHONFRAMEWORK) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/$(PYTHONFRAMEWORK); \ -+ $(LN) -fsn Versions/Current/Headers $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Headers; \ -+ $(LN) -fsn Versions/Current/Resources $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Resources; \ -+ $(INSTALL_SHARED) $(LDLIBRARY) $(DESTDIR)$(PYTHONFRAMEWORKPREFIX)/$(LDLIBRARY); \ -+ fi - - # This installs Mac/Lib into the framework - # Install a number of symlinks to keep software that expects a normal unix -@@ -2562,6 +2609,19 @@ - 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; \ ++# Check that the app store compliance patch can be applied (if configured). ++# This is checked as a dry-run against the original library sources; ++# the patch will be actually applied during the install phase. ++.PHONY: check-app-store-compliance ++check-app-store-compliance: ++ @if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \ ++ patch --dry-run --quiet --force --strip 1 --directory "$(abs_srcdir)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)"; \ ++ echo "App store compliance patch can be applied."; \ + 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 + # Profile generation build must start from a clean tree. + profile-clean-stamp: + $(MAKE) clean +@@ -2568,6 +2581,14 @@ + $(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py \ + $(DESTDIR)$(LIBDEST); \ + $(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt ++ @ # If app store compliance has been configured, apply the patch to the ++ @ # installed library code. The patch has been previously validated against ++ @ # the original source tree, so we can ignore any errors that are raised ++ @ # due to files that are missing because of --disable-test-modules etc. ++ @if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \ ++ echo "Applying app store compliance patch"; \ ++ patch --force --reject-file "$(abs_builddir)/app-store-compliance.rej" --strip 2 --directory "$(DESTDIR)$(LIBDEST)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)" || true ; \ ++ fi + @ # Build PYC files for the 3 optimization levels (0, 1, 2) + -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ + $(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \ diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c -index 3307260544..b5db9e8a80 100644 +index ec0857a4a99..2350e9dc821 100644 --- a/Misc/platform_triplet.c +++ b/Misc/platform_triplet.c -@@ -233,7 +233,42 @@ - # error unknown platform triplet - # endif - #elif defined(__APPLE__) -+# include "TargetConditionals.h" -+# if TARGET_OS_IOS -+# if TARGET_OS_SIMULATOR +@@ -257,6 +257,26 @@ + # else + PLATFORM_TRIPLET=arm64-iphoneos + # endif ++# elif defined(TARGET_OS_TV) && TARGET_OS_TV ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR +# if __x86_64__ -+PLATFORM_TRIPLET=iphonesimulator-x86_64 ++PLATFORM_TRIPLET=x86_64-appletvsimulator +# else -+PLATFORM_TRIPLET=iphonesimulator-arm64 ++PLATFORM_TRIPLET=arm64-appletvsimulator +# endif +# else -+PLATFORM_TRIPLET=iphoneos-arm64 ++PLATFORM_TRIPLET=arm64-appletvos +# endif -+# elif TARGET_OS_TV -+# if TARGET_OS_SIMULATOR ++# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH ++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR +# if __x86_64__ -+PLATFORM_TRIPLET=appletvsimulator-x86_64 ++PLATFORM_TRIPLET=x86_64-watchsimulator +# else -+PLATFORM_TRIPLET=appletvsimulator-arm64 ++PLATFORM_TRIPLET=arm64-watchsimulator +# endif +# else -+PLATFORM_TRIPLET=appletvos-arm64 ++PLATFORM_TRIPLET=arm64_32-watchos +# endif -+# elif TARGET_OS_WATCH -+# if TARGET_OS_SIMULATOR -+# if __x86_64__ -+PLATFORM_TRIPLET=watchsimulator-x86_64 -+# else -+PLATFORM_TRIPLET=watchsimulator-arm64 -+# endif -+# else -+PLATFORM_TRIPLET=watchos-arm64_32 -+# endif -+# elif TARGET_OS_OSX + // Older macOS SDKs do not define TARGET_OS_OSX + # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX PLATFORM_TRIPLET=darwin -+# else -+# error unknown Apple platform -+# endif - #elif defined(__VXWORKS__) - PLATFORM_TRIPLET=vxworks - #elif defined(__wasm32__) -diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c -index 2898eedc3e..b48a143c34 100644 ---- a/Modules/_posixsubprocess.c -+++ b/Modules/_posixsubprocess.c -@@ -33,10 +33,20 @@ - - #include "posixmodule.h" - -+#if defined(__APPLE__) -+#include "TargetConditionals.h" -+#endif -+ - #ifdef _Py_MEMORY_SANITIZER - # include - #endif - -+// iOS/tvOS/watchOS *define* a number of POSIX functions, but you can't use them -+// because they aren't conventional multiprocess environments. -+#if TARGET_OS_IPHONE -+# undef HAVE_FORK -+#endif -+ - #if defined(__ANDROID__) && __ANDROID_API__ < 21 && !defined(SYS_getdents64) - # include - # define SYS_getdents64 __NR_getdents64 -@@ -810,11 +820,16 @@ - saved_errno = 0; - for (i = 0; exec_array[i] != NULL; ++i) { - const char *executable = exec_array[i]; -+ -+#if TARGET_OS_TV || TARGET_OS_WATCH -+ errno = ENOTSUP; -+#else - if (envp) { - execve(executable, argv, envp); - } else { - execv(executable, argv); - } -+#endif /* TARGET_OS_TV || TARGET_OS_WATCH */ - if (errno != ENOENT && errno != ENOTDIR && saved_errno == 0) { - saved_errno = errno; - } -@@ -880,7 +895,9 @@ - PyObject *preexec_fn, - PyObject *preexec_fn_args_tuple) - { -- -+/* iOS/tvOS/watchOS define the existence of fork, but it cannot be invoked; -+ * so fail fast if any attempt is made to invoke fork_exec */ -+#ifdef HAVE_FORK - pid_t pid; - - #ifdef VFORK_USABLE -@@ -915,7 +932,7 @@ - pid = fork(); - } - } else --#endif -+#endif /* VFORK_USABLE */ - { - pid = fork(); - } -@@ -948,6 +965,9 @@ - preexec_fn, preexec_fn_args_tuple); - _exit(255); - return 0; /* Dead code to avoid a potential compiler warning. */ -+#else /* HAVE_FORK */ -+ return -1; -+#endif /* HAVE_FORK */ - } - - /*[clinic input] -@@ -1028,6 +1048,10 @@ - int *c_fds_to_keep = NULL; - Py_ssize_t fds_to_keep_len = PyTuple_GET_SIZE(py_fds_to_keep); - -+/* iOS/tvOS/watchOS define the existence of fork, but it cannot be invoked; -+ * so fail fast if any attempt is made to invoke fork_exec */ -+#ifdef HAVE_FORK -+ - PyInterpreterState *interp = _PyInterpreterState_GET(); - if ((preexec_fn != Py_None) && interp->finalizing) { - PyErr_SetString(PyExc_RuntimeError, -@@ -1225,7 +1249,7 @@ - } - old_sigmask = &old_sigs; - } --#endif -+#endif /* VFORK_USABLE */ - - pid = do_fork_exec(exec_array, argv, envp, cwd, - p2cread, p2cwrite, c2pread, c2pwrite, -@@ -1258,7 +1282,7 @@ - * the thread signal mask. */ - (void) pthread_sigmask(SIG_SETMASK, old_sigmask, NULL); - } --#endif -+#endif /* VFORK_USABLE */ - - if (need_after_fork) - PyOS_AfterFork_Parent(); -@@ -1292,6 +1316,10 @@ - } - - return pid == -1 ? NULL : PyLong_FromPid(pid); -+ -+#else /* HAVE_FORK */ -+ return NULL; -+#endif - } - - /* module level code ********************************************************/ -diff --git a/Modules/getpath.c b/Modules/getpath.c -index 6f76a84e78..e91272f833 100644 ---- a/Modules/getpath.c -+++ b/Modules/getpath.c -@@ -758,7 +758,7 @@ - return winmodule_to_dict(dict, key, PyWin_DLLhModule); - } - #endif --#elif defined(WITH_NEXT_FRAMEWORK) -+#elif defined(WITH_NEXT_FRAMEWORK) && !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR - static char modPath[MAXPATHLEN + 1]; - static int modPathInitialized = -1; - if (modPathInitialized < 0) { -diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c -index a4d9466559..8f51bef22d 100644 ---- a/Modules/mathmodule.c -+++ b/Modules/mathmodule.c -@@ -199,6 +199,10 @@ - } - - -+#ifdef __APPLE__ -+# include "TargetConditionals.h" -+#endif /* __APPLE__ */ -+ - /* - sin(pi*x), giving accurate results for all finite x (especially x - integral or close to an integer). This is here for use in the -diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c -index 650ae4bbd6..f1d90ea23b 100644 ---- a/Modules/posixmodule.c -+++ b/Modules/posixmodule.c -@@ -92,6 +92,8 @@ - - #include - -+#include "TargetConditionals.h" -+ - #if defined(__has_builtin) - #if __has_builtin(__builtin_available) - #define HAVE_BUILTIN_AVAILABLE 1 -@@ -369,6 +371,11 @@ - # define fsync _commit - #endif /* ! __WATCOMC__ || __QNX__ */ - -+// iOS/tvOS/watchOS *define* getgroups, but it returns an error if used. -+#if TARGET_OS_IPHONE -+# undef HAVE_GETGROUPS -+#endif -+ - /*[clinic input] - # one of the few times we lie about this name! - module os -@@ -1548,7 +1555,9 @@ - */ - #include - #elif !defined(_MSC_VER) && (!defined(__WATCOMC__) || defined(__QNX__) || defined(__VXWORKS__)) -+# if !TARGET_OS_TV && !TARGET_OS_WATCH - extern char **environ; -+# endif - #endif /* !_MSC_VER */ - - static PyObject * -@@ -1564,6 +1573,7 @@ - d = PyDict_New(); - if (d == NULL) - return NULL; -+#if !TARGET_OS_TV && !TARGET_OS_WATCH - #ifdef MS_WINDOWS - /* _wenviron must be initialized in this way if the program is started - through main() instead of wmain(). */ -@@ -1617,6 +1627,7 @@ - Py_DECREF(k); - Py_DECREF(v); - } -+#endif /* !TARGET_OS_TV && !TARGET_OS_WATCH */ - return d; - } - -@@ -5750,6 +5761,9 @@ - /*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/ - { - long result; -+#if TARGET_OS_IPHONE -+ result = -1; -+#else - const char *bytes = PyBytes_AsString(command); - - if (PySys_Audit("os.system", "(O)", command) < 0) { -@@ -5759,6 +5773,7 @@ - Py_BEGIN_ALLOW_THREADS - result = system(bytes); - Py_END_ALLOW_THREADS -+#endif /* TARGET_OS_IPHONE */ - return result; - } - #endif -@@ -15000,6 +15015,7 @@ - int is_symlink; - int need_stat; - #endif -+#if !TARGET_OS_TV && !TARGET_OS_WATCH - #ifdef MS_WINDOWS - unsigned long dir_bits; - #endif -@@ -15060,6 +15076,7 @@ - #endif - - return result; -+#endif /* !TARGET_OS_TV && !TARGET_OS_WATCH */ - - error: - Py_XDECREF(st_mode); -diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c -index b7034369c4..a7d63abe5d 100644 ---- a/Modules/pwdmodule.c -+++ b/Modules/pwdmodule.c -@@ -1,6 +1,10 @@ - - /* UNIX password file access module */ - -+#ifdef __APPLE__ -+# include "TargetConditionals.h" -+#endif /* __APPLE__ */ -+ - #include "Python.h" - #include "posixmodule.h" - -@@ -183,6 +187,22 @@ - if (nomem == 1) { - return PyErr_NoMemory(); - } -+ -+// iPhone has a "user" with UID 501, username "mobile"; but the simulator -+// doesn't reflect this. Generate a simulated response. -+#if TARGET_IPHONE_SIMULATOR -+ if (uid == 501) { -+ struct passwd mp; -+ mp.pw_name = "mobile"; -+ mp.pw_passwd = "/smx7MYTQIi2M"; -+ mp.pw_uid = 501; -+ mp.pw_gid = 501; -+ mp.pw_gecos = "Mobile User"; -+ mp.pw_dir = "/var/mobile"; -+ mp.pw_shell = "/bin/sh"; -+ return mkpwent(module, &mp); -+ } -+#endif - PyObject *uid_obj = _PyLong_FromUid(uid); - if (uid_obj == NULL) - return NULL; -@@ -266,6 +286,22 @@ - PyErr_NoMemory(); - } - else { -+// iPhone has a "user" with UID 501, username "mobile"; but the simulator -+// doesn't reflect this. Generate a simulated response. -+#if TARGET_IPHONE_SIMULATOR -+ if (strcmp(name, "mobile") == 0) { -+ struct passwd mp; -+ mp.pw_name = "mobile"; -+ mp.pw_passwd = "/smx7MYTQIi2M"; -+ mp.pw_uid = 501; -+ mp.pw_gid = 501; -+ mp.pw_gecos = "Mobile User"; -+ mp.pw_dir = "/var/mobile"; -+ mp.pw_shell = "/bin/sh"; -+ retval = mkpwent(module, &mp); -+ goto out; -+ } -+#endif - PyErr_Format(PyExc_KeyError, - "getpwnam(): name not found: %R", name); - } -diff --git a/Modules/timemodule.c b/Modules/timemodule.c -index 6a872a285d..197eadf55f 100644 ---- a/Modules/timemodule.c -+++ b/Modules/timemodule.c -@@ -59,6 +59,10 @@ - # define HAVE_CLOCK_GETTIME_RUNTIME 1 - #endif - -+// iOS/tvOS/watchOS *define* clock_settime, but it can't be used -+#if TARGET_OS_IPHONE -+# undef HAVE_CLOCK_SETTIME -+#endif - - #define SEC_TO_NS (1000 * 1000 * 1000) - -@@ -113,6 +117,11 @@ - } - - -+#ifdef __APPLE__ -+# include "TargetConditionals.h" -+#endif /* __APPLE__ */ -+ -+ - /* Forward declarations */ - static int pysleep(_PyTime_t timeout); - -@@ -337,11 +346,13 @@ - return NULL; - } - -+#if !TARGET_OS_IPHONE - ret = clock_settime((clockid_t)clk_id, &ts); - if (ret != 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } -+#endif - Py_RETURN_NONE; - } - -diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c -index 92f2301a01..ef6db7a9bb 100644 ---- a/Python/bootstrap_hash.c -+++ b/Python/bootstrap_hash.c -@@ -40,6 +40,10 @@ - #endif - - -+#ifdef __APPLE__ -+# include "TargetConditionals.h" -+#endif /* __APPLE__ */ -+ - #ifdef Py_DEBUG - int _Py_HashSecret_Initialized = 0; - #else -@@ -185,6 +189,9 @@ - } - - #elif defined(HAVE_GETENTROPY) -+// iOS, tvOS and watchOS have an incomplete definitions of getentropy -+// so it is *found* by configure, but doesn't actually exist. -+#elif defined(HAVE_GETENTROPY) && !TARGET_OS_IPHONE - #define PY_GETENTROPY 1 - - /* Fill buffer with size pseudo-random bytes generated by getentropy(): -diff --git a/Python/dynload_shlib.c b/Python/dynload_shlib.c -index 5a37a83805..92b632af22 100644 ---- a/Python/dynload_shlib.c -+++ b/Python/dynload_shlib.c -@@ -28,6 +28,10 @@ - #define LEAD_UNDERSCORE "" - #endif - -+#ifdef __APPLE__ -+# include "TargetConditionals.h" -+#endif /* __APPLE__ */ -+ - /* The .so extension module ABI tag, supplied by the Makefile via - Makefile.pre.in and configure. This is used to discriminate between - incompatible .so files so that extensions for different Python builds can -@@ -38,12 +42,21 @@ - #ifdef __CYGWIN__ - ".dll", - #else /* !__CYGWIN__ */ -- "." SOABI ".so", --#ifdef ALT_SOABI -- "." ALT_SOABI ".so", --#endif -- ".abi" PYTHON_ABI_STRING ".so", -- ".so", -+# ifdef __APPLE__ -+# if TARGET_OS_IPHONE -+# define SHLIB_SUFFIX ".dylib" -+# else -+# define SHLIB_SUFFIX ".so" -+# endif -+# else -+# define SHLIB_SUFFIX ".so" -+# endif -+ "." SOABI SHLIB_SUFFIX, -+# ifdef ALT_SOABI -+ "." ALT_SOABI SHLIB_SUFFIX, -+# endif -+ ".abi" PYTHON_ABI_STRING SHLIB_SUFFIX, -+ SHLIB_SUFFIX, - #endif /* __CYGWIN__ */ - NULL, - }; -diff --git a/Python/marshal.c b/Python/marshal.c -index 8940582c7f..3f2d77b307 100644 ---- a/Python/marshal.c -+++ b/Python/marshal.c -@@ -14,6 +14,10 @@ - #include "pycore_setobject.h" // _PySet_NextEntry() - #include "marshal.h" // Py_MARSHAL_VERSION - -+#ifdef __APPLE__ -+# include "TargetConditionals.h" -+#endif /* __APPLE__ */ -+ - /*[clinic input] - module marshal - [clinic start generated code]*/ -@@ -33,11 +37,15 @@ - * #if defined(MS_WINDOWS) && defined(_DEBUG) - */ - #if defined(MS_WINDOWS) --#define MAX_MARSHAL_STACK_DEPTH 1000 -+# define MAX_MARSHAL_STACK_DEPTH 1000 - #elif defined(__wasi__) --#define MAX_MARSHAL_STACK_DEPTH 1500 -+# define MAX_MARSHAL_STACK_DEPTH 1500 - #else --#define MAX_MARSHAL_STACK_DEPTH 2000 -+# if TARGET_OS_IPHONE -+# define MAX_MARSHAL_STACK_DEPTH 1500 -+# else -+# define MAX_MARSHAL_STACK_DEPTH 2000 -+# endif - #endif - - #define TYPE_NULL '0' -diff --git a/Python/sysmodule.c b/Python/sysmodule.c -index 3debe7f7c1..612ba30da1 100644 ---- a/Python/sysmodule.c -+++ b/Python/sysmodule.c -@@ -55,6 +55,10 @@ - extern const char *PyWin_DLLVersionString; - #endif - -+#if defined(__APPLE__) -+#include "TargetConditionals.h" -+#endif -+ - #ifdef __EMSCRIPTEN__ - # include - #endif -@@ -3152,6 +3156,15 @@ - goto error; - #endif - -+#if TARGET_OS_IPHONE -+# if TARGET_OS_SIMULATOR -+ res = PyDict_SetItemString(impl_info, "_simulator", Py_True); -+# else -+ res = PyDict_SetItemString(impl_info, "_simulator", Py_False); -+# endif -+ if (res < 0) -+ goto error; -+#endif - /* dict ready */ - - ns = _PyNamespace_New(impl_info); ---- /dev/null -+++ b/Tools/iOSTestbed/Python.xcframework/Info.plist -@@ -0,0 +1,44 @@ -+ -+ -+ -+ -+ AvailableLibraries -+ -+ -+ BinaryPath -+ Python.framework/Python -+ LibraryIdentifier -+ ios-arm64 -+ LibraryPath -+ Python.framework -+ SupportedArchitectures -+ -+ arm64 -+ -+ SupportedPlatform -+ ios -+ -+ -+ BinaryPath -+ Python.framework/Python -+ LibraryIdentifier -+ ios-arm64_x86_64-simulator -+ LibraryPath -+ Python.framework -+ SupportedArchitectures -+ -+ arm64 -+ x86_64 -+ -+ SupportedPlatform -+ ios -+ SupportedPlatformVariant -+ simulator -+ -+ -+ CFBundlePackageType -+ XFWK -+ XCFrameworkFormatVersion -+ 1.0 -+ -+ ---- /dev/null -+++ b/Tools/iOSTestbed/Python.xcframework/ios-arm64/README -@@ -0,0 +1,4 @@ -+This directory is intentionally empty. -+ -+It should be used as a target for `--enable-framework` when compiling an iOS on-device -+build for testing purposes. ---- /dev/null -+++ b/Tools/iOSTestbed/Python.xcframework/ios-arm64_x86_64-simulator/README -@@ -0,0 +1,4 @@ -+This directory is intentionally empty. -+ -+It should be used as a target for `--enable-framework` when compiling an iOS simulator -+build for testing purposes (either x86_64 or ARM64). ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed.xcodeproj/project.pbxproj -@@ -0,0 +1,569 @@ -+// !$*UTF8*$! -+{ -+ archiveVersion = 1; -+ classes = { -+ }; -+ objectVersion = 56; -+ objects = { -+ -+/* Begin PBXBuildFile section */ -+ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66162B0EFA380010BFC8 /* AppDelegate.m */; }; -+ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607A66212B0EFA390010BFC8 /* Assets.xcassets */; }; -+ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */; }; -+ 607A66282B0EFA390010BFC8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66272B0EFA390010BFC8 /* main.m */; }; -+ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */; }; -+ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; -+ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -+ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; }; -+ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 607A664A2B0EFB310010BFC8 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -+ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */ = {isa = PBXBuildFile; fileRef = 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */; }; -+/* End PBXBuildFile section */ -+ -+/* Begin PBXContainerItemProxy section */ -+ 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */ = { -+ isa = PBXContainerItemProxy; -+ containerPortal = 607A660A2B0EFA380010BFC8 /* Project object */; -+ proxyType = 1; -+ remoteGlobalIDString = 607A66112B0EFA380010BFC8; -+ remoteInfo = iOSTestbed; -+ }; -+/* End PBXContainerItemProxy section */ -+ -+/* Begin PBXCopyFilesBuildPhase section */ -+ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */ = { -+ isa = PBXCopyFilesBuildPhase; -+ buildActionMask = 2147483647; -+ dstPath = ""; -+ dstSubfolderSpec = 10; -+ files = ( -+ 607A664D2B0EFC080010BFC8 /* Python.xcframework in Embed Frameworks */, -+ ); -+ name = "Embed Frameworks"; -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */ = { -+ isa = PBXCopyFilesBuildPhase; -+ buildActionMask = 2147483647; -+ dstPath = ""; -+ dstSubfolderSpec = 10; -+ files = ( -+ 607A66512B0EFFE00010BFC8 /* Python.xcframework in Embed Frameworks */, -+ ); -+ name = "Embed Frameworks"; -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXCopyFilesBuildPhase section */ -+ -+/* Begin PBXFileReference section */ -+ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iOSTestbed.app; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 607A66152B0EFA380010BFC8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; -+ 607A66162B0EFA380010BFC8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; -+ 607A66212B0EFA390010BFC8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; -+ 607A66242B0EFA390010BFC8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; -+ 607A66272B0EFA390010BFC8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; -+ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iOSTestbedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = iOSTestbedTests.m; sourceTree = ""; }; -+ 607A664A2B0EFB310010BFC8 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; }; -+ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "dylib-Info-template.plist"; sourceTree = ""; }; -+ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "iOSTestbed-Info.plist"; sourceTree = ""; }; -+/* End PBXFileReference section */ -+ -+/* Begin PBXFrameworksBuildPhase section */ -+ 607A660F2B0EFA380010BFC8 /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A664C2B0EFC080010BFC8 /* Python.xcframework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+ 607A662A2B0EFA3A0010BFC8 /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A66502B0EFFE00010BFC8 /* Python.xcframework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXFrameworksBuildPhase section */ -+ -+/* Begin PBXGroup section */ -+ 607A66092B0EFA380010BFC8 = { -+ isa = PBXGroup; -+ children = ( -+ 607A664A2B0EFB310010BFC8 /* Python.xcframework */, -+ 607A66142B0EFA380010BFC8 /* iOSTestbed */, -+ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */, -+ 607A66132B0EFA380010BFC8 /* Products */, -+ 607A664F2B0EFFE00010BFC8 /* Frameworks */, -+ ); -+ sourceTree = ""; -+ }; -+ 607A66132B0EFA380010BFC8 /* Products */ = { -+ isa = PBXGroup; -+ children = ( -+ 607A66122B0EFA380010BFC8 /* iOSTestbed.app */, -+ 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */, -+ ); -+ name = Products; -+ sourceTree = ""; -+ }; -+ 607A66142B0EFA380010BFC8 /* iOSTestbed */ = { -+ isa = PBXGroup; -+ children = ( -+ 607A66592B0F08600010BFC8 /* iOSTestbed-Info.plist */, -+ 607A66572B0F079F0010BFC8 /* dylib-Info-template.plist */, -+ 607A66152B0EFA380010BFC8 /* AppDelegate.h */, -+ 607A66162B0EFA380010BFC8 /* AppDelegate.m */, -+ 607A66212B0EFA390010BFC8 /* Assets.xcassets */, -+ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */, -+ 607A66272B0EFA390010BFC8 /* main.m */, -+ ); -+ path = iOSTestbed; -+ sourceTree = ""; -+ }; -+ 607A66302B0EFA3A0010BFC8 /* iOSTestbedTests */ = { -+ isa = PBXGroup; -+ children = ( -+ 607A66312B0EFA3A0010BFC8 /* iOSTestbedTests.m */, -+ ); -+ path = iOSTestbedTests; -+ sourceTree = ""; -+ }; -+ 607A664F2B0EFFE00010BFC8 /* Frameworks */ = { -+ isa = PBXGroup; -+ children = ( -+ ); -+ name = Frameworks; -+ sourceTree = ""; -+ }; -+/* End PBXGroup section */ -+ -+/* Begin PBXNativeTarget section */ -+ 607A66112B0EFA380010BFC8 /* iOSTestbed */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */; -+ buildPhases = ( -+ 607A660E2B0EFA380010BFC8 /* Sources */, -+ 607A660F2B0EFA380010BFC8 /* Frameworks */, -+ 607A66102B0EFA380010BFC8 /* Resources */, -+ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */, -+ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */, -+ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ ); -+ name = iOSTestbed; -+ productName = iOSTestbed; -+ productReference = 607A66122B0EFA380010BFC8 /* iOSTestbed.app */; -+ productType = "com.apple.product-type.application"; -+ }; -+ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */; -+ buildPhases = ( -+ 607A66292B0EFA3A0010BFC8 /* Sources */, -+ 607A662A2B0EFA3A0010BFC8 /* Frameworks */, -+ 607A662B2B0EFA3A0010BFC8 /* Resources */, -+ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */, -+ ); -+ name = iOSTestbedTests; -+ productName = iOSTestbedTests; -+ productReference = 607A662D2B0EFA3A0010BFC8 /* iOSTestbedTests.xctest */; -+ productType = "com.apple.product-type.bundle.unit-test"; -+ }; -+/* End PBXNativeTarget section */ -+ -+/* Begin PBXProject section */ -+ 607A660A2B0EFA380010BFC8 /* Project object */ = { -+ isa = PBXProject; -+ attributes = { -+ BuildIndependentTargetsInParallel = 1; -+ LastUpgradeCheck = 1500; -+ TargetAttributes = { -+ 607A66112B0EFA380010BFC8 = { -+ CreatedOnToolsVersion = 15.0.1; -+ }; -+ 607A662C2B0EFA3A0010BFC8 = { -+ CreatedOnToolsVersion = 15.0.1; -+ TestTargetID = 607A66112B0EFA380010BFC8; -+ }; -+ }; -+ }; -+ buildConfigurationList = 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */; -+ compatibilityVersion = "Xcode 14.0"; -+ developmentRegion = en; -+ hasScannedForEncodings = 0; -+ knownRegions = ( -+ en, -+ Base, -+ ); -+ mainGroup = 607A66092B0EFA380010BFC8; -+ productRefGroup = 607A66132B0EFA380010BFC8 /* Products */; -+ projectDirPath = ""; -+ projectRoot = ""; -+ targets = ( -+ 607A66112B0EFA380010BFC8 /* iOSTestbed */, -+ 607A662C2B0EFA3A0010BFC8 /* iOSTestbedTests */, -+ ); -+ }; -+/* End PBXProject section */ -+ -+/* Begin PBXResourcesBuildPhase section */ -+ 607A66102B0EFA380010BFC8 /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A66252B0EFA390010BFC8 /* LaunchScreen.storyboard in Resources */, -+ 607A66582B0F079F0010BFC8 /* dylib-Info-template.plist in Resources */, -+ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+ 607A662B2B0EFA3A0010BFC8 /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXResourcesBuildPhase section */ -+ -+/* Begin PBXShellScriptBuildPhase section */ -+ 607A66552B0F061D0010BFC8 /* Install Target Specific Python Standard Library */ = { -+ isa = PBXShellScriptBuildPhase; -+ alwaysOutOfDate = 1; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputFileListPaths = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Install Target Specific Python Standard Library"; -+ outputFileListPaths = ( -+ ); -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "set -e\n\nmkdir -p \"$CODESIGNING_FOLDER_PATH/python/lib\"\nif [ \"$EFFECTIVE_PLATFORM_NAME\" = \"-iphonesimulator\" ]; then\n echo \"Installing Python modules for iOS Simulator\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64_x86_64-simulator/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nelse\n echo \"Installing Python modules for iOS Device\"\n rsync -au --delete \"$PROJECT_DIR/Python.xcframework/ios-arm64/lib/\" \"$CODESIGNING_FOLDER_PATH/python/lib/\" \nfi\n"; -+ }; -+ 607A66562B0F06200010BFC8 /* Prepare Python Binary Modules */ = { -+ isa = PBXShellScriptBuildPhase; -+ alwaysOutOfDate = 1; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputFileListPaths = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Prepare Python Binary Modules"; -+ outputFileListPaths = ( -+ ); -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "set -e\n\ninstall_dylib () {\n INSTALL_BASE=$1\n FULL_DYLIB=$2\n\n # The name of the .dylib file\n DYLIB=$(basename \"$FULL_DYLIB\")\n # The name of the .dylib file, relative to the install base\n RELATIVE_DYLIB=${FULL_DYLIB#$CODESIGNING_FOLDER_PATH/$INSTALL_BASE/}\n # The full dotted name of the binary module, constructed from the file path.\n FULL_MODULE_NAME=$(echo $RELATIVE_DYLIB | cut -d \".\" -f 1 | tr \"/\" \".\"); \n # A bundle identifier; not actually used, but required by Xcode framework packaging\n FRAMEWORK_BUNDLE_ID=$(echo $PRODUCT_BUNDLE_IDENTIFIER.$FULL_MODULE_NAME | tr \"_\" \"-\")\n # The name of the framework folder.\n FRAMEWORK_FOLDER=\"Frameworks/$FULL_MODULE_NAME.framework\"\n\n # If the framework folder doesn't exist, create it.\n if [ ! -d \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\" ]; then\n echo \"Creating framework for $RELATIVE_DYLIB\" \n mkdir -p \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n cp \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\"\n defaults write \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\" CFBundleExecutable -string \"$DYLIB\"\n defaults write \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist\" CFBundleIdentifier -string \"$FRAMEWORK_BUNDLE_ID\" \n fi\n \n echo \"Installing binary for $RELATIVE_DYLIB\" \n mv \"$FULL_DYLIB\" \"$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER\"\n}\n\nPYTHON_VER=$(ls -1 \"$CODESIGNING_FOLDER_PATH/python/lib\")\necho \"Install Python $PYTHON_VER standard library dylibs...\"\nfind \"$CODESIGNING_FOLDER_PATH/python/lib/$PYTHON_VER/lib-dynload\" -name \"*.dylib\" | while read FULL_DYLIB; do\n install_dylib python/lib/$PYTHON_VER/lib-dynload \"$FULL_DYLIB\"\ndone\n\n# Clean up dylib template \nrm -f \"$CODESIGNING_FOLDER_PATH/dylib-Info-template.plist\"\necho \"Signing frameworks as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)...\"\nfind \"$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 \"{}\" \\; \n"; -+ }; -+/* End PBXShellScriptBuildPhase section */ -+ -+/* Begin PBXSourcesBuildPhase section */ -+ 607A660E2B0EFA380010BFC8 /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */, -+ 607A66282B0EFA390010BFC8 /* main.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+ 607A66292B0EFA3A0010BFC8 /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 607A66322B0EFA3A0010BFC8 /* iOSTestbedTests.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXSourcesBuildPhase section */ -+ -+/* Begin PBXTargetDependency section */ -+ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */ = { -+ isa = PBXTargetDependency; -+ target = 607A66112B0EFA380010BFC8 /* iOSTestbed */; -+ targetProxy = 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */; -+ }; -+/* End PBXTargetDependency section */ -+ -+/* Begin PBXVariantGroup section */ -+ 607A66232B0EFA390010BFC8 /* LaunchScreen.storyboard */ = { -+ isa = PBXVariantGroup; -+ children = ( -+ 607A66242B0EFA390010BFC8 /* Base */, -+ ); -+ name = LaunchScreen.storyboard; -+ sourceTree = ""; -+ }; -+/* End PBXVariantGroup section */ -+ -+/* Begin XCBuildConfiguration section */ -+ 607A663F2B0EFA3A0010BFC8 /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; -+ CLANG_ANALYZER_NONNULL = YES; -+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_ENABLE_OBJC_WEAK = YES; -+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_COMMA = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INFINITE_RECURSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; -+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; -+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; -+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; -+ CLANG_WARN_STRICT_PROTOTYPES = YES; -+ CLANG_WARN_SUSPICIOUS_MOVE = YES; -+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; -+ CLANG_WARN_UNREACHABLE_CODE = YES; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ COPY_PHASE_STRIP = NO; -+ DEBUG_INFORMATION_FORMAT = dwarf; -+ ENABLE_STRICT_OBJC_MSGSEND = YES; -+ ENABLE_TESTABILITY = YES; -+ ENABLE_USER_SCRIPT_SANDBOXING = YES; -+ GCC_C_LANGUAGE_STANDARD = gnu17; -+ GCC_DYNAMIC_NO_PIC = NO; -+ GCC_NO_COMMON_BLOCKS = YES; -+ GCC_OPTIMIZATION_LEVEL = 0; -+ GCC_PREPROCESSOR_DEFINITIONS = ( -+ "DEBUG=1", -+ "$(inherited)", -+ ); -+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; -+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; -+ GCC_WARN_UNDECLARED_SELECTOR = YES; -+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; -+ GCC_WARN_UNUSED_FUNCTION = YES; -+ GCC_WARN_UNUSED_VARIABLE = YES; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; -+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; -+ MTL_FAST_MATH = YES; -+ ONLY_ACTIVE_ARCH = YES; -+ SDKROOT = iphoneos; -+ }; -+ name = Debug; -+ }; -+ 607A66402B0EFA3A0010BFC8 /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; -+ CLANG_ANALYZER_NONNULL = YES; -+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_ENABLE_OBJC_WEAK = YES; -+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_COMMA = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INFINITE_RECURSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; -+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; -+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; -+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; -+ CLANG_WARN_STRICT_PROTOTYPES = YES; -+ CLANG_WARN_SUSPICIOUS_MOVE = YES; -+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; -+ CLANG_WARN_UNREACHABLE_CODE = YES; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ COPY_PHASE_STRIP = NO; -+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; -+ ENABLE_NS_ASSERTIONS = NO; -+ ENABLE_STRICT_OBJC_MSGSEND = YES; -+ ENABLE_USER_SCRIPT_SANDBOXING = YES; -+ GCC_C_LANGUAGE_STANDARD = gnu17; -+ GCC_NO_COMMON_BLOCKS = YES; -+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; -+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; -+ GCC_WARN_UNDECLARED_SELECTOR = YES; -+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; -+ GCC_WARN_UNUSED_FUNCTION = YES; -+ GCC_WARN_UNUSED_VARIABLE = YES; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES; -+ MTL_ENABLE_DEBUG_INFO = NO; -+ MTL_FAST_MATH = YES; -+ SDKROOT = iphoneos; -+ VALIDATE_PRODUCT = YES; -+ }; -+ name = Release; -+ }; -+ 607A66422B0EFA3A0010BFC8 /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; -+ CODE_SIGN_STYLE = Automatic; -+ CURRENT_PROJECT_VERSION = 1; -+ DEVELOPMENT_TEAM = 3HEZE76D99; -+ ENABLE_USER_SCRIPT_SANDBOXING = NO; -+ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; -+ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist"; -+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; -+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; -+ INFOPLIST_KEY_UIMainStoryboardFile = Main; -+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; -+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ LD_RUNPATH_SEARCH_PATHS = ( -+ "$(inherited)", -+ "@executable_path/Frameworks", -+ ); -+ MARKETING_VERSION = 3.13.0a1; -+ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ SWIFT_EMIT_LOC_STRINGS = YES; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ }; -+ name = Debug; -+ }; -+ 607A66432B0EFA3A0010BFC8 /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; -+ CODE_SIGN_STYLE = Automatic; -+ CURRENT_PROJECT_VERSION = 1; -+ DEVELOPMENT_TEAM = 3HEZE76D99; -+ ENABLE_USER_SCRIPT_SANDBOXING = NO; -+ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; -+ INFOPLIST_FILE = "iOSTestbed/iOSTestbed-Info.plist"; -+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; -+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; -+ INFOPLIST_KEY_UIMainStoryboardFile = Main; -+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; -+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ LD_RUNPATH_SEARCH_PATHS = ( -+ "$(inherited)", -+ "@executable_path/Frameworks", -+ ); -+ MARKETING_VERSION = 3.13.0a1; -+ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbed; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ SWIFT_EMIT_LOC_STRINGS = YES; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ }; -+ name = Release; -+ }; -+ 607A66452B0EFA3A0010BFC8 /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ BUNDLE_LOADER = "$(TEST_HOST)"; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; -+ CODE_SIGN_STYLE = Automatic; -+ CURRENT_PROJECT_VERSION = 1; -+ DEVELOPMENT_TEAM = 3HEZE76D99; -+ GENERATE_INFOPLIST_FILE = YES; -+ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ MARKETING_VERSION = 1.0; -+ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ SWIFT_EMIT_LOC_STRINGS = NO; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed"; -+ }; -+ name = Debug; -+ }; -+ 607A66462B0EFA3A0010BFC8 /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ BUNDLE_LOADER = "$(TEST_HOST)"; -+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; -+ CODE_SIGN_STYLE = Automatic; -+ CURRENT_PROJECT_VERSION = 1; -+ DEVELOPMENT_TEAM = 3HEZE76D99; -+ GENERATE_INFOPLIST_FILE = YES; -+ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\""; -+ IPHONEOS_DEPLOYMENT_TARGET = 12.0; -+ MARKETING_VERSION = 1.0; -+ PRODUCT_BUNDLE_IDENTIFIER = org.python.iOSTestbedTests; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ SWIFT_EMIT_LOC_STRINGS = NO; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/iOSTestbed"; -+ }; -+ name = Release; -+ }; -+/* End XCBuildConfiguration section */ -+ -+/* Begin XCConfigurationList section */ -+ 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "iOSTestbed" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 607A663F2B0EFA3A0010BFC8 /* Debug */, -+ 607A66402B0EFA3A0010BFC8 /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbed" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 607A66422B0EFA3A0010BFC8 /* Debug */, -+ 607A66432B0EFA3A0010BFC8 /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "iOSTestbedTests" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 607A66452B0EFA3A0010BFC8 /* Debug */, -+ 607A66462B0EFA3A0010BFC8 /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+/* End XCConfigurationList section */ -+ }; -+ rootObject = 607A660A2B0EFA380010BFC8 /* Project object */; -+} ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/AppDelegate.h -@@ -0,0 +1,14 @@ -+// -+// AppDelegate.h -+// iOSTestbed -+// -+// Created by Russell Keith-Magee on 23/11/2023. -+// -+ -+#import -+ -+@interface AppDelegate : UIResponder -+ -+ -+@end -+ ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/AppDelegate.m -@@ -0,0 +1,22 @@ -+// -+// AppDelegate.m -+// iOSTestbed -+// -+// Created by Russell Keith-Magee on 23/11/2023. -+// -+ -+#import "AppDelegate.h" -+ -+@interface AppDelegate () -+ -+@end -+ -+@implementation AppDelegate -+ -+ -+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { -+ // Override point for customization after application launch. -+ return YES; -+} -+ -+@end ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/Assets.xcassets/AccentColor.colorset/Contents.json -@@ -0,0 +1,11 @@ -+{ -+ "colors" : [ -+ { -+ "idiom" : "universal" -+ } -+ ], -+ "info" : { -+ "author" : "xcode", -+ "version" : 1 -+ } -+} ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/Assets.xcassets/AppIcon.appiconset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "universal", -+ "platform" : "ios", -+ "size" : "1024x1024" -+ } -+ ], -+ "info" : { -+ "author" : "xcode", -+ "version" : 1 -+ } -+} ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/Assets.xcassets/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "author" : "xcode", -+ "version" : 1 -+ } -+} ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/Base.lproj/LaunchScreen.storyboard -@@ -0,0 +1,9 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/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 -+ -+ ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist.in -@@ -0,0 +1,54 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ en -+ CFBundleDisplayName -+ ${PRODUCT_NAME} -+ CFBundleExecutable -+ ${EXECUTABLE_NAME} -+ CFBundleIdentifier -+ org.python.iOSTestbed -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundleName -+ ${PRODUCT_NAME} -+ CFBundlePackageType -+ APPL -+ CFBundleShortVersionString -+ @VERSION@ -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ 1 -+ LSRequiresIPhoneOS -+ -+ UIRequiresFullScreen -+ -+ UILaunchStoryboardName -+ Launch Screen -+ UISupportedInterfaceOrientations -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ UISupportedInterfaceOrientations~ipad -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationPortraitUpsideDown -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ MainModule -+ ios -+ UIApplicationSceneManifest -+ -+ UIApplicationSupportsMultipleScenes -+ -+ UISceneConfigurations -+ -+ -+ -+ ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbed/main.m -@@ -0,0 +1,23 @@ -+// -+// main.m -+// iOSTestbed -+// -+// Created by Russell Keith-Magee on 23/11/2023. -+// -+ -+#import -+#import "AppDelegate.h" -+ -+int main(int argc, char * argv[]) { -+ NSString * appDelegateClassName; -+ @autoreleasepool { -+ // Setup code that might create autoreleased objects goes here. -+ appDelegateClassName = NSStringFromClass([AppDelegate class]); -+ } -+ -+ // iOS doesn't like uncaught signals. -+ signal(SIGPIPE, SIG_IGN); -+ signal(SIGXFSZ, SIG_IGN); -+ -+ return UIApplicationMain(argc, argv, nil, appDelegateClassName); -+} ---- /dev/null -+++ b/Tools/iOSTestbed/iOSTestbedTests/iOSTestbedTests.m -@@ -0,0 +1,188 @@ -+#import -+#import -+ -+@interface iOSTestbedTests : XCTestCase -+ -+@end -+ -+@implementation iOSTestbedTests -+ -+ -+- (void)testPython { -+ // Arguments to pass into the test suite runner. -+ // argv[0] must identify the process; any subsequent arg -+ // will be handled as if it were an argument to `python -m test` -+ const char *argv[] = { -+ "iOSTestbed", // argv[0] is the process that is running. -+ "-uall,-subprocess,-gui,-curses", // Enable most resources -+ "-v", // run in verbose mode so we get test failure information -+ // To run a subset of tests, add the test names below; e.g., -+ // "test_os", -+ // "test_sys", -+ }; -+ -+ // Start a Python interpreter. -+ int success = -1; -+ PyStatus status; -+ PyPreConfig preconfig; -+ PyConfig config; -+ NSString *python_home; -+ NSString *path; -+ wchar_t *wtmp_str; -+ -+ PyObject *app_module; -+ PyObject *module; -+ PyObject *module_attr; -+ PyObject *method_args; -+ PyObject *result; -+ PyObject *exc_type; -+ PyObject *exc_value; -+ PyObject *exc_traceback; -+ PyObject *systemExit_code; -+ -+ NSString *resourcePath = [[NSBundle mainBundle] resourcePath]; -+ -+ // Extract Python version from bundle -+ NSString *py_version_string = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; -+ -+ // Generate an isolated Python configuration. -+ NSLog(@"Configuring isolated Python %@...", py_version_string); -+ PyPreConfig_InitIsolatedConfig(&preconfig); -+ PyConfig_InitIsolatedConfig(&config); -+ -+ // Configure the Python interpreter: -+ // Enforce UTF-8 encoding for stderr, stdout, file-system encoding and locale. -+ // See https://docs.python.org/3/library/os.html#python-utf-8-mode. -+ preconfig.utf8_mode = 1; -+ // Don't buffer stdio. We want output to appears in the log immediately -+ config.buffered_stdio = 0; -+ // Don't write bytecode; we can't modify the app bundle -+ // after it has been signed. -+ config.write_bytecode = 0; -+ // Disable the user site module -+ config.site_import = 0; -+ // For debugging - enable verbose mode. -+ // config.verbose = 1; -+ -+ NSLog(@"Pre-initializing Python runtime..."); -+ status = Py_PreInitialize(&preconfig); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to pre-initialize Python interpreter: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ -+ // Set the home for the Python interpreter -+ python_home = [NSString stringWithFormat:@"%@/python", resourcePath, nil]; -+ NSLog(@"PythonHome: %@", python_home); -+ wtmp_str = Py_DecodeLocale([python_home UTF8String], NULL); -+ status = PyConfig_SetString(&config, &config.home, wtmp_str); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to set PYTHONHOME: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ PyMem_RawFree(wtmp_str); -+ -+ // Set the stdlib location for the Python interpreter -+ path = [NSString stringWithFormat:@"%@/python/lib/python%@", resourcePath, py_version_string, nil]; -+ NSLog(@"Stdlib dir: %@", path); -+ wtmp_str = Py_DecodeLocale([path UTF8String], NULL); -+ status = PyConfig_SetString(&config, &config.stdlib_dir, wtmp_str); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to set stdlib dir: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ PyMem_RawFree(wtmp_str); -+ -+ // Read the site config -+ status = PyConfig_Read(&config); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to read site config: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ -+ NSLog(@"Configure argc/argv..."); -+ status = PyConfig_SetBytesArgv(&config, sizeof(argv) / sizeof(char *), (char**) argv); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to configure argc/argv: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ -+ NSLog(@"Initializing Python runtime..."); -+ status = Py_InitializeFromConfig(&config); -+ if (PyStatus_Exception(status)) { -+ XCTFail(@"Unable to initialize Python interpreter: %s", status.err_msg); -+ PyConfig_Clear(&config); -+ return; -+ } -+ -+ // Start the test suite. -+ // -+ // From here to Py_ObjectCall(runmodule...) is effectively -+ // a copy of Py_RunMain() (and, more specifically, the -+ // pymain_run_module() method); we need to re-implement it -+ // because we need to be able to inspect the error state of -+ // the interpreter, not just the return code of the module. -+ NSLog(@"Running CPython test suite"); -+ module = PyImport_ImportModule("runpy"); -+ if (module == NULL) { -+ XCTFail(@"Could not import runpy module"); -+ } -+ -+ module_attr = PyObject_GetAttrString(module, "_run_module_as_main"); -+ if (module_attr == NULL) { -+ XCTFail(@"Could not access runpy._run_module_as_main"); -+ } -+ -+ app_module = PyUnicode_FromString("test"); -+ if (app_module == NULL) { -+ XCTFail(@"Could not convert module name to unicode"); -+ } -+ -+ method_args = Py_BuildValue("(Oi)", app_module, 0); -+ if (method_args == NULL) { -+ XCTFail(@"Could not create arguments for runpy._run_module_as_main"); -+ } -+ -+ // Print a separator to differentiate Python startup logs from app logs -+ NSLog(@"---------------------------------------------------------------------------"); -+ -+ // Invoke the app module -+ result = PyObject_Call(module_attr, method_args, NULL); -+ -+ NSLog(@"---------------------------------------------------------------------------"); -+ -+ // The test method doesn't return an object of any interest; -+ // but if the call returns NULL, there's been a problem. -+ if (result == NULL) { -+ // Retrieve the current error state of the interpreter. -+ PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); -+ PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback); -+ -+ if (exc_traceback == NULL) { -+ XCTFail(@"Could not retrieve traceback"); -+ } -+ -+ if (PyErr_GivenExceptionMatches(exc_value, PyExc_SystemExit)) { -+ systemExit_code = PyObject_GetAttrString(exc_value, "code"); -+ if (systemExit_code == NULL) { -+ XCTFail(@"Could not determine exit code"); -+ } -+ else { -+ success = (int) PyLong_AsLong(systemExit_code); -+ XCTAssertEqual(success, 0, @"Python test suite did not pass"); -+ } -+ } else { -+ PyErr_DisplayException(exc_value); -+ XCTFail(@"Test suite generated exception"); -+ } -+ } -+ Py_Finalize(); -+} -+ -+ -+@end -diff --git a/config.sub b/config.sub -index d74fb6deac..09ebc4287c 100755 ---- a/config.sub -+++ b/config.sub -@@ -1121,7 +1121,7 @@ - xscale-* | xscalee[bl]-*) - cpu=`echo "$cpu" | sed 's/^xscale/arm/'` - ;; -- arm64-*) -+ arm64-* | arm64_32-*) - cpu=aarch64 - ;; - -@@ -1723,7 +1723,7 @@ - | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ - | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ - | hiux* | abug | nacl* | netware* | windows* \ -- | os9* | macos* | osx* | ios* \ -+ | os9* | macos* | osx* | ios* | tvos* | watchos* \ - | mpw* | magic* | mmixware* | mon960* | lnews* \ - | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ - | aos* | aros* | cloudabi* | sortix* | twizzler* \ -@@ -1786,6 +1786,8 @@ - ;; - *-eabi* | *-gnueabi*) - ;; -+ ios*-simulator | tvos*-simulator | watchos*-simulator) -+ ;; - -*) - # Blank kernel with real OS is always fine. - ;; diff --git a/configure b/configure -index c87f518382..0e24298436 100755 +index bff4f6ceb4a..1ce51fcffeb 100755 --- a/configure +++ b/configure -@@ -963,10 +963,13 @@ +@@ -978,10 +978,13 @@ CFLAGS CC HAS_XCRUN +WATCHOS_DEPLOYMENT_TARGET +TVOS_DEPLOYMENT_TARGET -+IOS_DEPLOYMENT_TARGET + IPHONEOS_DEPLOYMENT_TARGET EXPORT_MACOSX_DEPLOYMENT_TARGET CONFIGURE_MACOSX_DEPLOYMENT_TARGET _PYTHON_HOST_PLATFORM --MACHDEP -+INSTALLTARGETS ++APP_STORE_COMPLIANCE_PATCH + INSTALLTARGETS FRAMEWORKINSTALLAPPSPREFIX FRAMEWORKUNIXTOOLSPREFIX - FRAMEWORKPYTHONW -@@ -974,6 +977,8 @@ - FRAMEWORKALTINSTALLFIRST - FRAMEWORKINSTALLLAST - FRAMEWORKINSTALLFIRST -+RESSRCDIR -+PYTHONFRAMEWORKINSTALLNAMEPREFIX - PYTHONFRAMEWORKINSTALLDIR - PYTHONFRAMEWORKPREFIX - PYTHONFRAMEWORKDIR -@@ -983,6 +988,7 @@ - LIPO_32BIT_FLAGS - ARCH_RUN_32BIT - UNIVERSALSDK -+MACHDEP - PKG_CONFIG_LIBDIR - PKG_CONFIG_PATH - PKG_CONFIG -@@ -3988,6 +3994,86 @@ - as_fn_error $? "pkg-config is required" "$LINENO" 5] - fi - -+# Set name for machine-dependent library files -+ -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5 -+printf %s "checking MACHDEP... " >&6; } -+if test -z "$MACHDEP" -+then -+ # avoid using uname for cross builds -+ if test "$cross_compiling" = yes; then -+ # ac_sys_system and ac_sys_release are used for setting -+ # a lot of different things including 'define_xopen_source' -+ # in the case statement below. -+ case "$host" in -+ *-*-linux-android*) -+ ac_sys_system=Linux-android -+ ;; -+ *-*-linux*) -+ ac_sys_system=Linux -+ ;; -+ *-*-cygwin*) -+ ac_sys_system=Cygwin -+ ;; -+ *-apple-ios*) -+ ac_sys_system=iOS -+ ;; +@@ -1077,6 +1080,7 @@ + with_universal_archs + with_framework_name + enable_framework ++with_app_store_compliance + with_emscripten_target + enable_wasm_dynamic_linking + enable_wasm_pthreads +@@ -1856,6 +1860,10 @@ + specify the name for the python framework on macOS + only valid when --enable-framework is set. see + Mac/README.rst (default is 'Python') ++ --with-app-store-compliance=[PATCH-FILE] ++ Enable any patches required for compiliance with app ++ stores. Optional PATCH-FILE specifies the custom ++ patch to apply. + --with-emscripten-target=[browser|node] + Emscripten platform + --with-suffix=SUFFIX set executable suffix to SUFFIX (default is empty, +@@ -4048,6 +4056,12 @@ + *-apple-ios*) + ac_sys_system=iOS + ;; + *-apple-tvos*) + ac_sys_system=tvOS + ;; + *-apple-watchos*) + ac_sys_system=watchOS + ;; -+ *-*-vxworks*) -+ ac_sys_system=VxWorks -+ ;; -+ *-*-emscripten) -+ ac_sys_system=Emscripten -+ ;; -+ *-*-wasi) -+ ac_sys_system=WASI -+ ;; -+ *) -+ # for now, limit cross builds to known configurations -+ MACHDEP="unknown" -+ as_fn_error $? "cross build not supported for $host" "$LINENO" 5 -+ esac -+ ac_sys_release= -+ else -+ ac_sys_system=`uname -s` -+ if test "$ac_sys_system" = "AIX" \ -+ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then -+ ac_sys_release=`uname -v` -+ else -+ ac_sys_release=`uname -r` -+ fi -+ fi -+ ac_md_system=`echo $ac_sys_system | -+ tr -d '/ ' | tr '[A-Z]' '[a-z]'` -+ ac_md_release=`echo $ac_sys_release | -+ tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'` -+ MACHDEP="$ac_md_system$ac_md_release" -+ -+ case $MACHDEP in -+ aix*) MACHDEP="aix";; -+ linux*) MACHDEP="linux";; -+ cygwin*) MACHDEP="cygwin";; -+ darwin*) MACHDEP="darwin";; -+ '') MACHDEP="unknown";; + *-*-vxworks*) + ac_sys_system=VxWorks + ;; +@@ -4102,7 +4116,7 @@ + # On cross-compile builds, configure will look for a host-specific compiler by + # prepending the user-provided host triple to the required binary name. + # +-# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", ++# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", + # which isn't a binary that exists, and isn't very convenient, as it contains the + # iOS version. As the default cross-compiler name won't exist, configure falls + # back to gcc, which *definitely* won't work. We're providing wrapper scripts for +@@ -4117,6 +4131,14 @@ + aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; + aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; + x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; ++ ++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; ++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; ++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; ++ ++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; ++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; ++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; + *) + esac + fi +@@ -4125,6 +4147,14 @@ + aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; + aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; + x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; ++ ++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; ++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; ++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; ++ ++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; ++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; ++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; + *) + esac + fi +@@ -4133,6 +4163,14 @@ + aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; + aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; + x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; ++ ++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; ++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; ++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; ++ ++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; ++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; ++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; + *) + esac + fi +@@ -4141,6 +4179,14 @@ + aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang ;; + aarch64-apple-ios*) CXX=arm64-apple-ios-clang ;; + x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang ;; ++ ++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang ;; ++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang ;; ++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang ;; ++ ++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang ;; ++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang ;; ++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang ;; + *) + esac + fi +@@ -4261,8 +4307,10 @@ + case $enableval in + yes) + case $ac_sys_system in +- Darwin) enableval=/Library/Frameworks ;; +- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ Darwin) enableval=/Library/Frameworks ;; ++ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; ++ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; + *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 + esac + esac +@@ -4271,6 +4319,8 @@ + no) + case $ac_sys_system in + iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; ++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; ++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -4377,6 +4427,36 @@ + + ac_config_files="$ac_config_files iOS/Resources/Info.plist" + ++ ;; ++ tvOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources ++ ++ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" ++ ++ ;; ++ watchOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=watchOS/Resources ++ ++ ac_config_files="$ac_config_files watchOS/Resources/Info.plist" ++ + ;; + *) + as_fn_error $? "Unknown platform for framework build" "$LINENO" 5 +@@ -4388,6 +4468,8 @@ + + case $ac_sys_system in + iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;; ++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;; ++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -4431,6 +4513,53 @@ + printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h + + ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --with-app-store-compliance" >&5 ++printf %s "checking for --with-app-store-compliance... " >&6; } ++ ++# Check whether --with-app_store_compliance was given. ++if test ${with_app_store_compliance+y} ++then : ++ withval=$with_app_store_compliance; ++ case "$withval" in ++ yes) ++ case $ac_sys_system in ++ Darwin|iOS|tvOS|watchOS) ++ # iOS/tvOS/watchOS is able to share the macOS patch ++ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" ++ ;; ++ *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; ++ esac ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 ++printf "%s\n" "applying default app store compliance patch" >&6; } ++ ;; ++ *) ++ APP_STORE_COMPLIANCE_PATCH="${withval}" ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying custom app store compliance patch" >&5 ++printf "%s\n" "applying custom app store compliance patch" >&6; } ++ ;; + esac + -+ if test "$ac_sys_system" = "SunOS"; then -+ # For Solaris, there isn't an OS version specific macro defined -+ # in most compilers, so we define one here. -+ SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\(0-9\)$!.0\1!g' | tr -d '.'` -+ -+printf "%s\n" "#define Py_SUNOS_VERSION $SUNOS_VERSION" >>confdefs.h ++else $as_nop + -+ fi -+fi -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5 -+printf "%s\n" "\"$MACHDEP\"" >&6; } -+ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for --enable-universalsdk" >&5 - printf %s "checking for --enable-universalsdk... " >&6; } - # Check whether --enable-universalsdk was given. -@@ -4111,11 +4197,15 @@ - PYTHONFRAMEWORKDIR=no-framework - PYTHONFRAMEWORKPREFIX= - PYTHONFRAMEWORKINSTALLDIR= -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX= -+ RESSRCDIR= - FRAMEWORKINSTALLFIRST= - FRAMEWORKINSTALLLAST= - FRAMEWORKALTINSTALLFIRST= - FRAMEWORKALTINSTALLLAST= - FRAMEWORKPYTHONW= -+ INSTALLTARGETS="commoninstall bininstall maninstall" -+ - if test "x${prefix}" = "xNONE"; then - FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" - else -@@ -4128,65 +4218,114 @@ - PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR - FRAMEWORKINSTALLFIRST="frameworkinstallstructure" - FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure " -- FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools" -- FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools" -- FRAMEWORKPYTHONW="frameworkpythonw" -- FRAMEWORKINSTALLAPPSPREFIX="/Applications" - -- if test "x${prefix}" = "xNONE" ; then -- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" -+ case $ac_sys_system in #( -+ iOS) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" - -- else -- FRAMEWORKUNIXTOOLSPREFIX="${prefix}" -- fi -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=iOS/Resources - -- case "${enableval}" in -- /System*) -- FRAMEWORKINSTALLAPPSPREFIX="/Applications" -- if test "${prefix}" = "NONE" ; then -- # See below -- FRAMEWORKUNIXTOOLSPREFIX="/usr" -- fi -- ;; -+ ac_config_files="$ac_config_files iOS/Resources/Info.plist" - -- /Library*) -- FRAMEWORKINSTALLAPPSPREFIX="/Applications" -- ;; -+ ac_config_files="$ac_config_files Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist" - -- */Library/Frameworks) -- MDIR="`dirname "${enableval}"`" -- MDIR="`dirname "${MDIR}"`" -- FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications" -- -- if test "${prefix}" = "NONE"; then -- # User hasn't specified the -- # --prefix option, but wants to install -- # the framework in a non-default location, -- # ensure that the compatibility links get -- # installed relative to that prefix as well -- # instead of in /usr/local. -- FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" -- fi -- ;; ++ case $ac_sys_system in ++ iOS|tvOS|watchOS) ++ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch ++ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 ++printf "%s\n" "applying default app store compliance patch" >&6; } + ;; -+ tvOS) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" - -- *) -- FRAMEWORKINSTALLAPPSPREFIX="/Applications" -- ;; -- esac -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=tvOS/Resources - -- prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION -+ ac_config_files="$ac_config_files tvOS/Resources/Info.plist" - -- # Add files for Mac specific code to the list of output -- # files: -- ac_config_files="$ac_config_files Mac/Makefile" ++ *) ++ # No default app compliance patching on any other platform ++ APP_STORE_COMPLIANCE_PATCH= ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not patching for app store compliance" >&5 ++printf "%s\n" "not patching for app store compliance" >&6; } + ;; -+ watchOS) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" -+ -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=watchOS/Resources - -- ac_config_files="$ac_config_files Mac/PythonLauncher/Makefile" -+ ac_config_files="$ac_config_files watchOS/Resources/Info.plist" - -- ac_config_files="$ac_config_files Mac/Resources/framework/Info.plist" -+ ;; -+ *) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools" -+ FRAMEWORKPYTHONW="frameworkpythonw" -+ FRAMEWORKINSTALLAPPSPREFIX="/Applications" -+ INSTALLTARGETS="commoninstall bininstall maninstall" - -- ac_config_files="$ac_config_files Mac/Resources/app/Info.plist" -+ if test "x${prefix}" = "xNONE" ; then -+ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" - -- esac -+ else -+ FRAMEWORKUNIXTOOLSPREFIX="${prefix}" -+ fi -+ -+ case "${enableval}" in -+ /System*) -+ FRAMEWORKINSTALLAPPSPREFIX="/Applications" -+ if test "${prefix}" = "NONE" ; then -+ # See below -+ FRAMEWORKUNIXTOOLSPREFIX="/usr" -+ fi -+ ;; -+ -+ /Library*) -+ FRAMEWORKINSTALLAPPSPREFIX="/Applications" -+ ;; -+ -+ */Library/Frameworks) -+ MDIR="`dirname "${enableval}"`" -+ MDIR="`dirname "${MDIR}"`" -+ FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications" -+ -+ if test "${prefix}" = "NONE"; then -+ # User hasn't specified the -+ # --prefix option, but wants to install -+ # the framework in a non-default location, -+ # ensure that the compatibility links get -+ # installed relative to that prefix as well -+ # instead of in /usr/local. -+ FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" -+ fi -+ ;; -+ -+ *) -+ FRAMEWORKINSTALLAPPSPREFIX="/Applications" -+ ;; -+ esac -+ -+ prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX=${prefix} -+ RESSRCDIR=Mac/Resources/framework -+ -+ # Add files for Mac specific code to the list of output -+ # files: -+ ac_config_files="$ac_config_files Mac/Makefile" -+ -+ ac_config_files="$ac_config_files Mac/PythonLauncher/Makefile" -+ -+ ac_config_files="$ac_config_files Mac/Resources/app/Info.plist" -+ -+ ac_config_files="$ac_config_files Mac/Resources/framework/Info.plist" ++ esac ++ ++fi ++ ++ + -+ ;; -+ esac -+ esac - - else $as_nop - -@@ -4194,6 +4333,8 @@ - PYTHONFRAMEWORKDIR=no-framework - PYTHONFRAMEWORKPREFIX= - PYTHONFRAMEWORKINSTALLDIR= -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX= -+ RESSRCDIR= - FRAMEWORKINSTALLFIRST= - FRAMEWORKINSTALLLAST= - FRAMEWORKALTINSTALLFIRST= -@@ -4223,79 +4364,11 @@ - - - --printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h -- -- --# Set name for machine-dependent library files -- --{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking MACHDEP" >&5 --printf %s "checking MACHDEP... " >&6; } --if test -z "$MACHDEP" --then -- # avoid using uname for cross builds -- if test "$cross_compiling" = yes; then -- # ac_sys_system and ac_sys_release are used for setting -- # a lot of different things including 'define_xopen_source' -- # in the case statement below. -- case "$host" in -- *-*-linux-android*) -- ac_sys_system=Linux-android -- ;; -- *-*-linux*) -- ac_sys_system=Linux -- ;; -- *-*-cygwin*) -- ac_sys_system=Cygwin -- ;; -- *-*-vxworks*) -- ac_sys_system=VxWorks -- ;; -- *-*-emscripten) -- ac_sys_system=Emscripten -- ;; -- *-*-wasi) -- ac_sys_system=WASI -- ;; -- *) -- # for now, limit cross builds to known configurations -- MACHDEP="unknown" -- as_fn_error $? "cross build not supported for $host" "$LINENO" 5 -- esac -- ac_sys_release= -- else -- ac_sys_system=`uname -s` -- if test "$ac_sys_system" = "AIX" \ -- -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then -- ac_sys_release=`uname -v` -- else -- ac_sys_release=`uname -r` -- fi -- fi -- ac_md_system=`echo $ac_sys_system | -- tr -d '/ ' | tr '[A-Z]' '[a-z]'` -- ac_md_release=`echo $ac_sys_release | -- tr -d '/ ' | sed 's/^[A-Z]\.//' | sed 's/\..*//'` -- MACHDEP="$ac_md_system$ac_md_release" - -- case $MACHDEP in -- aix*) MACHDEP="aix";; -- linux*) MACHDEP="linux";; -- cygwin*) MACHDEP="cygwin";; -- darwin*) MACHDEP="darwin";; -- '') MACHDEP="unknown";; -- esac - -- if test "$ac_sys_system" = "SunOS"; then -- # For Solaris, there isn't an OS version specific macro defined -- # in most compilers, so we define one here. -- SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\(0-9\)$!.0\1!g' | tr -d '.'` - --printf "%s\n" "#define Py_SUNOS_VERSION $SUNOS_VERSION" >>confdefs.h -+printf "%s\n" "#define _PYTHONFRAMEWORK \"${PYTHONFRAMEWORK}\"" >>confdefs.h - -- fi --fi --{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: \"$MACHDEP\"" >&5 --printf "%s\n" "\"$MACHDEP\"" >&6; } - if test "$cross_compiling" = yes; then -@@ -4303,27 +4376,102 @@ - *-*-linux*) - case "$host_cpu" in - arm*) -- _host_cpu=arm -+ _host_ident=arm - ;; - *) -- _host_cpu=$host_cpu -+ _host_ident=$host_cpu + case "$host" in +@@ -4468,6 +4597,50 @@ + ;; esac ;; - *-*-cygwin*) -- _host_cpu= -+ _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 -+ ;; -+ *-apple-tvos*-simulator) -+ _host_os=`echo $host | cut -d '-' -f3` -+ TVOS_DEPLOYMENT_TARGET=${_host_os:4} -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvsimulator-arm64 -+ ;; -+ *) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvsimulator-$host_cpu -+ esac -+ ;; -+ *-apple-tvos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ TVOS_DEPLOYMENT_TARGET=${_host_os:4} -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvos-arm64 -+ ;; -+ *) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvos-$host_cpu -+ esac -+ ;; -+ *-apple-watchos*-simulator) ++ *-apple-tvos*) + _host_os=`echo $host | cut -d '-' -f3` -+ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking tvOS deployment target" >&5 ++printf %s "checking tvOS deployment target... " >&6; } ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} ++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TVOS_DEPLOYMENT_TARGET" >&5 ++printf "%s\n" "$TVOS_DEPLOYMENT_TARGET" >&6; } ++ + case "$host_cpu" in -+ aarch64) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchsimulator-arm64 -+ ;; -+ *) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchsimulator-$host_cpu -+ esac -+ ;; -+ *-apple-watchos*) ++ aarch64) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} ++ ;; ++ *) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} ++ ;; ++ esac ++ ;; ++ *-apple-watchos*) + _host_os=`echo $host | cut -d '-' -f3` -+ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchosos-arm64_32 -+ ;; -+ *) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchosos-$host_cpu -+ esac -+ ;; -+ *-apple-*) ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking watchOS deployment target" >&5 ++printf %s "checking watchOS deployment target... " >&6; } ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} ++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WATCHOS_DEPLOYMENT_TARGET" >&5 ++printf "%s\n" "$WATCHOS_DEPLOYMENT_TARGET" >&6; } ++ + case "$host_cpu" in -+ arm*) -+ _host_ident=arm -+ ;; -+ *) -+ _host_ident=$host_cpu ++ aarch64) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} ++ ;; ++ *) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} ++ ;; + esac - ;; ++ ;; *-*-vxworks*) -- _host_cpu=$host_cpu -+ _host_ident=$host_cpu + _host_ident=$host_cpu ;; - wasm32-*-* | wasm64-*-*) -- _host_cpu=$host_cpu -+ _host_ident=$host_cpu - ;; - *) - # for now, limit cross builds to known configurations - MACHDEP="unknown" - as_fn_error $? "cross build not supported for $host" "$LINENO" 5 - esac -- _PYTHON_HOST_PLATFORM="$MACHDEP${_host_cpu:+-$_host_cpu}" -+ _PYTHON_HOST_PLATFORM="$MACHDEP${_host_ident:+-$_host_ident}" - fi - - # Some systems cannot stand _XOPEN_SOURCE being defined at all; they -@@ -4390,6 +4538,13 @@ +@@ -4546,9 +4719,13 @@ 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 iOS, defining _POSIX_C_SOURCE also disables platform specific features. ++ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. + iOS/*) + define_xopen_source=no;; + tvOS/*) + define_xopen_source=no;; + watchOS/*) @@ -3836,45 +664,39 @@ index c87f518382..0e24298436 100755 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -4484,6 +4639,32 @@ - ;; - esac +@@ -4611,7 +4788,10 @@ + CONFIGURE_MACOSX_DEPLOYMENT_TARGET= + EXPORT_MACOSX_DEPLOYMENT_TARGET='#' -+case $ac_sys_system in #( -+ iOS) : +-# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. ++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / ++# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. + -+ 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}" + -+ ;; #( + + + # checks for alternative programs +@@ -4652,6 +4832,16 @@ + as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" + as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}" + ;; #( + tvOS) : + -+ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=9.0} + as_fn_append CFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" + as_fn_append LDFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}" -+ + ;; #( + watchOS) : + -+ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} + as_fn_append CFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}" + as_fn_append LDFLAGS " -mwatchos-version-min=${WATCHOS_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. -@@ -6746,6 +6927,12 @@ - case $ac_sys_system in #( - Darwin*) : + *) : + ;; + esac +@@ -6953,6 +7143,10 @@ + MULTIARCH="" ;; #( + iOS) : MULTIARCH="" ;; #( -+ iOS) : -+ MULTIARCH="" ;; #( + tvOS) : + MULTIARCH="" ;; #( + watchOS) : @@ -3882,682 +704,564 @@ index c87f518382..0e24298436 100755 FreeBSD*) : MULTIARCH="" ;; #( *) : -@@ -6753,8 +6940,6 @@ - ;; - esac - --{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5 --printf "%s\n" "$MULTIARCH" >&6; } +@@ -6973,7 +7167,7 @@ + printf "%s\n" "$MULTIARCH" >&6; } - if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then - if test x$PLATFORM_TRIPLET != x$MULTIARCH; then -@@ -6764,6 +6949,16 @@ - MULTIARCH=$PLATFORM_TRIPLET - fi - -+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MULTIARCH" >&5 -+printf "%s\n" "$MULTIARCH" >&6; } -+ -+case $ac_sys_system in #( + case $ac_sys_system in #( +- iOS) : + iOS|tvOS|watchOS) : -+ SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f1` ;; #( -+ *) : -+ SOABI_PLATFORM=$PLATFORM_TRIPLET -+ ;; -+esac - - if test x$MULTIARCH != x; then - MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" -@@ -6807,6 +7002,12 @@ + SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #( + *) : + SOABI_PLATFORM=$PLATFORM_TRIPLET +@@ -7024,6 +7218,14 @@ PY_SUPPORT_TIER=3 ;; #( - x86_64-*-freebsd*/clang) : + aarch64-apple-ios*/clang) : PY_SUPPORT_TIER=3 ;; #( -+ aarch64-apple-ios*-simulator/clang) : ++ aarch64-apple-tvos*-simulator/clang) : + PY_SUPPORT_TIER=3 ;; #( -+ x86_64-apple-ios*-simulator/clang) : ++ aarch64-apple-tvos*/clang) : + PY_SUPPORT_TIER=3 ;; #( -+ aarch64-apple-ios*/clang) : ++ aarch64-apple-watchos*-simulator/clang) : + PY_SUPPORT_TIER=3 ;; #( - *) : - PY_SUPPORT_TIER=0 - ;; -@@ -7257,17 +7458,23 @@ - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDLIBRARY" >&5 - printf %s "checking LDLIBRARY... " >&6; } - --# MacOSX framework builds need more magic. LDLIBRARY is the dynamic -+# iOS/MacOSX framework builds need more magic. LDLIBRARY is the dynamic - # library that we build, but we do not want to link against it (we - # 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 -- LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' -- RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}} -+ case $ac_sys_system in -+ iOS|tvOS|watchOS) -+ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; -+ *) -+ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; -+ esac - BLDLIBRARY='' -+ RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}} - else - BLDLIBRARY='$(LDLIBRARY)' - fi -@@ -7317,12 +7524,16 @@ - ;; - Darwin*) - LDLIBRARY='libpython$(LDVERSION).dylib' -- BLDLIBRARY='-L. -lpython$(LDVERSION)' -- RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} -+ BLDLIBRARY='-L. -lpython$(LDVERSION)' -+ RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} -+ ;; ++ arm64_32-apple-watchos*/clang) : ++ PY_SUPPORT_TIER=3 ;; #( + aarch64-*-linux-android/clang) : + PY_SUPPORT_TIER=3 ;; #( + x86_64-*-linux-android/clang) : +@@ -7494,7 +7696,7 @@ + case $ac_sys_system in + Darwin) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; + *) + as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;; +@@ -7560,7 +7762,7 @@ + BLDLIBRARY='-L. -lpython$(LDVERSION)' + RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} + ;; +- iOS) + iOS|tvOS|watchOS) -+ LDLIBRARY='libpython$(LDVERSION).dylib' -+ BLDLIBRARY='-L. -lpython$(LDVERSION)' - ;; + LDLIBRARY='libpython$(LDVERSION).dylib' + ;; AIX*) -- LDLIBRARY='libpython$(LDVERSION).so' -- RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}} -+ LDLIBRARY='libpython$(LDVERSION).so' -+ RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}} - ;; - - esac -@@ -12515,6 +12726,7 @@ - esac - ;; - CYGWIN*) SHLIB_SUFFIX=.dll;; -+ iOS|tvOS|watchOS) SHLIB_SUFFIX=.dylib;; - *) SHLIB_SUFFIX=.so;; - esac - fi -@@ -12597,6 +12809,11 @@ +@@ -12895,7 +13097,7 @@ BLDSHARED="$LDSHARED" fi ;; +- iOS/*) + iOS/*|tvOS/*|watchOS/*) -+ LDSHARED='$(CC) -dynamiclib -F . -framework Python' -+ LDCXXSHARED='$(CXX) -dynamiclib -F . -framework Python' -+ BLDSHARED="$LDSHARED" -+ ;; - Emscripten|WASI) - LDSHARED='$(CC) -shared' - LDCXXSHARED='$(CXX) -shared';; -@@ -12750,6 +12967,24 @@ - LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + BLDSHARED="$LDSHARED" +@@ -13028,7 +13230,7 @@ + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; + Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; + # -u libsys_s pulls in all symbols in libsys +- Darwin/*|iOS/*) ++ Darwin/*|iOS/*|tvOS/*|watchOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" + + # Issue #18075: the default maximum stack size (8MBytes) is too +@@ -13052,7 +13254,7 @@ + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED" +- elif test $ac_sys_system = "iOS"; then ++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' fi - LINKFORSHARED="$LINKFORSHARED";; -+ iOS/*|tvOS/*|watchOS/*) -+ LINKFORSHARED="$extra_undefs -framework CoreFoundation" + ;; +@@ -14451,7 +14653,7 @@ + + ctypes_malloc_closure=yes + ;; #( +- iOS) : ++ iOS|tvOS|watchOS) : + + ctypes_malloc_closure=yes + ;; #( +@@ -17902,12 +18104,6 @@ + then : + printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h + +-fi +-ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" +-if test "x$ac_cv_func_execv" = xyes +-then : +- printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero" + if test "x$ac_cv_func_explicit_bzero" = xyes +@@ -17968,18 +18164,6 @@ + then : + printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h + +-fi +-ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" +-if test "x$ac_cv_func_fork" = xyes +-then : +- printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" +-if test "x$ac_cv_func_fork1" = xyes +-then : +- printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf" + if test "x$ac_cv_func_fpathconf" = xyes +@@ -18406,24 +18590,6 @@ + then : + printf "%s\n" "#define HAVE_POSIX_OPENPT 1" >>confdefs.h + +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" +-if test "x$ac_cv_func_posix_spawn" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" +-if test "x$ac_cv_func_posix_spawnp" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h +- +-fi +-ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" +-if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes +-then : +- printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread" + if test "x$ac_cv_func_pread" = xyes +@@ -18712,12 +18878,6 @@ + then : + printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h + +-fi +-ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" +-if test "x$ac_cv_func_sigaltstack" = xyes +-then : +- printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h +- + fi + ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset" + if test "x$ac_cv_func_sigfillset" = xyes +@@ -18986,11 +19146,11 @@ + + fi + +-# iOS defines some system methods that can be linked (so they are ++# iOS/tvOS/watchOS define 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 ++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then + ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy" + if test "x$ac_cv_func_getentropy" = xyes + then : +@@ -19012,6 +19172,53 @@ + + fi + ++# tvOS/watchOS have some additional methods that can be found, but not used. ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv" ++if test "x$ac_cv_func_execv" = xyes ++then : ++ printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h + -+ # 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 ++fi ++ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork" ++if test "x$ac_cv_func_fork" = xyes ++then : ++ printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h + ++fi ++ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1" ++if test "x$ac_cv_func_fork1" = xyes ++then : ++ printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h + -+printf "%s\n" "#define THREAD_STACK_SIZE 0x$stack_size" >>confdefs.h ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" ++if test "x$ac_cv_func_posix_spawn" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h + ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp" ++if test "x$ac_cv_func_posix_spawnp" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>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";; -@@ -14138,6 +14373,10 @@ - - ctypes_malloc_closure=yes - ;; #( -+ iOS|tvOS|watchOS) : ++fi ++ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np" ++if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes ++then : ++ printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h + -+ ctypes_malloc_closure=yes -+ ;; #( - sunos5) : - as_fn_append LIBFFI_LIBS " -mimpure-text" - ;; #( -@@ -23651,7 +23890,7 @@ - printf "%s\n" "$ABIFLAGS" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking SOABI" >&5 - printf %s "checking SOABI... " >&6; } --SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET} -+SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${SOABI_PLATFORM:+-$SOABI_PLATFORM} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SOABI" >&5 - printf "%s\n" "$SOABI" >&6; } ++fi ++ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack" ++if test "x$ac_cv_func_sigaltstack" = xyes ++then : ++ printf "%s\n" "#define HAVE_SIGALTSTACK 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} +@@ -21808,7 +22015,8 @@ -@@ -23660,7 +23899,7 @@ - if test "$Py_DEBUG" = 'true'; then - # Similar to SOABI but remove "d" flag from ABIFLAGS -- ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET} -+ ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${SOABI_PLATFORM:+-$SOABI_PLATFORM} + # check for openpty, login_tty, and forkpty +- ++# tvOS/watchOS have functions for tty, but can't use them ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then + + for ac_func in openpty + do : +@@ -21904,7 +22112,7 @@ + fi + + done +-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 ++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 + printf %s "checking for library containing login_tty... " >&6; } + if test ${ac_cv_search_login_tty+y} + then : +@@ -22061,6 +22269,7 @@ + fi + + done ++fi + + # check for long file support functions + ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" +@@ -22307,10 +22516,10 @@ - printf "%s\n" "#define ALT_SOABI \"${ALT_SOABI}\"" >>confdefs.h + done -@@ -27949,6 +28188,28 @@ +-# On Android and iOS, clock_settime can be linked (so it is found by ++# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by + # configure), but when used in an unprivileged process, it crashes rather than + # returning an error. Force the symbol off. +-if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" ++if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" + then + + for ac_func in clock_settime +@@ -24537,8 +24746,8 @@ + MODULE_LDFLAGS="\$(BLDLIBRARY)" + fi + +-# On iOS the shared libraries must be linked with the Python framework +-if test "$ac_sys_system" = "iOS"; then ++# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework ++if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then + MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" + fi + +@@ -27238,7 +27447,7 @@ + { 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" = "Linux-android" || test "$ac_sys_system" = "iOS"; then ++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then + ac_cv_file__dev_ptmx=no + ac_cv_file__dev_ptc=no + else +@@ -27671,7 +27880,7 @@ + with_ensurepip=no ;; #( + WASI) : + with_ensurepip=no ;; #( +- iOS) : ++ iOS|tvOS|watchOS) : + with_ensurepip=no ;; #( + *) : + with_ensurepip=upgrade +@@ -28698,7 +28907,7 @@ ;; #( Darwin) : ;; #( +- iOS) : + iOS|tvOS|watchOS) : -+ -+ -+ -+ 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*) : -@@ -31528,10 +31789,14 @@ - do - case $ac_config_target in - "pyconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS pyconfig.h" ;; -+ "iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES iOS/Resources/Info.plist" ;; -+ "Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist") CONFIG_FILES="$CONFIG_FILES Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist" ;; + +@@ -32463,6 +32672,8 @@ + "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" ;; + "tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES tvOS/Resources/Info.plist" ;; + "watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES watchOS/Resources/Info.plist" ;; - "Mac/Makefile") CONFIG_FILES="$CONFIG_FILES Mac/Makefile" ;; - "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" ;; -+ "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/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 cd69f0ede5..0a3321d9f5 100644 +index 65975732f72..940136f3311 100644 --- a/configure.ac +++ b/configure.ac -@@ -310,6 +310,83 @@ - AC_MSG_ERROR([pkg-config is required])] - fi - -+# Set name for machine-dependent library files -+AC_ARG_VAR([MACHDEP], [name for machine-dependent library files]) -+AC_MSG_CHECKING([MACHDEP]) -+if test -z "$MACHDEP" -+then -+ # avoid using uname for cross builds -+ if test "$cross_compiling" = yes; then -+ # ac_sys_system and ac_sys_release are used for setting -+ # a lot of different things including 'define_xopen_source' -+ # in the case statement below. -+ case "$host" in -+ *-*-linux-android*) -+ ac_sys_system=Linux-android -+ ;; -+ *-*-linux*) -+ ac_sys_system=Linux -+ ;; -+ *-*-cygwin*) -+ ac_sys_system=Cygwin -+ ;; -+ *-apple-ios*) -+ ac_sys_system=iOS -+ ;; +@@ -330,6 +330,12 @@ + *-apple-ios*) + ac_sys_system=iOS + ;; + *-apple-tvos*) + ac_sys_system=tvOS + ;; + *-apple-watchos*) + ac_sys_system=watchOS + ;; -+ *-*-vxworks*) -+ ac_sys_system=VxWorks -+ ;; -+ *-*-emscripten) -+ ac_sys_system=Emscripten -+ ;; -+ *-*-wasi) -+ ac_sys_system=WASI -+ ;; -+ *) -+ # for now, limit cross builds to known configurations -+ MACHDEP="unknown" -+ AC_MSG_ERROR([cross build not supported for $host]) -+ esac -+ ac_sys_release= -+ else -+ ac_sys_system=`uname -s` -+ if test "$ac_sys_system" = "AIX" \ -+ -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then -+ ac_sys_release=`uname -v` -+ else -+ ac_sys_release=`uname -r` -+ fi -+ fi -+ ac_md_system=`echo $ac_sys_system | -+ tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'` -+ ac_md_release=`echo $ac_sys_release | -+ tr -d '[/ ]' | sed 's/^[[A-Z]]\.//' | sed 's/\..*//'` -+ MACHDEP="$ac_md_system$ac_md_release" -+ -+ case $MACHDEP in -+ aix*) MACHDEP="aix";; -+ linux*) MACHDEP="linux";; -+ cygwin*) MACHDEP="cygwin";; -+ darwin*) MACHDEP="darwin";; -+ '') MACHDEP="unknown";; -+ esac -+ -+ if test "$ac_sys_system" = "SunOS"; then -+ # For Solaris, there isn't an OS version specific macro defined -+ # in most compilers, so we define one here. -+ SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\([0-9]\)$!.0\1!g' | tr -d '.'` -+ AC_DEFINE_UNQUOTED([Py_SUNOS_VERSION], [$SUNOS_VERSION], -+ [The version of SunOS/Solaris as reported by `uname -r' without the dot.]) -+ fi -+fi -+AC_MSG_RESULT(["$MACHDEP"]) -+ - AC_MSG_CHECKING([for --enable-universalsdk]) - AC_ARG_ENABLE([universalsdk], - AS_HELP_STRING([--enable-universalsdk@<:@=SDKDIR@:>@], -@@ -427,11 +504,15 @@ - PYTHONFRAMEWORKDIR=no-framework - PYTHONFRAMEWORKPREFIX= - PYTHONFRAMEWORKINSTALLDIR= -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX= -+ RESSRCDIR= - FRAMEWORKINSTALLFIRST= - FRAMEWORKINSTALLLAST= - FRAMEWORKALTINSTALLFIRST= - FRAMEWORKALTINSTALLLAST= - FRAMEWORKPYTHONW= -+ INSTALLTARGETS="commoninstall bininstall maninstall" -+ - if test "x${prefix}" = "xNONE"; then - FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" - else -@@ -444,66 +525,113 @@ - PYTHONFRAMEWORKINSTALLDIR=$PYTHONFRAMEWORKPREFIX/$PYTHONFRAMEWORKDIR - FRAMEWORKINSTALLFIRST="frameworkinstallstructure" - FRAMEWORKALTINSTALLFIRST="frameworkinstallstructure " -- FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools" -- FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools" -- FRAMEWORKPYTHONW="frameworkpythonw" -- FRAMEWORKINSTALLAPPSPREFIX="/Applications" - -- if test "x${prefix}" = "xNONE" ; then -- FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" -+ case $ac_sys_system in #( -+ iOS) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" - -- else -- FRAMEWORKUNIXTOOLSPREFIX="${prefix}" -- fi -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=iOS/Resources - -- case "${enableval}" in -- /System*) -- FRAMEWORKINSTALLAPPSPREFIX="/Applications" -- if test "${prefix}" = "NONE" ; then -- # See below -- FRAMEWORKUNIXTOOLSPREFIX="/usr" -- fi -- ;; -+ AC_CONFIG_FILES([iOS/Resources/Info.plist]) -+ AC_CONFIG_FILES([Tools/iOSTestbed/iOSTestbed/iOSTestbed-Info.plist]) -+ ;; -+ tvOS) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" - -- /Library*) -- FRAMEWORKINSTALLAPPSPREFIX="/Applications" -- ;; -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=tvOS/Resources - -- */Library/Frameworks) -- MDIR="`dirname "${enableval}"`" -- MDIR="`dirname "${MDIR}"`" -- FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications" -- -- if test "${prefix}" = "NONE"; then -- # User hasn't specified the -- # --prefix option, but wants to install -- # the framework in a non-default location, -- # ensure that the compatibility links get -- # installed relative to that prefix as well -- # instead of in /usr/local. -- FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" -- fi -- ;; -+ AC_CONFIG_FILES([tvOS/Resources/Info.plist]) -+ ;; -+ watchOS) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" -+ FRAMEWORKPYTHONW= -+ INSTALLTARGETS="libinstall inclinstall sharedinstall" - -- *) -- FRAMEWORKINSTALLAPPSPREFIX="/Applications" -- ;; -- esac -+ prefix=$PYTHONFRAMEWORKPREFIX -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" -+ RESSRCDIR=watchOS/Resources - -- prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION -+ AC_CONFIG_FILES([watchOS/Resources/Info.plist]) -+ ;; -+ *) : -+ FRAMEWORKINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools" -+ FRAMEWORKALTINSTALLLAST="frameworkinstallmaclib frameworkinstallapps frameworkaltinstallunixtools" -+ FRAMEWORKPYTHONW="frameworkpythonw" -+ FRAMEWORKINSTALLAPPSPREFIX="/Applications" -+ INSTALLTARGETS="commoninstall bininstall maninstall" - -- # Add files for Mac specific code to the list of output -- # files: -- AC_CONFIG_FILES([Mac/Makefile]) -- AC_CONFIG_FILES([Mac/PythonLauncher/Makefile]) -- AC_CONFIG_FILES([Mac/Resources/framework/Info.plist]) -- AC_CONFIG_FILES([Mac/Resources/app/Info.plist]) -- esac -+ if test "x${prefix}" = "xNONE" ; then -+ FRAMEWORKUNIXTOOLSPREFIX="${ac_default_prefix}" -+ -+ else -+ FRAMEWORKUNIXTOOLSPREFIX="${prefix}" -+ fi -+ -+ case "${enableval}" in -+ /System*) -+ FRAMEWORKINSTALLAPPSPREFIX="/Applications" -+ if test "${prefix}" = "NONE" ; then -+ # See below -+ FRAMEWORKUNIXTOOLSPREFIX="/usr" -+ fi -+ ;; -+ -+ /Library*) -+ FRAMEWORKINSTALLAPPSPREFIX="/Applications" -+ ;; -+ -+ */Library/Frameworks) -+ MDIR="`dirname "${enableval}"`" -+ MDIR="`dirname "${MDIR}"`" -+ FRAMEWORKINSTALLAPPSPREFIX="${MDIR}/Applications" -+ -+ if test "${prefix}" = "NONE"; then -+ # User hasn't specified the -+ # --prefix option, but wants to install -+ # the framework in a non-default location, -+ # ensure that the compatibility links get -+ # installed relative to that prefix as well -+ # instead of in /usr/local. -+ FRAMEWORKUNIXTOOLSPREFIX="${MDIR}" -+ fi -+ ;; -+ -+ *) -+ FRAMEWORKINSTALLAPPSPREFIX="/Applications" -+ ;; -+ esac -+ -+ prefix=$PYTHONFRAMEWORKINSTALLDIR/Versions/$VERSION -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX=${prefix} -+ RESSRCDIR=Mac/Resources/framework -+ -+ # Add files for Mac specific code to the list of output -+ # files: -+ AC_CONFIG_FILES([Mac/Makefile]) -+ AC_CONFIG_FILES([Mac/PythonLauncher/Makefile]) -+ AC_CONFIG_FILES([Mac/Resources/app/Info.plist]) -+ AC_CONFIG_FILES([Mac/Resources/framework/Info.plist]) -+ ;; -+ esac -+ esac + *-*-vxworks*) + ac_sys_system=VxWorks + ;; +@@ -382,7 +388,7 @@ + # On cross-compile builds, configure will look for a host-specific compiler by + # prepending the user-provided host triple to the required binary name. + # +-# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", ++# On iOS/tvOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc", + # which isn't a binary that exists, and isn't very convenient, as it contains the + # iOS version. As the default cross-compiler name won't exist, configure falls + # back to gcc, which *definitely* won't work. We're providing wrapper scripts for +@@ -397,6 +403,14 @@ + aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;; + aarch64-apple-ios*) AR=arm64-apple-ios-ar ;; + x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;; ++ ++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;; ++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;; ++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;; ++ ++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;; ++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;; ++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;; + *) + esac + fi +@@ -405,6 +419,14 @@ + aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;; + aarch64-apple-ios*) CC=arm64-apple-ios-clang ;; + x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;; ++ ++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;; ++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;; ++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;; ++ ++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;; ++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;; ++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;; + *) + esac + fi +@@ -413,6 +435,14 @@ + aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;; + aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;; + x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;; ++ ++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;; ++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;; ++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;; ++ ++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;; ++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;; ++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;; + *) + esac + fi +@@ -421,6 +451,14 @@ + aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang ;; + aarch64-apple-ios*) CXX=arm64-apple-ios-clang ;; + x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang ;; ++ ++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang ;; ++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang ;; ++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang ;; ++ ++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang ;; ++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang ;; ++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang ;; + *) + esac + fi +@@ -535,8 +573,10 @@ + case $enableval in + yes) + case $ac_sys_system in +- Darwin) enableval=/Library/Frameworks ;; +- iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ Darwin) enableval=/Library/Frameworks ;; ++ iOS) enableval=iOS/Frameworks/\$\(MULTIARCH\) ;; ++ tvOS) enableval=tvOS/Frameworks/\$\(MULTIARCH\) ;; ++ watchOS) enableval=watchOS/Frameworks/\$\(MULTIARCH\) ;; + *) AC_MSG_ERROR([Unknown platform for framework build]) + esac + esac +@@ -545,6 +585,8 @@ + no) + case $ac_sys_system in + iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; ++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; ++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -647,6 +689,34 @@ + + AC_CONFIG_FILES([iOS/Resources/Info.plist]) + ;; ++ tvOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=tvOS/Resources ++ ++ AC_CONFIG_FILES([tvOS/Resources/Info.plist]) ++ ;; ++ watchOS) : ++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure" ++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure " ++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders" ++ FRAMEWORKPYTHONW= ++ INSTALLTARGETS="libinstall inclinstall sharedinstall" ++ ++ prefix=$PYTHONFRAMEWORKPREFIX ++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR" ++ RESSRCDIR=watchOS/Resources ++ ++ AC_CONFIG_FILES([watchOS/Resources/Info.plist]) ++ ;; + *) + AC_MSG_ERROR([Unknown platform for framework build]) + ;; +@@ -655,6 +725,8 @@ ],[ - PYTHONFRAMEWORK= - PYTHONFRAMEWORKDIR=no-framework - PYTHONFRAMEWORKPREFIX= - PYTHONFRAMEWORKINSTALLDIR= -+ PYTHONFRAMEWORKINSTALLNAMEPREFIX= -+ RESSRCDIR= - FRAMEWORKINSTALLFIRST= - FRAMEWORKINSTALLLAST= - FRAMEWORKALTINSTALLFIRST= -@@ -522,6 +650,8 @@ - AC_SUBST([PYTHONFRAMEWORKDIR]) - AC_SUBST([PYTHONFRAMEWORKPREFIX]) - AC_SUBST([PYTHONFRAMEWORKINSTALLDIR]) -+AC_SUBST([PYTHONFRAMEWORKINSTALLNAMEPREFIX]) -+AC_SUBST([RESSRCDIR]) - AC_SUBST([FRAMEWORKINSTALLFIRST]) - AC_SUBST([FRAMEWORKINSTALLLAST]) - AC_SUBST([FRAMEWORKALTINSTALLFIRST]) -@@ -529,105 +659,113 @@ - AC_SUBST([FRAMEWORKPYTHONW]) - AC_SUBST([FRAMEWORKUNIXTOOLSPREFIX]) - AC_SUBST([FRAMEWORKINSTALLAPPSPREFIX]) -+AC_SUBST([INSTALLTARGETS]) - + case $ac_sys_system in + iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;; ++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;; ++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;; + *) + PYTHONFRAMEWORK= + PYTHONFRAMEWORKDIR=no-framework +@@ -695,6 +767,47 @@ AC_DEFINE_UNQUOTED([_PYTHONFRAMEWORK], ["${PYTHONFRAMEWORK}"], [framework name]) --# Set name for machine-dependent library files --AC_ARG_VAR([MACHDEP], [name for machine-dependent library files]) --AC_MSG_CHECKING([MACHDEP]) --if test -z "$MACHDEP" --then -- # avoid using uname for cross builds -- if test "$cross_compiling" = yes; then -- # ac_sys_system and ac_sys_release are used for setting -- # a lot of different things including 'define_xopen_source' -- # in the case statement below. -- case "$host" in -- *-*-linux-android*) -- ac_sys_system=Linux-android -- ;; -- *-*-linux*) -- ac_sys_system=Linux -- ;; -- *-*-cygwin*) -- ac_sys_system=Cygwin -- ;; -- *-*-vxworks*) -- ac_sys_system=VxWorks -- ;; -- *-*-emscripten) -- ac_sys_system=Emscripten -- ;; -- *-*-wasi) -- ac_sys_system=WASI -- ;; -- *) -- # for now, limit cross builds to known configurations -- MACHDEP="unknown" -- AC_MSG_ERROR([cross build not supported for $host]) -- esac -- ac_sys_release= -- else -- ac_sys_system=`uname -s` -- if test "$ac_sys_system" = "AIX" \ -- -o "$ac_sys_system" = "UnixWare" -o "$ac_sys_system" = "OpenUNIX"; then -- ac_sys_release=`uname -v` -- else -- ac_sys_release=`uname -r` -- fi -- fi -- ac_md_system=`echo $ac_sys_system | -- tr -d '[/ ]' | tr '[[A-Z]]' '[[a-z]]'` -- ac_md_release=`echo $ac_sys_release | -- tr -d '[/ ]' | sed 's/^[[A-Z]]\.//' | sed 's/\..*//'` -- MACHDEP="$ac_md_system$ac_md_release" -- -- case $MACHDEP in -- aix*) MACHDEP="aix";; -- linux*) MACHDEP="linux";; -- cygwin*) MACHDEP="cygwin";; -- darwin*) MACHDEP="darwin";; -- '') MACHDEP="unknown";; -- esac -- -- if test "$ac_sys_system" = "SunOS"; then -- # For Solaris, there isn't an OS version specific macro defined -- # in most compilers, so we define one here. -- SUNOS_VERSION=`echo $ac_sys_release | sed -e 's!\.\([0-9]\)$!.0\1!g' | tr -d '.'` -- AC_DEFINE_UNQUOTED([Py_SUNOS_VERSION], [$SUNOS_VERSION], -- [The version of SunOS/Solaris as reported by `uname -r' without the dot.]) -- fi --fi --AC_MSG_RESULT(["$MACHDEP"]) -- ++dnl quadrigraphs "@<:@" and "@:>@" produce "[" and "]" in the output ++AC_MSG_CHECKING([for --with-app-store-compliance]) ++AC_ARG_WITH( ++ [app_store_compliance], ++ [AS_HELP_STRING( ++ [--with-app-store-compliance=@<:@PATCH-FILE@:>@], ++ [Enable any patches required for compiliance with app stores. ++ Optional PATCH-FILE specifies the custom patch to apply.] ++ )],[ ++ case "$withval" in ++ yes) ++ case $ac_sys_system in ++ Darwin|iOS|tvOS|watchOS) ++ # iOS/tvOS/watchOS is able to share the macOS patch ++ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" ++ ;; ++ *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;; ++ esac ++ AC_MSG_RESULT([applying default app store compliance patch]) ++ ;; ++ *) ++ APP_STORE_COMPLIANCE_PATCH="${withval}" ++ AC_MSG_RESULT([applying custom app store compliance patch]) ++ ;; ++ esac ++ ],[ ++ case $ac_sys_system in ++ iOS|tvOS|watchOS) ++ # Always apply the compliance patch on iOS/tvOS/watchOS; we can use the macOS patch ++ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" ++ AC_MSG_RESULT([applying default app store compliance patch]) ++ ;; ++ *) ++ # No default app compliance patching on any other platform ++ APP_STORE_COMPLIANCE_PATCH= ++ AC_MSG_RESULT([not patching for app store compliance]) ++ ;; ++ esac ++]) ++AC_SUBST([APP_STORE_COMPLIANCE_PATCH]) ++ AC_SUBST([_PYTHON_HOST_PLATFORM]) if test "$cross_compiling" = yes; then case "$host" in - *-*-linux*) - case "$host_cpu" in - arm*) -- _host_cpu=arm -+ _host_ident=arm - ;; - *) -- _host_cpu=$host_cpu -+ _host_ident=$host_cpu +@@ -730,6 +843,46 @@ + ;; esac ;; - *-*-cygwin*) -- _host_cpu= -+ _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 -+ ;; -+ *-apple-tvos*-simulator) -+ _host_os=`echo $host | cut -d '-' -f3` -+ TVOS_DEPLOYMENT_TARGET=${_host_os:4} -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvsimulator-arm64 -+ ;; -+ *) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvsimulator-$host_cpu -+ esac -+ ;; -+ *-apple-tvos*) -+ _host_os=`echo $host | cut -d '-' -f3` -+ TVOS_DEPLOYMENT_TARGET=${_host_os:4} -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvos-arm64 -+ ;; -+ *) -+ _host_ident=${TVOS_DEPLOYMENT_TARGET}-appletvos-$host_cpu -+ esac -+ ;; -+ *-apple-watchos*-simulator) ++ *-apple-tvos*) + _host_os=`echo $host | cut -d '-' -f3` -+ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version ++ AC_MSG_CHECKING([tvOS deployment target]) ++ TVOS_DEPLOYMENT_TARGET=${_host_os:4} ++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0} ++ AC_MSG_RESULT([$TVOS_DEPLOYMENT_TARGET]) ++ + case "$host_cpu" in -+ aarch64) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchsimulator-arm64 -+ ;; -+ *) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchsimulator-$host_cpu -+ esac -+ ;; -+ *-apple-watchos*) ++ aarch64) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device} ++ ;; ++ *) ++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device} ++ ;; ++ esac ++ ;; ++ *-apple-watchos*) + _host_os=`echo $host | cut -d '-' -f3` -+ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} -+ case "$host_cpu" in -+ aarch64) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchosos-arm64_32 -+ ;; -+ *) -+ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-watchosos-$host_cpu -+ esac -+ ;; -+ *-apple-*) ++ _host_device=`echo $host | cut -d '-' -f4` ++ _host_device=${_host_device:=os} ++ ++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version ++ AC_MSG_CHECKING([watchOS deployment target]) ++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7} ++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} ++ AC_MSG_RESULT([$WATCHOS_DEPLOYMENT_TARGET]) ++ + case "$host_cpu" in -+ arm*) -+ _host_ident=arm -+ ;; -+ *) -+ _host_ident=$host_cpu ++ aarch64) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device} ++ ;; ++ *) ++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device} ++ ;; + esac - ;; ++ ;; *-*-vxworks*) -- _host_cpu=$host_cpu -+ _host_ident=$host_cpu + _host_ident=$host_cpu ;; - wasm32-*-* | wasm64-*-*) -- _host_cpu=$host_cpu -+ _host_ident=$host_cpu - ;; - *) - # for now, limit cross builds to known configurations - MACHDEP="unknown" - AC_MSG_ERROR([cross build not supported for $host]) - esac -- _PYTHON_HOST_PLATFORM="$MACHDEP${_host_cpu:+-$_host_cpu}" -+ _PYTHON_HOST_PLATFORM="$MACHDEP${_host_ident:+-$_host_ident}" - fi - - # Some systems cannot stand _XOPEN_SOURCE being defined at all; they -@@ -693,6 +831,13 @@ +@@ -807,9 +960,13 @@ 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 iOS, defining _POSIX_C_SOURCE also disables platform specific features. ++ # On iOS/tvOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features. + iOS/*) + define_xopen_source=no;; + tvOS/*) + define_xopen_source=no;; + watchOS/*) @@ -4565,701 +1269,283 @@ index cd69f0ede5..0a3321d9f5 100644 # On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from # defining NI_NUMERICHOST. QNX/6.3.2) -@@ -783,6 +928,26 @@ +@@ -868,8 +1025,11 @@ + CONFIGURE_MACOSX_DEPLOYMENT_TARGET= + EXPORT_MACOSX_DEPLOYMENT_TARGET='#' + +-# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple. ++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET / ++# WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple. + AC_SUBST([IPHONEOS_DEPLOYMENT_TARGET]) ++AC_SUBST([TVOS_DEPLOYMENT_TARGET]) ++AC_SUBST([WATCHOS_DEPLOYMENT_TARGET]) + + # checks for alternative programs + +@@ -903,11 +1063,17 @@ ], ) -+dnl iOS/tvOS/watchOS need to enforce the deployment target. -+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]) +-dnl Add the compiler flag for the iOS minimum supported OS version. ++dnl Add the compiler flag for the iOS/tvOS/watchOS minimum supported OS version. + AS_CASE([$ac_sys_system], + [iOS], [ + AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) + AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"]) + ],[tvOS], [ -+ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=9.0} + AS_VAR_APPEND([CFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) + AS_VAR_APPEND([LDFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"]) -+ AC_SUBST([TVOS_DEPLOYMENT_TARGET]) + ],[watchOS], [ -+ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0} + AS_VAR_APPEND([CFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) + AS_VAR_APPEND([LDFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"]) -+ AC_SUBST([WATCHOS_DEPLOYMENT_TARGET]) -+ ], -+) -+ - if test "$ac_sys_system" = "Darwin" - then - dnl look for SDKROOT -@@ -941,11 +1106,13 @@ - AC_MSG_CHECKING([for multiarch]) + ], + ) + +@@ -1095,6 +1261,8 @@ AS_CASE([$ac_sys_system], [Darwin*], [MULTIARCH=""], -+ [iOS], [MULTIARCH=""], + [iOS], [MULTIARCH=""], + [tvOS], [MULTIARCH=""], + [watchOS], [MULTIARCH=""], [FreeBSD*], [MULTIARCH=""], [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] ) - AC_SUBST([MULTIARCH]) --AC_MSG_RESULT([$MULTIARCH]) - - if test x$PLATFORM_TRIPLET != x && test x$MULTIARCH != x; then - if test x$PLATFORM_TRIPLET != x$MULTIARCH; then -@@ -955,6 +1122,12 @@ - MULTIARCH=$PLATFORM_TRIPLET - fi - AC_SUBST([PLATFORM_TRIPLET]) -+AC_MSG_RESULT([$MULTIARCH]) -+ -+AS_CASE([$ac_sys_system], -+ [iOS|tvOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f1`], -+ [SOABI_PLATFORM=$PLATFORM_TRIPLET] -+) - - if test x$MULTIARCH != x; then - MULTIARCH_CPPFLAGS="-DMULTIARCH=\\\"$MULTIARCH\\\"" -@@ -985,6 +1158,9 @@ - [wasm32-unknown-emscripten/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly Emscripten - [wasm32-unknown-wasi/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly System Interface - [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 -+ [x86_64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on x86_64 -+ [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64 - [PY_SUPPORT_TIER=0] +@@ -1116,7 +1284,7 @@ + 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`], ++ [iOS|tvOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`], + [SOABI_PLATFORM=$PLATFORM_TRIPLET] ) -@@ -1298,17 +1474,23 @@ - - AC_MSG_CHECKING([LDLIBRARY]) - --# MacOSX framework builds need more magic. LDLIBRARY is the dynamic -+# iOS/MacOSX framework builds need more magic. LDLIBRARY is the dynamic - # library that we build, but we do not want to link against it (we - # 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 -- LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' -- RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}} -+ case $ac_sys_system in -+ iOS|tvOS|watchOS) -+ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; -+ *) -+ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; -+ esac - BLDLIBRARY='' -+ RUNSHARED=DYLD_FRAMEWORK_PATH=`pwd`${DYLD_FRAMEWORK_PATH:+:${DYLD_FRAMEWORK_PATH}} - else - BLDLIBRARY='$(LDLIBRARY)' - fi -@@ -1357,12 +1539,16 @@ - ;; - Darwin*) - LDLIBRARY='libpython$(LDVERSION).dylib' -- BLDLIBRARY='-L. -lpython$(LDVERSION)' -- RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} -+ BLDLIBRARY='-L. -lpython$(LDVERSION)' -+ RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} -+ ;; +@@ -1150,6 +1318,10 @@ + [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 ++ [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl tvOS Simulator on arm64 ++ [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl tvOS on ARM64 ++ [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl watchOS Simulator on arm64 ++ [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl watchOS on ARM64 + [aarch64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on ARM64 + [x86_64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on AMD64 + +@@ -1481,7 +1653,7 @@ + case $ac_sys_system in + Darwin) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';; +- iOS) ++ iOS|tvOS|watchOS) + LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';; + *) + AC_MSG_ERROR([Unknown platform for framework build]);; +@@ -1546,7 +1718,7 @@ + BLDLIBRARY='-L. -lpython$(LDVERSION)' + RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}} + ;; +- iOS) + iOS|tvOS|watchOS) -+ LDLIBRARY='libpython$(LDVERSION).dylib' -+ BLDLIBRARY='-L. -lpython$(LDVERSION)' - ;; + LDLIBRARY='libpython$(LDVERSION).dylib' + ;; AIX*) -- LDLIBRARY='libpython$(LDVERSION).so' -- RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}} -+ LDLIBRARY='libpython$(LDVERSION).so' -+ RUNSHARED=LIBPATH=`pwd`${LIBPATH:+:${LIBPATH}} - ;; - - esac -@@ -3085,6 +3271,7 @@ - esac - ;; - CYGWIN*) SHLIB_SUFFIX=.dll;; -+ iOS|tvOS|watchOS) SHLIB_SUFFIX=.dylib;; - *) SHLIB_SUFFIX=.so;; - esac - fi -@@ -3165,6 +3352,11 @@ +@@ -3417,7 +3589,7 @@ BLDSHARED="$LDSHARED" fi ;; +- iOS/*) + iOS/*|tvOS/*|watchOS/*) -+ LDSHARED='$(CC) -dynamiclib -F . -framework Python' -+ LDCXXSHARED='$(CXX) -dynamiclib -F . -framework Python' -+ BLDSHARED="$LDSHARED" -+ ;; - Emscripten|WASI) - LDSHARED='$(CC) -shared' - LDCXXSHARED='$(CXX) -shared';; -@@ -3309,6 +3501,24 @@ - LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)' + BLDSHARED="$LDSHARED" +@@ -3541,7 +3713,7 @@ + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; + Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; + # -u libsys_s pulls in all symbols in libsys +- Darwin/*|iOS/*) ++ Darwin/*|iOS/*|tvOS/*|watchOS/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" + + # Issue #18075: the default maximum stack size (8MBytes) is too +@@ -3565,7 +3737,7 @@ + LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)' + fi + LINKFORSHARED="$LINKFORSHARED" +- elif test $ac_sys_system = "iOS"; then ++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS"; then + LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)' fi - LINKFORSHARED="$LINKFORSHARED";; -+ iOS/*|tvOS/*|watchOS/*) -+ 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";; -@@ -3682,6 +3892,9 @@ + ;; +@@ -3949,7 +4121,7 @@ dnl when do we need USING_APPLE_OS_LIBFFI? ctypes_malloc_closure=yes ], +- [iOS], [ + [iOS|tvOS|watchOS], [ -+ ctypes_malloc_closure=yes -+ ], + ctypes_malloc_closure=yes + ], [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])] - ) - AS_VAR_IF([ctypes_malloc_closure], [yes], [ -@@ -5714,7 +5927,7 @@ - AC_MSG_CHECKING([ABIFLAGS]) - AC_MSG_RESULT([$ABIFLAGS]) - AC_MSG_CHECKING([SOABI]) --SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET} -+SOABI='cpython-'`echo $VERSION | tr -d .`${ABIFLAGS}${SOABI_PLATFORM:+-$SOABI_PLATFORM} - AC_MSG_RESULT([$SOABI]) +@@ -5043,9 +5215,9 @@ + # checks for library functions + AC_CHECK_FUNCS([ \ + accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \ +- copy_file_range ctermid dup dup3 execv explicit_bzero explicit_memset \ ++ copy_file_range ctermid dup dup3 explicit_bzero explicit_memset \ + faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \ +- fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \ ++ fpathconf fstatat ftime ftruncate futimens futimes futimesat \ + gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \ + getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin \ + getpeername getpgid getpid getppid getpriority _getpty \ +@@ -5053,15 +5225,14 @@ + getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \ + lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \ + mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \ +- pipe2 plock poll posix_fadvise posix_fallocate posix_openpt posix_spawn posix_spawnp \ +- posix_spawn_file_actions_addclosefrom_np \ ++ pipe2 plock poll posix_fadvise posix_fallocate posix_openpt \ + pread preadv preadv2 process_vm_readv pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \ + pthread_kill ptsname ptsname_r pwrite pwritev pwritev2 readlink readlinkat readv realpath renameat \ + rtpSpawn sched_get_priority_max sched_rr_get_interval sched_setaffinity \ + sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \ + sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \ + setitimer setlocale setpgid setpgrp setpriority setregid setresgid \ +- setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \ ++ setresuid setreuid setsid setuid setvbuf shutdown sigaction \ + sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \ + sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \ + sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \ +@@ -5076,12 +5247,20 @@ + AC_CHECK_FUNCS([lchmod]) + fi + +-# iOS defines some system methods that can be linked (so they are ++# iOS/tvOS/watchOS define 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]) ++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([ getentropy getgroups system ]) ++fi ++ ++# tvOS/watchOS have some additional methods that can be found, but not used. ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([ \ ++ execv fork fork1 posix_spawn posix_spawnp posix_spawn_file_actions_addclosefrom_np \ ++ sigaltstack \ ++ ]) + fi + + AC_CHECK_DECL([dirfd], +@@ -5332,20 +5511,22 @@ + ]) + + # check for openpty, login_tty, and forkpty +- +-AC_CHECK_FUNCS([openpty], [], +- [AC_CHECK_LIB([util], [openpty], +- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], +- [AC_CHECK_LIB([bsd], [openpty], +- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) +-AC_SEARCH_LIBS([login_tty], [util], +- [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] +-) +-AC_CHECK_FUNCS([forkpty], [], +- [AC_CHECK_LIB([util], [forkpty], +- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], +- [AC_CHECK_LIB([bsd], [forkpty], +- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) ++# tvOS/watchOS have functions for tty, but can't use them ++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then ++ AC_CHECK_FUNCS([openpty], [], ++ [AC_CHECK_LIB([util], [openpty], ++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"], ++ [AC_CHECK_LIB([bsd], [openpty], ++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])]) ++ AC_SEARCH_LIBS([login_tty], [util], ++ [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] ++ ) ++ AC_CHECK_FUNCS([forkpty], [], ++ [AC_CHECK_LIB([util], [forkpty], ++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"], ++ [AC_CHECK_LIB([bsd], [forkpty], ++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])]) ++fi + + # check for long file support functions + AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs]) +@@ -5384,10 +5565,10 @@ + ]) + ]) + +-# On Android and iOS, clock_settime can be linked (so it is found by ++# On Android, iOS, tvOS and watchOS, clock_settime can be linked (so it is found by + # configure), but when used in an unprivileged process, it crashes rather than + # returning an error. Force the symbol off. +-if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS" ++if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" + then + AC_CHECK_FUNCS([clock_settime], [], [ + AC_CHECK_LIB([rt], [clock_settime], [ +@@ -6135,8 +6316,8 @@ + MODULE_LDFLAGS="\$(BLDLIBRARY)" + fi - # Release build, debug build (Py_DEBUG), and trace refs build (Py_TRACE_REFS) -@@ -5722,7 +5935,7 @@ - if test "$Py_DEBUG" = 'true'; then - # Similar to SOABI but remove "d" flag from ABIFLAGS - AC_SUBST([ALT_SOABI]) -- ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${PLATFORM_TRIPLET:+-$PLATFORM_TRIPLET} -+ ALT_SOABI='cpython-'`echo $VERSION | tr -d .``echo $ABIFLAGS | tr -d d`${SOABI_PLATFORM:+-$SOABI_PLATFORM} - AC_DEFINE_UNQUOTED([ALT_SOABI], ["${ALT_SOABI}"], - [Alternative SOABI used in debug build to load C extensions built in release mode]) +-# On iOS the shared libraries must be linked with the Python framework +-if test "$ac_sys_system" = "iOS"; then ++# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework ++if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "watchOS"; then + MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)" fi -@@ -7068,6 +7281,29 @@ + +@@ -6772,7 +6953,7 @@ + dnl NOTE: Inform user how to proceed with files when cross compiling. + dnl Some 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" = "Linux-android" || test "$ac_sys_system" = "iOS"; then ++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "watchOS" ; then + ac_cv_file__dev_ptmx=no + ac_cv_file__dev_ptc=no + else +@@ -7029,7 +7210,7 @@ + AS_CASE([$ac_sys_system], + [Emscripten], [with_ensurepip=no], + [WASI], [with_ensurepip=no], +- [iOS], [with_ensurepip=no], ++ [iOS|tvOS|watchOS], [with_ensurepip=no], + [with_ensurepip=upgrade] + ) + ]) +@@ -7439,7 +7620,7 @@ [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])], dnl The _scproxy module is available on macOS [Darwin], [], +- [iOS], [ + [iOS|tvOS|watchOS], [ -+ 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])], ---- /dev/null -+++ b/iOS/README.rst -@@ -0,0 +1,354 @@ -+==================== -+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, on the most -+recently released macOS. -+ -+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. -+ -+How do I build Python for iOS? -+------------------------------ -+ -+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: -+ -+1. Produce multiple ``Python.framework`` builds, one for each ABI and -+ architecture; -+2. Merge the binaries for each architecture on a given ABI into a single "fat" -+ binary. This can be done using the ``lipo`` tool, provide by Xcode: -+ -+ $ lipo -create -output module.dylib path/to/x86_64/module.dylib path/to/arm64/module.dylib -+ -+3. Merge the headers for each architecture. The header files will be identical on each platform, -+ 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 into the merged headers folder. -+ This will allow the two Python architectures to share header files. -+4. Merge the "fat" frameworks for each ABI into a single XCframework. -+ -+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:$PATH -+ $ ./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 \ -+ ac_cv_file__dev_ptmx=no \ -+ ac_cv_file__dev_ptc=no -+ $ 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; howver, ``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. -+ -+* ``/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). -+ -+How do I test 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. -+ -+How do I debug 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. -+ -+Using Python on iOS -+=================== -+ -+To add Python to an iOS Xcode project: -+ -+1. Build Python for each architecture that you want to support. 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`. This will -+ produce a ``Python.framework``, plus a ``bin`` and ``lib`` folder in the same -+ directory as the ``Python.framework``. -+ -+2. Create an XCframework from the individual single-platform frameworks. The -+ basic structure can be compiled from the individual ``Python.framework`` -+ outputs:: -+ -+ 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-simulator -+ cp path/to/iphonesimulator/lib Python.xcframework/ios-arm64-simulator -+ -+ Note that the name of the architecture-specific slice for the simulator will -+ depend on the CPU architecture that you build. -+ -+3. Add symbolic links to "common" platform names for each slice:: -+ -+ ln -si ios-arm64 Python.xcframework/iphoneos -+ ln -si ios-arm64-simulator Python.xcframework/iphonesimulator -+ -+4. 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. -+ -+5. Drag the ``iOS/Resources/dylib-Info-template.plist`` file into your project, -+ and ensure it is associated with the app target. -+ -+6. Select the app target by selecting the root node of your Xcode project, then -+ the target name in the sidebar that appears. -+ -+7. In the "General" settings, under "Frameworks, Libraries and Embedded -+ Content", Add ``Python.xcframework``, with "Embed & Sign" selected. -+ -+8. In the "Build Settings" tab, modify the following: -+ -+ - Build Options -+ * User script sandboxing: No -+ - 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 -+ -+9. 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 -+ -+10. 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" -+ defaults write "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" CFBundleExecutable -string "$DYLIB" -+ defaults write "$CODESIGNING_FOLDER_PATH/$FRAMEWORK_FOLDER/Info.plist" CFBundleIdentifier -string "$FRAMEWORK_BUNDLE_ID" -+ 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 "{}" \; -+ -+11. 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. ---- /dev/null + 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 +diff --git a/iOS/Resources/Info.plist.in b/iOS/Resources/Info.plist.in +index c3e261ecd9e..26ef7a95de4 100644 +--- a/iOS/Resources/Info.plist.in +++ 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 +@@ -17,13 +17,13 @@ + CFBundlePackageType + FMWK + CFBundleShortVersionString +- @VERSION@ + %VERSION% -+ CFBundleLongVersionString -+ %VERSION%, (c) 2001-2023 Python Software Foundation. -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ 1 -+ CFBundleSupportedPlatforms -+ -+ iPhoneOS -+ -+ MinimumOSVersion -+ @IOS_DEPLOYMENT_TARGET@ -+ -+ ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-ar -@@ -0,0 +1,2 @@ -+#!/bin/bash -+xcrun --sdk iphoneos ar $@ ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-clang -@@ -0,0 +1,2 @@ -+#!/bin/bash -+xcrun --sdk iphoneos clang -target arm64-apple-ios $@ ---- /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 $@ ---- /dev/null -+++ b/iOS/Resources/bin/arm64-apple-ios-simulator-ar -@@ -0,0 +1,2 @@ -+#!/bin/bash -+xcrun --sdk iphonesimulator ar $@ ---- /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 $@ ---- /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 $@ ---- /dev/null -+++ b/iOS/Resources/bin/x86_64-apple-ios-simulator-ar -@@ -0,0 +1,2 @@ -+#!/bin/bash -+xcrun --sdk iphonesimulator ar $@ ---- /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 $@ ---- /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 $@ ---- /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 -+ -+ ---- /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 + CFBundleLongVersionString + %VERSION%, (c) 2001-2024 Python Software Foundation. + CFBundleSignature + ???? + CFBundleVersion +- 1 ++ %VERSION% + CFBundleSupportedPlatforms + + iPhoneOS --- /dev/null +++ b/tvOS/README.rst @@ -0,0 +1,108 @@ @@ -5395,11 +1681,11 @@ index cd69f0ede5..0a3321d9f5 100644 + CFBundleShortVersionString + %VERSION% + CFBundleLongVersionString -+ %VERSION%, (c) 2001-2023 Python Software Foundation. ++ %VERSION%, (c) 2001-2024 Python Software Foundation. + CFBundleSignature + ???? + CFBundleVersion -+ %VERSION% ++ 1 + CFBundleSupportedPlatforms + + tvOS @@ -5412,47 +1698,47 @@ index cd69f0ede5..0a3321d9f5 100644 +++ b/tvOS/Resources/bin/arm64-apple-tvos-ar @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvos ar $@ ++xcrun --sdk appletvos${TVOS_SDK_VERSION} ar $@ --- /dev/null +++ b/tvOS/Resources/bin/arm64-apple-tvos-clang @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvos clang -target arm64-apple-tvos $@ ++xcrun --sdk appletvos${TVOS_SDK_VERSION} clang -target arm64-apple-tvos $@ --- /dev/null +++ b/tvOS/Resources/bin/arm64-apple-tvos-cpp @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvos clang -target arm64-apple-tvos -E $@ ++xcrun --sdk appletvos${TVOS_SDK_VERSION} clang -target arm64-apple-tvos -E $@ --- /dev/null +++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-ar @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvsimulator ar $@ ++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} ar $@ --- /dev/null +++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-clang @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvsimulator clang -target arm64-apple-tvos-simulator $@ ++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target arm64-apple-tvos-simulator $@ --- /dev/null +++ b/tvOS/Resources/bin/arm64-apple-tvos-simulator-cpp @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvsimulator clang -target arm64-apple-tvos-simulator -E $@ ++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target arm64-apple-tvos-simulator -E $@ --- /dev/null +++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-ar @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvsimulator ar $@ ++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} ar $@ --- /dev/null +++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-clang @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvsimulator clang -target x86_64-apple-tvos-simulator $@ ++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target x86_64-apple-tvos-simulator $@ --- /dev/null +++ b/tvOS/Resources/bin/x86_64-apple-tvos-simulator-cpp @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk appletvsimulator clang -target x86_64-apple-tvos-simulator -E $@ ++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target x86_64-apple-tvos-simulator -E $@ --- /dev/null +++ b/tvOS/Resources/dylib-Info-template.plist @@ -0,0 +1,26 @@ @@ -5644,12 +1930,12 @@ index cd69f0ede5..0a3321d9f5 100644 +++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-ar @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk watchsimulator ar $@ ++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} ar $@ --- /dev/null +++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-clang @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk watchsimulator clang -target arm64-apple-watchos-simulator $@ ++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target arm64-apple-watchos-simulator $@ --- /dev/null +++ b/watchOS/Resources/bin/arm64-apple-watchos-simulator-cpp @@ -0,0 +1,2 @@ @@ -5659,32 +1945,32 @@ index cd69f0ede5..0a3321d9f5 100644 +++ b/watchOS/Resources/bin/arm64_32-apple-watchos-ar @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk watchos ar $@ ++xcrun --sdk watchos${WATCHOS_SDK_VERSION} ar $@ --- /dev/null +++ b/watchOS/Resources/bin/arm64_32-apple-watchos-clang @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk watchos clang -target arm64_32-apple-watchos $@ ++xcrun --sdk watchos${WATCHOS_SDK_VERSION} clang -target arm64_32-apple-watchos $@ --- /dev/null +++ b/watchOS/Resources/bin/arm64_32-apple-watchos-cpp @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk watchos clang -target arm64_32-apple-watchos -E $@ ++xcrun --sdk watchos${WATCHOS_SDK_VERSION} clang -target arm64_32-apple-watchos -E $@ --- /dev/null +++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-ar @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk watchsimulator ar $@ ++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} ar $@ --- /dev/null +++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-clang @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk watchsimulator clang -target x86_64-apple-watchos-simulator $@ ++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target x86_64-apple-watchos-simulator $@ --- /dev/null +++ b/watchOS/Resources/bin/x86_64-apple-watchos-simulator-cpp @@ -0,0 +1,2 @@ +#!/bin/bash -+xcrun --sdk watchsimulator clang -target x86_64-apple-watchos-simulator -E $@ ++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target x86_64-apple-watchos-simulator -E $@ --- /dev/null +++ b/watchOS/Resources/dylib-Info-template.plist @@ -0,0 +1,26 @@ diff --git a/patch/Python/release.macOS.exclude b/patch/Python/release.macOS.exclude index 1385454..f45bf7f 100644 --- a/patch/Python/release.macOS.exclude +++ b/patch/Python/release.macOS.exclude @@ -2,7 +2,13 @@ # when building macOS Python-Apple-support tarballs from the official Framework # It is used by `tar -X` during the Makefile build. # -./Versions/*/Resources/Python.app -./Versions/*/bin -./Versions/*/etc -./Versions/*/share +Resources/Python.app +Versions/*/bin +Versions/*/etc +Versions/*/Frameworks +Versions/*/lib/python*/idlelib +Versions/*/lib/python*/lib-dynload/_tkinter.* +Versions/*/lib/python*/tkinter +Versions/*/lib/python*/turtle.py +Versions/*/lib/python*/turtledemo +Versions/*/share diff --git a/patch/make-macho-standalone.py b/patch/make-macho-standalone.py deleted file mode 100644 index 975765d..0000000 --- a/patch/make-macho-standalone.py +++ /dev/null @@ -1,10 +0,0 @@ -import os -import sys -from macholib.MachOStandalone import MachOStandalone - - -if __name__ == "__main__": - MachOStandalone( - sys.argv[1], - os.path.abspath(f"{sys.argv[1]}/") - ).run(contents="@rpath/") diff --git a/patch/make-relocatable.sh b/patch/make-relocatable.sh new file mode 100755 index 0000000..f268cd7 --- /dev/null +++ b/patch/make-relocatable.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +FRAMEWORK_BASEDIR=$1 +echo "Making $1 relocatable" +PYTHON_VER=${FRAMEWORK_BASEDIR##*/} +echo "Python version ${PYTHON_VER}" + +pushd ${FRAMEWORK_BASEDIR} + +echo "Rewrite ID of Python library" +install_name_tool -id @rpath/Python.framework/Versions/${PYTHON_VER}/Python Python > /dev/null +for dylib in `ls lib/*.*.dylib`; do + # lib + if [ "${dylib}" != "lib/libpython${PYTHON_VER}.dylib" ] ; then + echo Rewrite ID of ${dylib} + install_name_tool -id @rpath/Python.framework/Versions/${PYTHON_VER}/${dylib} ${FRAMEWORK_BASEDIR}/${dylib} + fi +done +for module in `find . -name "*.dylib" -type f -o -name "*.so" -type f`; do + if [ "$(otool -L ${module} | grep -c /Library/Frameworks/Python.framework)" != "0" ]; then + for dylib in `ls lib/*.*.dylib`; do + echo Rewrite references to ${dylib} in ${module} + install_name_tool -change /Library/Frameworks/Python.framework/Versions/${PYTHON_VER}/${dylib} @rpath/Python.framework/Versions/${PYTHON_VER}/${dylib} ${module} + done + fi +done +popd diff --git a/patch/make-xcrun-alias b/patch/make-xcrun-alias deleted file mode 100755 index 50340e1..0000000 --- a/patch/make-xcrun-alias +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -# A script that writes an executable xcrun alias. -# Arg 1: The name of the file to output -# Arg 2: The arguments to pass to xcrun -mkdir -p $(dirname $1) -cat << EOF > $1 -#!/bin/bash -xcrun $2 \$@ -EOF -chmod +x $1 From ad578a9c265a992f92ac8065af41b70012c31a58 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 30 Jul 2024 09:27:34 +0800 Subject: [PATCH 12/13] Use a branch version of Briefcase. --- .github/workflows/ci.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7f86e85..615c723 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -68,8 +68,10 @@ jobs: - name: Install dependencies if: matrix.run-tests run: | + # TODO - Revert to the development version of Briefcase # Use the development version of Briefcase - python -m pip install git+https://github.com/beeware/briefcase.git + # python -m pip install git+https://github.com/beeware/briefcase.git + python -m pip install git+https://github.com/freakboy3742/briefcase.git@version-bumps - name: Run support testbed check if: matrix.run-tests working-directory: Python-support-testbed From 8a0cd421b3a1f5ce39028328efd9f5b1b76685b2 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 30 Jul 2024 11:12:08 +0800 Subject: [PATCH 13/13] Add a timeout for iOS testing. --- .github/workflows/ci.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 615c723..a9b1b6f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,13 +33,14 @@ jobs: run-tests: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v4.1.7 - name: Extract config variables id: config-vars run: | PYTHON_VER=$(make config | grep "PYTHON_VER=" | cut -d "=" -f 2) echo "PYTHON_VER=${PYTHON_VER}" | tee -a ${GITHUB_OUTPUT} + - name: Set up Python uses: actions/setup-python@v5.1.1 with: @@ -51,6 +52,7 @@ jobs: run: | # Do the build for the requested target. make ${{ matrix.target }} + - name: Upload build artefacts uses: actions/upload-artifact@v4.3.4 with: @@ -72,8 +74,10 @@ jobs: # Use the development version of Briefcase # python -m pip install git+https://github.com/beeware/briefcase.git python -m pip install git+https://github.com/freakboy3742/briefcase.git@version-bumps + - name: Run support testbed check if: matrix.run-tests + timeout-minutes: 10 working-directory: Python-support-testbed # TODO - remove the template_branch option. run: briefcase run ${{ matrix.target }} Xcode --test ${{ matrix.briefcase-run-args }} -C support_package=\'../dist/Python-${{ steps.config-vars.outputs.PYTHON_VER }}-${{ matrix.target }}-support.custom.tar.gz\' -C template_branch=\'framework-lib\'