diff --git a/.gitignore b/.gitignore index 5a32a5f6..0fb0445a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,14 +1,18 @@ *.swo *.swp -src/* +.envrc +.vscode/ archive/* build/* -downloads/* diff/* dist/* -.envrc -.vscode/ +downloads/* +install/* local/* +merge/* +src/* +support/* +wheels/* *.dist-info __pycache__ tests/testbed/macOS diff --git a/Makefile b/Makefile index ca7de673..87725336 100644 --- a/Makefile +++ b/Makefile @@ -39,127 +39,122 @@ 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.9.12 +PYTHON_VERSION=3.9.14 PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+") PYTHON_VER=$(basename $(PYTHON_VERSION)) BZIP2_VERSION=1.0.8 -XZ_VERSION=5.2.5 +XZ_VERSION=5.2.6 -OPENSSL_VERSION_NUMBER=1.1.1 -OPENSSL_REVISION=o -OPENSSL_VERSION=$(OPENSSL_VERSION_NUMBER)$(OPENSSL_REVISION) +# Preference is to use OpenSSL 3; however, Cryptography 3.4.8 (and +# probably some other packages as well) only works with 1.1.1, so +# we need to preserve the ability to build the older OpenSSL (for now...) +OPENSSL_VERSION=3.0.5 +# OPENSSL_VERSION_NUMBER=1.1.1 +# OPENSSL_REVISION=q +# OPENSSL_VERSION=$(OPENSSL_VERSION_NUMBER)$(OPENSSL_REVISION) LIBFFI_VERSION=3.4.2 -# Supported OS and products -PRODUCTS=BZip2 XZ OpenSSL libFFI Python +# Supported OS and dependencies +DEPENDENCIES=BZip2 XZ OpenSSL libFFI OS_LIST=macOS iOS tvOS watchOS +CURL_FLAGS=--fail --location --create-dirs --progress-bar + # macOS targets TARGETS-macOS=macosx.x86_64 macosx.arm64 -CFLAGS-macOS=-mmacosx-version-min=10.15 -CFLAGS-macosx.x86_64= -CFLAGS-macosx.arm64= -SLICE-macosx=macos-arm64_x86_64 -SDK_ROOT-macosx=$(shell xcrun --sdk macosx --show-sdk-path) -CC-macosx=xcrun --sdk macosx clang --sysroot=$(SDK_ROOT-macosx) $(CFLAGS-macOS) +VERSION_MIN-macOS=10.15 +CFLAGS-macOS=-mmacosx-version-min=$(VERSION_MIN-macOS) # iOS targets TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64 -CFLAGS-iOS=-mios-version-min=12.0 -fembed-bitcode -CFLAGS-iphoneos.arm64= -CFLAGS-iphonesimulator.x86_64= -CFLAGS-iphonesimulator.arm64= -SLICE-iphoneos=ios-arm64 -SLICE-iphonesimulator=ios-arm64_x86_64-simulator +VERSION_MIN-iOS=12.0 +CFLAGS-iOS=-mios-version-min=$(VERSION_MIN-iOS) # tvOS targets TARGETS-tvOS=appletvsimulator.x86_64 appletvsimulator.arm64 appletvos.arm64 -CFLAGS-tvOS=-mtvos-version-min=9.0 -fembed-bitcode -CFLAGS-appletvos.arm64= -CFLAGS-appletvsimulator.x86_64= -CFLAGS-appletvsimulator.arm64= -SLICE-appletvos=tvos-arm64 -SLICE-appletvsimulator=tvos-arm64_x86_64-simulator +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 -CFLAGS-watchOS=-mwatchos-version-min=4.0 -fembed-bitcode -CFLAGS_watchsimulator.x86_64= -CFLAGS-watchsimulator.arm64= -CFLAGS-watchos.arm64_32= -SLICE-watchos=watchos-arm64_32 -SLICE-watchsimulator=watchos-arm64_x86_64-simulator +VERSION_MIN-watchOS=4.0 +CFLAGS-watchOS=-mwatchos-version-min=$(VERSION_MIN-watchOS) PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no -# override machine types for arm64 -MACHINE_DETAILED-arm64=aarch64 -MACHINE_SIMPLE-arm64=arm - -# override machine types for arm64_32 -MACHINE_DETAILED-arm64_32=aarch64 -MACHINE_SIMPLE-arm64_32=arm - # The architecture of the machine doing the build HOST_ARCH=$(shell uname -m) +HOST_PYTHON=install/macOS/macosx/python-$(PYTHON_VERSION) +HOST_PYTHON_EXE=$(HOST_PYTHON)/bin/python3 +BDIST_WHEEL=$(HOST_PYTHON)/lib/python$(PYTHON_VER)/site-packages/wheel/bdist_wheel.py + +# Force the path to be minimal. This ensures that anything in the user environment +# (in particular, homebrew and user-provided Python installs) aren't inadvertently +# linked into the support package. +PATH=/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin # Build for all operating systems all: $(OS_LIST) .PHONY: \ - all clean distclean update-patch vars \ - $(foreach product,$(PRODUCTS),$(foreach os,$(OS_LIST),$(product) $(product)-$(os) clean-$(product) clean-$(product)-$(os))) \ - $(foreach os,$(OS_LIST),$(os) clean-$(os) vars-$(os)) + all clean distclean update-patch vars wheels \ + $(foreach product,$(PRODUCTS),$(product) $(foreach os,$(OS_LIST),$(product)-$(os) clean-$(product) clean-$(product)-$(os))) \ + $(foreach product,$(PRODUCTS),$(product)-wheels $(foreach os,$(OS_LIST),$(product)-wheels-$(os) clean-$(product)-wheels-$(os))) \ + $(foreach os,$(OS_LIST),$(os) wheels-$(os) clean-$(os) clean-wheels-$(os) vars-$(os)) # Clean all builds clean: - rm -rf build dist + rm -rf build install merge dist support # Full clean - includes all downloaded products distclean: clean rm -rf downloads downloads: \ - downloads/bzip2-$(BZIP2_VERSION).tgz \ - downloads/xz-$(XZ_VERSION).tgz \ - downloads/openssl-$(OPENSSL_VERSION).tgz \ - downloads/libffi-$(LIBFFI_VERSION).tgz \ - downloads/Python-$(PYTHON_VERSION).tgz + downloads/bzip2-$(BZIP2_VERSION).tar.gz \ + downloads/xz-$(XZ_VERSION).tar.gz \ + downloads/openssl-$(OPENSSL_VERSION).tar.gz \ + downloads/libffi-$(LIBFFI_VERSION).tar.gz \ + downloads/Python-$(PYTHON_VERSION).tar.gz update-patch: - # Generate a diff from the clone of the python/cpython Github repository - # Requireds patchutils (installable via `brew install patchutils`) + # Generate a diff from the clone of the python/cpython Github repository, + # comparing between the current state of the 3.X branch against the v3.X.Y + # tag associated with the release being built. This allows you to + # maintain a branch that contains custom patches against the default Python. + # The patch archived in this respository is based on github.com/freakboy3742/cpython + # Requires patchutils (installable via `brew install patchutils`); this + # also means we need to re-introduce homebrew to the path for the filterdiff + # 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) | filterdiff -X $(PROJECT_DIR)/patch/Python/diff.exclude -p 1 --clean > $(PROJECT_DIR)/patch/Python/Python.patch + cd $(PYTHON_REPO_DIR) && \ + git diff -D v$(PYTHON_VERSION) $(PYTHON_VER) \ + | 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 ########################################################################### # Setup: BZip2 ########################################################################### # Download original BZip2 source code archive. -downloads/bzip2-$(BZIP2_VERSION).tgz: +downloads/bzip2-$(BZIP2_VERSION).tar.gz: @echo ">>> Download BZip2 sources" - mkdir -p downloads - if [ ! -e downloads/bzip2-$(BZIP2_VERSION).tgz ]; then \ - curl --fail -L https://sourceware.org/pub/bzip2/bzip2-$(BZIP2_VERSION).tar.gz \ - -o downloads/bzip2-$(BZIP2_VERSION).tgz; \ - fi + curl $(CURL_FLAGS) -o $@ \ + https://sourceware.org/pub/bzip2/$(notdir $@) ########################################################################### # Setup: XZ (LZMA) ########################################################################### # Download original XZ source code archive. -downloads/xz-$(XZ_VERSION).tgz: +downloads/xz-$(XZ_VERSION).tar.gz: @echo ">>> Download XZ sources" - mkdir -p downloads - if [ ! -e downloads/xz-$(XZ_VERSION).tgz ]; then \ - curl --fail -L http://tukaani.org/xz/xz-$(XZ_VERSION).tar.gz \ - -o downloads/xz-$(XZ_VERSION).tgz; \ - fi + curl $(CURL_FLAGS) -o $@ \ + https://tukaani.org/xz/$(notdir $@) ########################################################################### # Setup: OpenSSL @@ -168,43 +163,32 @@ downloads/xz-$(XZ_VERSION).tgz: ########################################################################### # Download original OpenSSL source code archive. -downloads/openssl-$(OPENSSL_VERSION).tgz: +downloads/openssl-$(OPENSSL_VERSION).tar.gz: @echo ">>> Download OpenSSL sources" - mkdir -p downloads - -if [ ! -e downloads/openssl-$(OPENSSL_VERSION).tgz ]; then \ - curl --fail -L http://openssl.org/source/openssl-$(OPENSSL_VERSION).tar.gz \ - -o downloads/openssl-$(OPENSSL_VERSION).tgz; \ - fi - if [ ! -e downloads/openssl-$(OPENSSL_VERSION).tgz ]; then \ - curl --fail -L http://openssl.org/source/old/$(OPENSSL_VERSION_NUMBER)/openssl-$(OPENSSL_VERSION).tar.gz \ - -o downloads/openssl-$(OPENSSL_VERSION).tgz; \ - fi + curl $(CURL_FLAGS) -o $@ \ + https://openssl.org/source/$(notdir $@) \ + || curl $(CURL_FLAGS) -o $@ \ + https://openssl.org/source/old/$(basename $(OPENSSL_VERSION))/$(notdir $@) ########################################################################### # Setup: libFFI ########################################################################### -# Download original XZ source code archive. -downloads/libffi-$(LIBFFI_VERSION).tgz: +# Download original libFFI source code archive. +downloads/libffi-$(LIBFFI_VERSION).tar.gz: @echo ">>> Download libFFI sources" - mkdir -p downloads - if [ ! -e downloads/libffi-$(LIBFFI_VERSION).tgz ]; then \ - curl --fail -L http://github.com/libffi/libffi/releases/download/v$(LIBFFI_VERSION)/libffi-$(LIBFFI_VERSION).tar.gz \ - -o downloads/libffi-$(LIBFFI_VERSION).tgz; \ - fi + curl $(CURL_FLAGS) -o $@ \ + https://github.com/libffi/libffi/releases/download/v$(LIBFFI_VERSION)/$(notdir $@) ########################################################################### # Setup: Python ########################################################################### # Download original Python source code archive. -downloads/Python-$(PYTHON_VERSION).tgz: +downloads/Python-$(PYTHON_VERSION).tar.gz: @echo ">>> Download Python sources" - mkdir -p downloads - if [ ! -e downloads/Python-$(PYTHON_VERSION).tgz ]; then \ - curl --fail -L https://www.python.org/ftp/python/$(PYTHON_MICRO_VERSION)/Python-$(PYTHON_VERSION).tgz \ - -o downloads/Python-$(PYTHON_VERSION).tgz; \ - fi + curl $(CURL_FLAGS) -o $@ \ + https://www.python.org/ftp/python/$(PYTHON_MICRO_VERSION)/$(basename $(basename $(notdir $@))).tgz ########################################################################### # Build for specified target (from $(TARGETS-*)) @@ -219,172 +203,322 @@ define build-target target=$1 os=$2 +OS_LOWER-$(target)=$(shell echo $(os) | tr '[:upper:]' '[:lower:]') +WHEEL_TAG-$(target)=py3-none-$$(OS_LOWER-$(target))_$$(shell echo $$(VERSION_MIN-$(os))_$(target) | sed "s/\./_/g") + # $(target) can be broken up into is composed of $(SDK).$(ARCH) SDK-$(target)=$$(basename $(target)) ARCH-$(target)=$$(subst .,,$$(suffix $(target))) -ifdef MACHINE_DETAILED-$$(ARCH-$(target)) -MACHINE_DETAILED-$(target)=$$(MACHINE_DETAILED-$$(ARCH-$(target))) -else -MACHINE_DETAILED-$(target)=$$(ARCH-$(target)) -endif -ifdef MACHINE_SIMPLE-$$(ARCH-$(target)) -MACHINE_SIMPLE-$(target)=$$(MACHINE_SIMPLE-$$(ARCH-$(target))) -else -MACHINE_SIMPLE-$(target)=$$(ARCH-$(target)) -endif - -ifeq ($$(findstring simulator,$$(SDK-$(target))),) -TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$(shell echo $(os) | tr '[:upper:]' '[:lower:]') +ifeq ($(os),macOS) +TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-darwin else -TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$(shell echo $(os) | tr '[:upper:]' '[:lower:]')-simulator + ifeq ($$(findstring simulator,$$(SDK-$(target))),) +TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target)) + else +TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))-simulator + endif endif SDK_ROOT-$(target)=$$(shell xcrun --sdk $$(SDK-$(target)) --show-sdk-path) -CC-$(target)=xcrun --sdk $$(SDK-$(target)) clang \ +CC-$(target)=xcrun --sdk $$(SDK-$(target)) clang +CXX-$(target)=xcrun --sdk $$(SDK-$(target)) clang +AR-$(target)=xcrun --sdk $$(SDK-$(target)) ar +CFLAGS-$(target)=\ -target $$(TARGET_TRIPLE-$(target)) \ --sysroot=$$(SDK_ROOT-$(target)) \ - $$(CFLAGS-$(os)) $$(CFLAGS-$(target)) -LDFLAGS-$(target)=-arch $$(ARCH-$(target)) -isysroot=$$(SDK_ROOT-$(target)) + $$(CFLAGS-$(os)) +LDFLAGS-$(target)=\ + -target $$(TARGET_TRIPLE-$(target)) \ + --sysroot=$$(SDK_ROOT-$(target)) \ + $$(CFLAGS-$(os)) ########################################################################### # Target: BZip2 ########################################################################### -BZIP2_DIR-$(target)=build/$(os)/bzip2-$(BZIP2_VERSION)-$(target) -BZIP2_LIB-$(target)=$$(BZIP2_DIR-$(target))/_install/lib/libbz2.a +BZIP2_SRCDIR-$(target)=build/$(os)/$(target)/bzip2-$(BZIP2_VERSION) +BZIP2_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/bzip2-$(BZIP2_VERSION) +BZIP2_LIB-$(target)=$$(BZIP2_INSTALL-$(target))/lib/libbz2.a +BZIP2_WHEEL-$(target)=wheels/dist/bzip2/bzip2-$(BZIP2_VERSION)-1-$$(WHEEL_TAG-$(target)).whl +BZIP2_WHEEL_DISTINFO-$(target)=$$(BZIP2_INSTALL-$(target))/wheel/bzip2-$(BZIP2_VERSION).dist-info -$$(BZIP2_DIR-$(target))/Makefile: downloads/bzip2-$(BZIP2_VERSION).tgz +$$(BZIP2_SRCDIR-$(target))/Makefile: downloads/bzip2-$(BZIP2_VERSION).tar.gz @echo ">>> Unpack BZip2 sources for $(target)" - mkdir -p $$(BZIP2_DIR-$(target)) - tar zxf downloads/bzip2-$(BZIP2_VERSION).tgz --strip-components 1 -C $$(BZIP2_DIR-$(target)) + mkdir -p $$(BZIP2_SRCDIR-$(target)) + tar zxf $$< --strip-components 1 -C $$(BZIP2_SRCDIR-$(target)) # Touch the makefile to ensure that Make identifies it as up to date. - touch $$(BZIP2_DIR-$(target))/Makefile + touch $$(BZIP2_SRCDIR-$(target))/Makefile -$$(BZIP2_LIB-$(target)): $$(BZIP2_DIR-$(target))/Makefile +$$(BZIP2_LIB-$(target)): $$(BZIP2_SRCDIR-$(target))/Makefile @echo ">>> Build BZip2 for $(target)" - cd $$(BZIP2_DIR-$(target)) && \ + cd $$(BZIP2_SRCDIR-$(target)) && \ make install \ - PREFIX="$(PROJECT_DIR)/$$(BZIP2_DIR-$(target))/_install" \ + PREFIX="$$(BZIP2_INSTALL-$(target))" \ CC="$$(CC-$(target))" \ - 2>&1 | tee -a ../bzip2-$(target).build.log + CFLAGS="$$(CFLAGS-$(target))" \ + LDFLAGS="$$(LDFLAGS-$(target))" \ + 2>&1 | tee -a ../bzip2-$(BZIP2_VERSION).build.log + +$$(BZIP2_WHEEL-$(target)): $$(BZIP2_LIB-$(target)) $$(BDIST_WHEEL) + @echo ">>> Build BZip2 wheel for $(target)" + mkdir -p $$(BZIP2_WHEEL_DISTINFO-$(target)) + mkdir -p $$(BZIP2_INSTALL-$(target))/wheel/opt + + # Copy distributable content + cp -r $$(BZIP2_INSTALL-$(target))/include $$(BZIP2_INSTALL-$(target))/wheel/opt/include + cp -r $$(BZIP2_INSTALL-$(target))/lib $$(BZIP2_INSTALL-$(target))/wheel/opt/lib + + # Copy LICENSE file + cp $$(BZIP2_SRCDIR-$(target))/LICENSE $$(BZIP2_WHEEL_DISTINFO-$(target)) + + # Write package metadata + echo "Metadata-Version: 1.2" >> $$(BZIP2_WHEEL_DISTINFO-$(target))/METADATA + echo "Name: bzip2" >> $$(BZIP2_WHEEL_DISTINFO-$(target))/METADATA + echo "Version: $(BZIP2_VERSION)" >> $$(BZIP2_WHEEL_DISTINFO-$(target))/METADATA + echo "Summary: " >> $$(BZIP2_WHEEL_DISTINFO-$(target))/METADATA + echo "Download-URL: " >> $$(BZIP2_WHEEL_DISTINFO-$(target))/METADATA + + # Write wheel metadata + echo "Wheel-Version: 1.0" >> $$(BZIP2_WHEEL_DISTINFO-$(target))/WHEEL + echo "Root-Is-Purelib: false" >> $$(BZIP2_WHEEL_DISTINFO-$(target))/WHEEL + echo "Generator: Python-Apple-support.BeeWare" >> $$(BZIP2_WHEEL_DISTINFO-$(target))/WHEEL + echo "Build: 1" >> $$(BZIP2_WHEEL_DISTINFO-$(target))/WHEEL + echo "Tag: $$(WHEEL_TAG-$(target))" >> $$(BZIP2_WHEEL_DISTINFO-$(target))/WHEEL + + # Pack the wheel + mkdir -p wheels/dist/bzip2 + $(HOST_PYTHON_EXE) -m wheel pack $$(BZIP2_INSTALL-$(target))/wheel --dest-dir wheels/dist/bzip2 --build-number 1 ########################################################################### # Target: XZ (LZMA) ########################################################################### -XZ_DIR-$(target)=build/$(os)/xz-$(XZ_VERSION)-$(target) -XZ_LIB-$(target)=$$(XZ_DIR-$(target))/_install/lib/liblzma.a +XZ_SRCDIR-$(target)=build/$(os)/$(target)/xz-$(XZ_VERSION) +XZ_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/xz-$(XZ_VERSION) +XZ_LIB-$(target)=$$(XZ_INSTALL-$(target))/lib/liblzma.a +XZ_WHEEL-$(target)=wheels/dist/xz/xz-$(XZ_VERSION)-1-$$(WHEEL_TAG-$(target)).whl +XZ_WHEEL_DISTINFO-$(target)=$$(XZ_INSTALL-$(target))/wheel/xz-$(XZ_VERSION).dist-info -$$(XZ_DIR-$(target))/Makefile: downloads/xz-$(XZ_VERSION).tgz +$$(XZ_SRCDIR-$(target))/Makefile: downloads/xz-$(XZ_VERSION).tar.gz @echo ">>> Unpack XZ sources for $(target)" - mkdir -p $$(XZ_DIR-$(target)) - tar zxf downloads/xz-$(XZ_VERSION).tgz --strip-components 1 -C $$(XZ_DIR-$(target)) + mkdir -p $$(XZ_SRCDIR-$(target)) + tar zxf $$< --strip-components 1 -C $$(XZ_SRCDIR-$(target)) + # Patch the source to add support for new platforms + cd $$(XZ_SRCDIR-$(target)) && patch -p1 < $(PROJECT_DIR)/patch/xz-$(XZ_VERSION).patch # Configure the build - cd $$(XZ_DIR-$(target)) && \ + cd $$(XZ_SRCDIR-$(target)) && \ ./configure \ CC="$$(CC-$(target))" \ + CFLAGS="$$(CFLAGS-$(target))" \ LDFLAGS="$$(LDFLAGS-$(target))" \ - --disable-shared --enable-static \ - --host=$$(MACHINE_SIMPLE-$(target))-apple-darwin \ - --prefix="$(PROJECT_DIR)/$$(XZ_DIR-$(target))/_install" \ - 2>&1 | tee -a ../xz-$(target).config.log + --disable-shared \ + --enable-static \ + --host=$$(TARGET_TRIPLE-$(target)) \ + --prefix="$$(XZ_INSTALL-$(target))" \ + 2>&1 | tee -a ../xz-$(XZ_VERSION).config.log -$$(XZ_LIB-$(target)): $$(XZ_DIR-$(target))/Makefile +$$(XZ_LIB-$(target)): $$(XZ_SRCDIR-$(target))/Makefile @echo ">>> Build and install XZ for $(target)" - cd $$(XZ_DIR-$(target)) && \ + cd $$(XZ_SRCDIR-$(target)) && \ make install \ - 2>&1 | tee -a ../xz-$(target).build.log + 2>&1 | tee -a ../xz-$(XZ_VERSION).build.log + +$$(XZ_WHEEL-$(target)): $$(XZ_LIB-$(target)) $$(BDIST_WHEEL) + @echo ">>> Build XZ wheel for $(target)" + mkdir -p $$(XZ_WHEEL_DISTINFO-$(target)) + mkdir -p $$(XZ_INSTALL-$(target))/wheel/opt + + # Copy distributable content + cp -r $$(XZ_INSTALL-$(target))/include $$(XZ_INSTALL-$(target))/wheel/opt/include + cp -r $$(XZ_INSTALL-$(target))/lib $$(XZ_INSTALL-$(target))/wheel/opt/lib + + # Copy license files + cp $$(XZ_SRCDIR-$(target))/COPYING $$(XZ_WHEEL_DISTINFO-$(target))/LICENSE + cp $$(XZ_SRCDIR-$(target))/COPYING.* $$(XZ_WHEEL_DISTINFO-$(target)) + + # Write package metadata + echo "Metadata-Version: 1.2" >> $$(XZ_WHEEL_DISTINFO-$(target))/METADATA + echo "Name: xz" >> $$(XZ_WHEEL_DISTINFO-$(target))/METADATA + echo "Version: $(XZ_VERSION)" >> $$(XZ_WHEEL_DISTINFO-$(target))/METADATA + echo "Summary: " >> $$(XZ_WHEEL_DISTINFO-$(target))/METADATA + echo "Download-URL: " >> $$(XZ_WHEEL_DISTINFO-$(target))/METADATA + + # Write wheel metadata + echo "Wheel-Version: 1.0" >> $$(XZ_WHEEL_DISTINFO-$(target))/WHEEL + echo "Root-Is-Purelib: false" >> $$(XZ_WHEEL_DISTINFO-$(target))/WHEEL + echo "Generator: Python-Apple-support.BeeWare" >> $$(XZ_WHEEL_DISTINFO-$(target))/WHEEL + echo "Build: 1" >> $$(XZ_WHEEL_DISTINFO-$(target))/WHEEL + echo "Tag: $$(WHEEL_TAG-$(target))" >> $$(XZ_WHEEL_DISTINFO-$(target))/WHEEL + + # Pack the wheel + mkdir -p wheels/dist/xz + $(HOST_PYTHON_EXE) -m wheel pack $$(XZ_INSTALL-$(target))/wheel --dest-dir wheels/dist/xz --build-number 1 ########################################################################### # Target: OpenSSL ########################################################################### -OPENSSL_DIR-$(target)=build/$(os)/openssl-$(OPENSSL_VERSION)-$(target) -OPENSSL_SSL_LIB-$(target)=$$(OPENSSL_DIR-$(target))/_install/lib/libssl.a -OPENSSL_CRYPTO_LIB-$(target)=$$(OPENSSL_DIR-$(target))/_install/lib/libcrypto.a +OPENSSL_SRCDIR-$(target)=build/$(os)/$(target)/openssl-$(OPENSSL_VERSION) +OPENSSL_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/openssl-$(OPENSSL_VERSION) +OPENSSL_SSL_LIB-$(target)=$$(OPENSSL_INSTALL-$(target))/lib/libssl.a +OPENSSL_CRYPTO_LIB-$(target)=$$(OPENSSL_INSTALL-$(target))/lib/libcrypto.a +OPENSSL_WHEEL-$(target)=wheels/dist/openssl/openssl-$(OPENSSL_VERSION)-1-$$(WHEEL_TAG-$(target)).whl +OPENSSL_WHEEL_DISTINFO-$(target)=$$(OPENSSL_INSTALL-$(target))/wheel/openssl-$(OPENSSL_VERSION).dist-info -$$(OPENSSL_DIR-$(target))/is_configured: downloads/openssl-$(OPENSSL_VERSION).tgz +$$(OPENSSL_SRCDIR-$(target))/is_configured: downloads/openssl-$(OPENSSL_VERSION).tar.gz @echo ">>> Unpack and configure OpenSSL sources for $(target)" - mkdir -p $$(OPENSSL_DIR-$(target)) - tar zxf downloads/openssl-$(OPENSSL_VERSION).tgz --strip-components 1 -C $$(OPENSSL_DIR-$(target)) + mkdir -p $$(OPENSSL_SRCDIR-$(target)) + tar zxf $$< --strip-components 1 -C $$(OPENSSL_SRCDIR-$(target)) -ifeq ($$(findstring simulator,$$(SDK-$(target))),) - # Tweak ui_openssl.c - sed -ie "s!static volatile sig_atomic_t intr_signal;!static volatile intr_signal;!" $$(OPENSSL_DIR-$(target))/crypto/ui/ui_openssl.c +ifneq ($(os),macOS) + # Patch code to disable the use of fork as it's not available on $(os) +ifeq ($(OPENSSL_VERSION_NUMBER),1.1.1) + sed -ie 's/define HAVE_FORK 1/define HAVE_FORK 0/' $$(OPENSSL_SRCDIR-$(target))/apps/speed.c + sed -ie 's/define HAVE_FORK 1/define HAVE_FORK 0/' $$(OPENSSL_SRCDIR-$(target))/apps/ocsp.c +else + sed -ie 's/define HAVE_FORK 1/define HAVE_FORK 0/' $$(OPENSSL_SRCDIR-$(target))/apps/include/http_server.h + sed -ie 's/define HAVE_FORK 1/define HAVE_FORK 0/' $$(OPENSSL_SRCDIR-$(target))/apps/speed.c endif - -ifeq ($$(findstring iphone,$$(SDK-$(target))),) - # Patch apps/speed.c and apps/ocsp.c to not use fork() since it's not available on tvOS - sed -ie 's/define HAVE_FORK 1/define HAVE_FORK 0/' $$(OPENSSL_DIR-$(target))/apps/speed.c - sed -ie 's/define HAVE_FORK 1/define HAVE_FORK 0/' $$(OPENSSL_DIR-$(target))/apps/ocsp.c - # Patch Configure to build for tvOS or watchOS, not iOS - LC_ALL=C sed -ie 's/-D_REENTRANT:iOS/-D_REENTRANT:$(os)/' $$(OPENSSL_DIR-$(target))/Configure endif # Configure the OpenSSL build ifeq ($(os),macOS) - cd $$(OPENSSL_DIR-$(target)) && \ - CC="$$(CC-$(target))" \ + cd $$(OPENSSL_SRCDIR-$(target)) && \ + CC="$$(CC-$(target)) $$(CFLAGS-$(target))" \ ./Configure darwin64-$$(ARCH-$(target))-cc no-tests \ - --prefix="$(PROJECT_DIR)/$$(OPENSSL_DIR-$(target))/_install" \ + --prefix="$$(OPENSSL_INSTALL-$(target))" \ --openssldir=/etc/ssl \ - 2>&1 | tee -a ../openssl-$(target).config.log + 2>&1 | tee -a ../openssl-$(OPENSSL_VERSION).config.log else - cd $$(OPENSSL_DIR-$(target)) && \ - CC="$$(CC-$(target))" \ + cd $$(OPENSSL_SRCDIR-$(target)) && \ + CC="$$(CC-$(target)) $$(CFLAGS-$(target))" \ CROSS_TOP="$$(dir $$(SDK_ROOT-$(target))).." \ CROSS_SDK="$$(notdir $$(SDK_ROOT-$(target)))" \ ./Configure iphoneos-cross no-asm no-tests \ - --prefix="$(PROJECT_DIR)/$$(OPENSSL_DIR-$(target))/_install" \ + --prefix="$$(OPENSSL_INSTALL-$(target))" \ --openssldir=/etc/ssl \ - 2>&1 | tee -a ../openssl-$(target).config.log + 2>&1 | tee -a ../openssl-$(OPENSSL_VERSION).config.log endif # The OpenSSL Makefile is... interesting. Invoking `make all` or `make # install` *modifies the Makefile*. Therefore, we can't use the Makefile as # a build dependency, because building/installing dirties the target that # was used as a dependency. To compensate, create a dummy file as a marker # for whether OpenSSL has been configured, and use *that* as a reference. - date > $$(OPENSSL_DIR-$(target))/is_configured + date > $$(OPENSSL_SRCDIR-$(target))/is_configured -$$(OPENSSL_DIR-$(target))/libssl.a: $$(OPENSSL_DIR-$(target))/is_configured +$$(OPENSSL_SRCDIR-$(target))/libssl.a: $$(OPENSSL_SRCDIR-$(target))/is_configured @echo ">>> Build OpenSSL for $(target)" # OpenSSL's `all` target modifies the Makefile; # use the raw targets that make up all and it's dependencies - cd $$(OPENSSL_DIR-$(target)) && \ - CC="$$(CC-$(target))" \ + cd $$(OPENSSL_SRCDIR-$(target)) && \ + CC="$$(CC-$(target)) $$(CFLAGS-$(target))" \ CROSS_TOP="$$(dir $$(SDK_ROOT-$(target))).." \ CROSS_SDK="$$(notdir $$(SDK_ROOT-$(target)))" \ make all \ - 2>&1 | tee -a ../openssl-$(target).build.log + 2>&1 | tee -a ../openssl-$(OPENSSL_VERSION).build.log -$$(OPENSSL_SSL_LIB-$(target)): $$(OPENSSL_DIR-$(target))/libssl.a +$$(OPENSSL_SSL_LIB-$(target)): $$(OPENSSL_SRCDIR-$(target))/libssl.a @echo ">>> Install OpenSSL for $(target)" # Install just the software (not the docs) - cd $$(OPENSSL_DIR-$(target)) && \ - CC="$$(CC-$(target))" \ + cd $$(OPENSSL_SRCDIR-$(target)) && \ + CC="$$(CC-$(target)) $$(CFLAGS-$(target))" \ CROSS_TOP="$$(dir $$(SDK_ROOT-$(target))).." \ CROSS_SDK="$$(notdir $$(SDK_ROOT-$(target)))" \ make install_sw \ - 2>&1 | tee -a ../openssl-$(target).install.log + 2>&1 | tee -a ../openssl-$(OPENSSL_VERSION).install.log + +$$(OPENSSL_WHEEL-$(target)): $$(OPENSSL_LIB-$(target)) $$(BDIST_WHEEL) + @echo ">>> Build OpenSSL wheel for $(target)" + mkdir -p $$(OPENSSL_WHEEL_DISTINFO-$(target)) + mkdir -p $$(OPENSSL_INSTALL-$(target))/wheel/opt + + # Copy distributable content + cp -r $$(OPENSSL_INSTALL-$(target))/include $$(OPENSSL_INSTALL-$(target))/wheel/opt/include + cp -r $$(OPENSSL_INSTALL-$(target))/lib $$(OPENSSL_INSTALL-$(target))/wheel/opt/lib + + # Remove dynamic library content + rm -f $$(OPENSSL_INSTALL-$(target))/wheel/opt/lib/*.dylib + + # Copy LICENSE file + # OpenSSL 1.1.1 uses LICENSE; OpenSSL 3 uses LICENSE.txt + if [ -f "$$(OPENSSL_SRCDIR-$(target))/LICENSE.txt" ]; then \ + cp $$(OPENSSL_SRCDIR-$(target))/LICENSE.txt $$(OPENSSL_WHEEL_DISTINFO-$(target))/LICENSE; \ + else \ + cp $$(OPENSSL_SRCDIR-$(target))/LICENSE $$(OPENSSL_WHEEL_DISTINFO-$(target))/LICENSE; \ + fi + + # Write package metadata + echo "Metadata-Version: 1.2" >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/METADATA + echo "Name: openssl" >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/METADATA + echo "Version: $(OPENSSL_VERSION)" >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/METADATA + echo "Summary: " >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/METADATA + echo "Download-URL: " >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/METADATA + + # Write wheel metadata + echo "Wheel-Version: 1.0" >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/WHEEL + echo "Root-Is-Purelib: false" >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/WHEEL + echo "Generator: Python-Apple-support.BeeWare" >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/WHEEL + echo "Build: 1" >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/WHEEL + echo "Tag: $$(WHEEL_TAG-$(target))" >> $$(OPENSSL_WHEEL_DISTINFO-$(target))/WHEEL + + # Pack the wheel + mkdir -p wheels/dist/openssl + $(HOST_PYTHON_EXE) -m wheel pack $$(OPENSSL_INSTALL-$(target))/wheel --dest-dir wheels/dist/openssl --build-number 1 ########################################################################### # Target: libFFI ########################################################################### # macOS builds use the system libFFI, so there's no need to do -# a per-target build on macOS +# a per-target build on macOS. +# The configure step is performed as part of the OS-level build. ifneq ($(os),macOS) -LIBFFI_DIR-$(os)=build/$(os)/libffi-$(LIBFFI_VERSION) -LIBFFI_DIR-$(target)=$$(LIBFFI_DIR-$(os))/build_$$(SDK-$(target))-$$(ARCH-$(target)) -LIBFFI_LIB-$(target)=$$(LIBFFI_DIR-$(target))/.libs/libffi.a +LIBFFI_SRCDIR-$(os)=build/$(os)/libffi-$(LIBFFI_VERSION) +LIBFFI_SRCDIR-$(target)=$$(LIBFFI_SRCDIR-$(os))/build_$$(SDK-$(target))-$$(ARCH-$(target)) +LIBFFI_LIB-$(target)=$$(LIBFFI_SRCDIR-$(target))/.libs/libffi.a +LIBFFI_WHEEL-$(target)=wheels/dist/libffi/libffi-$(LIBFFI_VERSION)-1-$$(WHEEL_TAG-$(target)).whl +LIBFFI_WHEEL_DISTINFO-$(target)=$$(LIBFFI_SRCDIR-$(target))/wheel/libffi-$(LIBFFI_VERSION).dist-info -$$(LIBFFI_LIB-$(target)): $$(LIBFFI_DIR-$(os))/darwin_common/include/ffi.h +$$(LIBFFI_LIB-$(target)): $$(LIBFFI_SRCDIR-$(os))/darwin_common/include/ffi.h @echo ">>> Build libFFI for $(target)" - cd $$(LIBFFI_DIR-$(target)) && \ + cd $$(LIBFFI_SRCDIR-$(target)) && \ make \ - 2>&1 | tee -a ../../libffi-$(target).build.log + 2>&1 | tee -a ../../libffi-$(LIBFFI_VERSION).build.log + +$$(LIBFFI_WHEEL-$(target)): $$(LIBFFI_LIB-$(target)) $$(BDIST_WHEEL) + @echo ">>> Build libFFI wheel for $(target)" + mkdir -p $$(LIBFFI_WHEEL_DISTINFO-$(target)) + mkdir -p $$(LIBFFI_SRCDIR-$(target))/wheel/opt + + # Copy distributable content + cp -r $$(LIBFFI_SRCDIR-$(target))/include $$(LIBFFI_SRCDIR-$(target))/wheel/opt/include + cp -r $$(LIBFFI_SRCDIR-$(target))/.libs $$(LIBFFI_SRCDIR-$(target))/wheel/opt/lib + + # Remove dynamic library content + rm -f $$(LIBFFI_SRCDIR-$(target))/wheel/opt/lib/*.dylib + + # Copy LICENSE file + cp $$(LIBFFI_SRCDIR-$(os))/LICENSE $$(LIBFFI_WHEEL_DISTINFO-$(target)) + + # Write package metadata + echo "Metadata-Version: 1.2" >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/METADATA + echo "Name: libffi" >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/METADATA + echo "Version: $(LIBFFI_VERSION)" >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/METADATA + echo "Summary: " >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/METADATA + echo "Download-URL: " >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/METADATA + + # Write wheel metadata + echo "Wheel-Version: 1.0" >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/WHEEL + echo "Root-Is-Purelib: false" >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/WHEEL + echo "Generator: Python-Apple-support.BeeWare" >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/WHEEL + echo "Build: 1" >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/WHEEL + echo "Tag: $$(WHEEL_TAG-$(target))" >> $$(LIBFFI_WHEEL_DISTINFO-$(target))/WHEEL + + # Pack the wheel + mkdir -p wheels/dist/libffi + $(HOST_PYTHON_EXE) -m wheel pack $$(LIBFFI_SRCDIR-$(target))/wheel --dest-dir wheels/dist/libffi --build-number 1 endif @@ -392,72 +526,64 @@ endif # Target: Python ########################################################################### -# macOS builds are compiled as a single universal2 build. As a result, -# the macOS Python build is configured in the `build` macro, rather than the +# macOS builds are compiled as a single universal2 build. +# The macOS Python build is configured in the `build-sdk` macro, rather than the # `build-target` macro. -ifeq ($(os),macOS) - -# These constants will be the same for all macOS targets -PYTHON_DIR-$(target)=build/$(os)/Python-$(PYTHON_VERSION)-$(os) -PYTHON_LIB-$(target)=$$(PYTHON_DIR-$(target))/_install/lib/libpython$(PYTHON_VER).a -# PYCONFIG_H-$(target) not defined, as there's no header shim needed - -else +ifneq ($(os),macOS) -PYTHON_DIR-$(target)=build/$(os)/Python-$(PYTHON_VERSION)-$(target) -PYTHON_LIB-$(target)=$$(PYTHON_DIR-$(target))/_install/lib/libpython$(PYTHON_VER).a -PYCONFIG_H-$(target)=build/$(os)/python/$$(SDK-$(target))/include/python$(PYTHON_VER)/pyconfig-$$(ARCH-$(target)).h - -$$(PYTHON_DIR-$(target))/Makefile: \ - $$(BZIP2_XCFRAMEWORK-$(os)) \ - $$(XZ_XCFRAMEWORK-$(os)) \ - $$(OPENSSL_XCFRAMEWORK-$(os)) \ - $$(LIBFFI_XCFRAMEWORK-$(os)) \ - $$(PYTHON_XCFRAMEWORK-macOS) \ - downloads/Python-$(PYTHON_VERSION).tgz +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_SRCDIR-$(target))/Makefile: \ + downloads/Python-$(PYTHON_VERSION).tar.gz \ + $$(BZIP2_FATLIB-$$(SDK-$(target))) \ + $$(XZ_FATLIB-$$(SDK-$(target))) \ + $$(OPENSSL_FATINCLUDE-$$(SDK-$(target))) $$(OPENSSL_SSL_FATLIB-$$(SDK-$(target))) $$(OPENSSL_CRYPTO_FATLIB-$$(SDK-$(target))) \ + $$(LIBFFI_FATLIB-$$(SDK-$(target))) \ + $$(PYTHON_XCFRAMEWORK-macOS) @echo ">>> Unpack and configure Python for $(target)" - mkdir -p $$(PYTHON_DIR-$(target)) - tar zxf downloads/Python-$(PYTHON_VERSION).tgz --strip-components 1 -C $$(PYTHON_DIR-$(target)) + mkdir -p $$(PYTHON_SRCDIR-$(target)) + tar zxf downloads/Python-$(PYTHON_VERSION).tar.gz --strip-components 1 -C $$(PYTHON_SRCDIR-$(target)) # Apply target Python patches - cd $$(PYTHON_DIR-$(target)) && patch -p1 < $(PROJECT_DIR)/patch/Python/Python.patch - # Generate the embedded module configuration - cat $(PROJECT_DIR)/patch/Python/Setup.embedded \ - $(PROJECT_DIR)/patch/Python/Setup.$(os) \ - $(PROJECT_DIR)/patch/Python/Setup.$(target) | \ - sed -e "s/{{slice}}/$$(SLICE-$$(SDK-$(target)))/g" \ - > $$(PYTHON_DIR-$(target))/Modules/Setup.local + cd $$(PYTHON_SRCDIR-$(target)) && patch -p1 < $(PROJECT_DIR)/patch/Python/Python.patch # Configure target Python - cd $$(PYTHON_DIR-$(target)) && \ - PATH="$(PROJECT_DIR)/$(PYTHON_DIR-macOS)/_install/bin:$(PATH)" \ + cd $$(PYTHON_SRCDIR-$(target)) && \ + PATH="$$(PYTHON_INSTALL-macosx)/bin:$(PATH)" \ ./configure \ - CC="$$(CC-$(target))" LD="$$(CC-$(target))" \ - --host=$$(MACHINE_DETAILED-$(target))-apple-$(shell echo $(os) | tr '[:upper:]' '[:lower:]') \ + AR="$$(AR-$(target))" \ + CC="$$(CC-$(target))" \ + CXX="$$(CXX-$(target))" \ + CFLAGS="$$(CFLAGS-$(target)) -I$$(BZIP2_MERGE-$$(SDK-$(target)))/include -I$$(XZ_MERGE-$$(SDK-$(target)))/include" \ + LDFLAGS="$$(LDFLAGS-$(target)) -L$$(BZIP2_MERGE-$$(SDK-$(target)))/lib -L$$(XZ_MERGE-$$(SDK-$(target)))/lib" \ + LIBFFI_INCLUDEDIR="$$(LIBFFI_MERGE-$$(SDK-$(target)))/include" \ + LIBFFI_LIBDIR="$$(LIBFFI_MERGE-$$(SDK-$(target)))/lib" \ + LIBFFI_LIB="ffi" \ + --host=$$(TARGET_TRIPLE-$(target)) \ --build=$(HOST_ARCH)-apple-darwin \ - --prefix="$(PROJECT_DIR)/$$(PYTHON_DIR-$(target))/_install" \ - --without-doc-strings --enable-ipv6 --without-ensurepip \ - --with-openssl=../openssl/$$(SDK-$(target)) \ - ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no \ + --prefix="$$(PYTHON_INSTALL-$(target))" \ + --enable-ipv6 \ + --with-openssl="$$(OPENSSL_MERGE-$$(SDK-$(target)))" \ + --without-doc-strings \ + --without-ensurepip \ + ac_cv_file__dev_ptmx=no \ + ac_cv_file__dev_ptc=no \ $$(PYTHON_CONFIGURE-$(os)) \ - 2>&1 | tee -a ../python-$(target).config.log + 2>&1 | tee -a ../python-$(PYTHON_VERSION).config.log -$$(PYTHON_DIR-$(target))/python.exe: $$(PYTHON_DIR-$(target))/Makefile +$$(PYTHON_SRCDIR-$(target))/python.exe: $$(PYTHON_SRCDIR-$(target))/Makefile @echo ">>> Build Python for $(target)" - cd $$(PYTHON_DIR-$(target)) && \ - PATH="$(PROJECT_DIR)/$(PYTHON_DIR-macOS)/_install/bin:$(PATH)" \ - make all \ - 2>&1 | tee -a ../python-$(target).build.log + cd $$(PYTHON_SRCDIR-$(target)) && \ + PATH="$$(PYTHON_INSTALL-macosx)/bin:$(PATH)" \ + make all \ + 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log -$$(PYTHON_LIB-$(target)): $$(PYTHON_DIR-$(target))/python.exe +$$(PYTHON_LIB-$(target)): $$(PYTHON_SRCDIR-$(target))/python.exe @echo ">>> Install Python for $(target)" - cd $$(PYTHON_DIR-$(target)) && \ - PATH="$(PROJECT_DIR)/$(PYTHON_DIR-macOS)/_install/bin:$(PATH)" \ - make install \ - 2>&1 | tee -a ../python-$(target).install.log - -$$(PYCONFIG_H-$(target)): $$(PYTHON_LIB-$(target)) - @echo ">>> Install pyconfig headers for $(target)" - cp $(PROJECT_DIR)/patch/Python/pyconfig-$(os).h build/$(os)/python/$$(SDK-$(target))/include/python$(PYTHON_VER)/pyconfig.h - cp $$(PYTHON_DIR-$(target))/_install/include/python$(PYTHON_VER)/pyconfig.h $$(PYCONFIG_H-$(target)) + cd $$(PYTHON_SRCDIR-$(target)) && \ + PATH="$$(PYTHON_INSTALL-macosx)/bin:$(PATH)" \ + make install \ + 2>&1 | tee -a ../python-$(PYTHON_VERSION).install.log endif @@ -467,23 +593,36 @@ endif vars-$(target): @echo ">>> Environment variables for $(target)" - @echo "ARCH-$(target): $$(ARCH-$(target))" - @echo "MACHINE_DETAILED-$(target): $$(MACHINE_DETAILED-$(target))" @echo "SDK-$(target): $$(SDK-$(target))" + @echo "ARCH-$(target): $$(ARCH-$(target))" + @echo "TARGET_TRIPLE-$(target): $$(TARGET_TRIPLE-$(target))" @echo "SDK_ROOT-$(target): $$(SDK_ROOT-$(target))" @echo "CC-$(target): $$(CC-$(target))" - @echo "BZIP2_DIR-$(target): $$(BZIP2_DIR-$(target))" + @echo "CFLAGS-$(target): $$(CFLAGS-$(target))" + @echo "LDFLAGS-$(target): $$(LDFLAGS-$(target))" + @echo "BZIP2_SRCDIR-$(target): $$(BZIP2_SRCDIR-$(target))" + @echo "BZIP2_INSTALL-$(target): $$(BZIP2_INSTALL-$(target))" @echo "BZIP2_LIB-$(target): $$(BZIP2_LIB-$(target))" - @echo "XZ_DIR-$(target): $$(XZ_DIR-$(target))" + @echo "BZIP2_WHEEL-$(target): $$(BZIP2_WHEEL-$(target))" + @echo "BZIP2_WHEEL_DISTINFO-$(target): $$(BZIP2_WHEEL_DISTINFO-$(target))" + @echo "XZ_SRCDIR-$(target): $$(XZ_SRCDIR-$(target))" + @echo "XZ_INSTALL-$(target): $$(XZ_INSTALL-$(target))" @echo "XZ_LIB-$(target): $$(XZ_LIB-$(target))" - @echo "OPENSSL_DIR-$(target): $$(OPENSSL_DIR-$(target))" + @echo "XZ_WHEEL-$(target): $$(XZ_WHEEL-$(target))" + @echo "XZ_WHEEL_DISTINFO-$(target): $$(XZ_WHEEL_DISTINFO-$(target))" + @echo "OPENSSL_SRCDIR-$(target): $$(OPENSSL_SRCDIR-$(target))" + @echo "OPENSSL_INSTALL-$(target): $$(OPENSSL_INSTALL-$(target))" @echo "OPENSSL_SSL_LIB-$(target): $$(OPENSSL_SSL_LIB-$(target))" @echo "OPENSSL_CRYPTO_LIB-$(target): $$(OPENSSL_CRYPTO_LIB-$(target))" - @echo "LIBFFI_DIR-$(target): $$(LIBFFI_DIR-$(target))" + @echo "OPENSSL_WHEEL-$(target): $$(OPENSSL_WHEEL-$(target))" + @echo "OPENSSL_WHEEL_DISTINFO-$(target): $$(OPENSSL_WHEEL_DISTINFO-$(target))" + @echo "LIBFFI_SRCDIR-$(target): $$(LIBFFI_SRCDIR-$(target))" @echo "LIBFFI_LIB-$(target): $$(LIBFFI_LIB-$(target))" - @echo "PYTHON_DIR-$(target): $$(PYTHON_DIR-$(target))" + @echo "LIBFFI_WHEEL-$(target): $$(LIBFFI_WHEEL-$(target))" + @echo "LIBFFI_WHEEL_DISTINFO-$(target): $$(LIBFFI_WHEEL_DISTINFO-$(target))" + @echo "PYTHON_SRCDIR-$(target): $$(PYTHON_SRCDIR-$(target))" + @echo "PYTHON_INSTALL-$(target): $$(PYTHON_INSTALL-$(target))" @echo "PYTHON_LIB-$(target): $$(PYTHON_LIB-$(target))" - @echo "PYCONFIG_H-$(target): $$(PYCONFIG_H-$(target))" @echo endef # build-target @@ -501,100 +640,225 @@ define build-sdk sdk=$1 os=$2 +OS_LOWER-$(sdk)=$(shell echo $(os) | tr '[:upper:]' '[:lower:]') + SDK_TARGETS-$(sdk)=$$(filter $(sdk).%,$$(TARGETS-$(os))) SDK_ARCHES-$(sdk)=$$(sort $$(subst .,,$$(suffix $$(SDK_TARGETS-$(sdk))))) +ifeq ($$(findstring simulator,$(sdk)),) +SDK_SLICE-$(sdk)=$$(OS_LOWER-$(sdk))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g") +else +SDK_SLICE-$(sdk)=$$(OS_LOWER-$(sdk))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g")-simulator +endif + +CC-$(sdk)=xcrun --sdk $(sdk) clang +CFLAGS-$(sdk)=\ + $$(CFLAGS-$(os)) +LDFLAGS-$(sdk)=\ + $$(CFLAGS-$(os)) + +# Predeclare SDK constants that are used by the build-target macro + +BZIP2_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/$(sdk)/bzip2-$(BZIP2_VERSION) +BZIP2_FATLIB-$(sdk)=$$(BZIP2_MERGE-$(sdk))/lib/libbz2.a + +XZ_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/$(sdk)/xz-$(XZ_VERSION) +XZ_FATLIB-$(sdk)=$$(XZ_MERGE-$(sdk))/lib/liblzma.a + +OPENSSL_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/$(sdk)/openssl-$(OPENSSL_VERSION) +OPENSSL_FATINCLUDE-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/include +OPENSSL_SSL_FATLIB-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/lib/libssl.a +OPENSSL_CRYPTO_FATLIB-$(sdk)=$$(OPENSSL_MERGE-$(sdk))/lib/libcrypto.a + +LIBFFI_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/$(sdk)/libffi-$(LIBFFI_VERSION) +LIBFFI_FATLIB-$(sdk)=$$(LIBFFI_MERGE-$(sdk))/lib/libffi.a + +PYTHON_MERGE-$(sdk)=$(PROJECT_DIR)/merge/$(os)/$(sdk)/python-$(PYTHON_VERSION) +PYTHON_FATLIB-$(sdk)=$$(PYTHON_MERGE-$(sdk))/libPython$(PYTHON_VER).a +PYTHON_FATINCLUDE-$(sdk)=$$(PYTHON_MERGE-$(sdk))/Headers +PYTHON_FATSTDLIB-$(sdk)=$$(PYTHON_MERGE-$(sdk))/python-stdlib + +# Expand the build-target macro for target on this OS +$$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(eval $$(call build-target,$$(target),$(os)))) + ########################################################################### # SDK: BZip2 ########################################################################### -BZIP2_FATLIB-$(sdk)=build/$(os)/bzip2/$(sdk)/lib/libbzip2.a - $$(BZIP2_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(BZIP2_LIB-$$(target))) @echo ">>> Build BZip2 fat library for $(sdk)" - mkdir -p build/$(os)/bzip2/$(sdk)/lib - xcrun --sdk $(sdk) libtool -no_warning_for_no_symbols -static -o $$@ $$^ \ - 2>&1 | tee -a build/$(os)/bzip2-$(sdk).libtool.log - # Copy headers from the first target associated with the SDK - cp -r $$(BZIP2_DIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/_install/include build/$(os)/bzip2/$(sdk) + mkdir -p $$(BZIP2_MERGE-$(sdk))/lib + lipo -create -output $$@ $$^ \ + 2>&1 | tee -a merge/$(os)/$(sdk)/bzip2-$(BZIP2_VERSION).lipo.log + # Copy headers from the first target associated with the $(sdk) SDK + cp -r $$(BZIP2_INSTALL-$$(firstword $$(SDK_TARGETS-$(sdk))))/include $$(BZIP2_MERGE-$(sdk)) ########################################################################### # SDK: XZ (LZMA) ########################################################################### -XZ_FATLIB-$(sdk)=build/$(os)/xz/$(sdk)/lib/libxz.a - $$(XZ_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(XZ_LIB-$$(target))) @echo ">>> Build XZ fat library for $(sdk)" - mkdir -p build/$(os)/xz/$(sdk)/lib - xcrun --sdk $(sdk) libtool -no_warning_for_no_symbols -static -o $$@ $$^ \ - 2>&1 | tee -a build/$(os)/xz-$(sdk).libtool.log - # Copy headers from the first target associated with the SDK - cp -r $$(XZ_DIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/_install/include build/$(os)/xz/$(sdk) + mkdir -p $$(XZ_MERGE-$(sdk))/lib + lipo -create -output $$@ $$^ \ + 2>&1 | tee -a merge/$(os)/$(sdk)/xz-$(XZ_VERSION).lipo.log + # Copy headers from the first target associated with the $(sdk) SDK + cp -r $$(XZ_INSTALL-$$(firstword $$(SDK_TARGETS-$(sdk))))/include $$(XZ_MERGE-$(sdk)) ########################################################################### # SDK: OpenSSL ########################################################################### -OPENSSL_FATLIB-$(sdk)=build/$(os)/openssl/$(sdk)/lib/libOpenSSL.a - -$$(OPENSSL_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_SSL_LIB-$$(target))) - @echo ">>> Build OpenSSL fat library for $(sdk)" - mkdir -p build/$(os)/openssl/$(sdk)/lib - xcrun --sdk $(sdk) libtool -no_warning_for_no_symbols -static -o $$@ \ - $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_SSL_LIB-$$(target)) $$(OPENSSL_CRYPTO_LIB-$$(target))) \ - 2>&1 | tee -a build/$(os)/openssl-$(sdk).libtool.log - # Copy headers from the first target associated with the SDK - cp -r $$(OPENSSL_DIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/_install/include build/$(os)/openssl/$(sdk) +$$(OPENSSL_FATINCLUDE-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_SSL_LIB-$$(target))) + @echo ">>> Copy OpenSSL headers from the first target associated with the SDK" + mkdir -p $$(OPENSSL_MERGE-$(sdk)) + cp -r $$(OPENSSL_INSTALL-$$(firstword $$(SDK_TARGETS-$(sdk))))/include $$(OPENSSL_MERGE-$(sdk)) + +$$(OPENSSL_SSL_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_SSL_LIB-$$(target))) + @echo ">>> Build OpenSSL ssl fat library for $(sdk)" + mkdir -p $$(OPENSSL_MERGE-$(sdk))/lib + lipo -create -output $$@ \ + $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_SSL_LIB-$$(target))) \ + 2>&1 | tee -a merge/$(os)/$(sdk)/openssl-$(OPENSSL_VERSION).ssl.lipo.log + +$$(OPENSSL_CRYPTO_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_CRYPTO_LIB-$$(target))) + @echo ">>> Build OpenSSL crypto fat library for $(sdk)" + mkdir -p $$(OPENSSL_MERGE-$(sdk))/lib + lipo -create -output $$@ \ + $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(OPENSSL_CRYPTO_LIB-$$(target))) \ + 2>&1 | tee -a merge/$(os)/$(sdk)/openssl-$(OPENSSL_VERSION).crypto.lipo.log ########################################################################### # SDK: libFFI ########################################################################### -LIBFFI_FATLIB-$(sdk)=$$(LIBFFI_DIR-$(os))/_install/$(sdk)/libFFI.a - $$(LIBFFI_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(LIBFFI_LIB-$$(target))) @echo ">>> Build libFFI fat library for $(sdk)" - mkdir -p $$(LIBFFI_DIR-$(os))/_install/$(sdk) - xcrun --sdk $(sdk) libtool -no_warning_for_no_symbols -static -o $$@ $$^ \ - 2>&1 | tee -a build/$(os)/libffi-$(sdk).libtool.log - # Copy headers from the first target associated with the SDK - cp -f -r $$(LIBFFI_DIR-$(os))/darwin_common/include \ - $$(LIBFFI_DIR-$(os))/_install/$(sdk) - cp -f -r $$(LIBFFI_DIR-$(os))/darwin_$(shell echo $(os) | tr '[:upper:]' '[:lower:]')/include/* \ - $$(LIBFFI_DIR-$(os))/_install/$(sdk)/include + mkdir -p $$(LIBFFI_MERGE-$(sdk))/lib + lipo -create -output $$@ $$^ \ + 2>&1 | tee -a merge/$(os)/$(sdk)/libffi-$(LIBFFI_VERSION).lipo.log + # Copy headers from the first target associated with the $(sdk) SDK + cp -f -r $$(LIBFFI_SRCDIR-$(os))/darwin_common/include \ + $$(LIBFFI_MERGE-$(sdk)) + cp -f -r $$(LIBFFI_SRCDIR-$(os))/darwin_$$(OS_LOWER-$(sdk))/include/* \ + $$(LIBFFI_MERGE-$(sdk))/include ########################################################################### # SDK: Python ########################################################################### -PYTHON_DIR-$(sdk)=build/$(os)/python/$(sdk) -PYTHON_FATLIB-$(sdk)=$$(PYTHON_DIR-$(sdk))/lib/libPython.a - +# 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) -# There's a single OS-level build for macOS; the fat library is a direct copy of -# OS build, and the headers are the unmodifed headers produced by the OS build. -$$(PYTHON_FATLIB-$(sdk)): $$(PYTHON_LIB-$$(firstword $$(SDK_TARGETS-$(sdk)))) +PYTHON_SRCDIR-$(sdk)=build/$(os)/$(sdk)/python-$(PYTHON_VERSION) +PYTHON_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/python-$(PYTHON_VERSION) +PYTHON_LIB-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/lib/libpython$(PYTHON_VER).a + +$$(PYTHON_SRCDIR-$(sdk))/Makefile: \ + $$(BZIP2_FATLIB-$$(sdk)) \ + $$(XZ_FATLIB-$$(sdk)) \ + $$(OPENSSL_FATINCLUDE-$$(sdk)) $$(OPENSSL_SSL_FATLIB-$$(sdk)) $$(OPENSSL_CRYPTO_FATLIB-$$(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 + # Configure target Python + cd $$(PYTHON_SRCDIR-$(sdk)) && \ + ./configure \ + CC="$$(CC-$(sdk))" \ + CFLAGS="$$(CFLAGS-$(sdk)) -I$$(BZIP2_MERGE-$(sdk))/include -I$$(XZ_MERGE-$(sdk))/include" \ + LDFLAGS="$$(LDFLAGS-$(sdk)) -L$$(XZ_MERGE-$(sdk))/lib -L$$(BZIP2_MERGE-$(sdk))/lib" \ + --prefix="$$(PYTHON_INSTALL-$(sdk))" \ + --enable-ipv6 \ + --enable-universalsdk \ + --with-openssl="$$(OPENSSL_MERGE-$(sdk))" \ + --with-universal-archs=universal2 \ + --without-doc-strings \ + --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)) && \ + make all \ + 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log + +$(HOST_PYTHON_EXE) $$(PYTHON_LIB-$(sdk)): $$(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 + +$$(PYTHON_FATLIB-$(sdk)): $$(PYTHON_LIB-$(sdk)) + @echo ">>> Build Python fat library for $(sdk)" + mkdir -p $$(dir $$(PYTHON_FATLIB-$(sdk))) + # The macosx static library is already fat; copy it as-is + cp $$(PYTHON_LIB-$(sdk)) $$(PYTHON_FATLIB-$(sdk)) + +$$(PYTHON_FATINCLUDE-$(sdk)): $$(PYTHON_LIB-$(sdk)) @echo ">>> Build Python fat library for $(sdk)" - # Copy the OS-level library - mkdir -p build/$(os)/python/$(sdk)/lib - cp $$(PYTHON_LIB-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_FATLIB-$(sdk)) - # Copy headers from the OS-level build - cp -r $$(PYTHON_DIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/_install/include build/$(os)/python/$(sdk) + # The macosx headers are already fat; copy as-is + cp -r $$(PYTHON_INSTALL-$(sdk))/include/python$(PYTHON_VER) $$(PYTHON_FATINCLUDE-$(sdk)) + +$$(PYTHON_FATSTDLIB-$(sdk)): $$(PYTHON_LIB-$(sdk)) + @echo ">>> Build Python stdlib library for $(sdk)" + # The macosx stdlib is already fat; copy it as-is + cp -r $$(PYTHON_INSTALL-$(sdk))/lib/python$(PYTHON_VER) $$(PYTHON_FATSTDLIB-$(sdk)) else +# 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 +# * Merging fat versions of the standard library lib-dynload folder + $$(PYTHON_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_LIB-$$(target))) - @echo ">>> Build Python fat library for $(sdk)" - mkdir -p build/$(os)/python/$(sdk)/lib - xcrun --sdk $(sdk) libtool -no_warning_for_no_symbols -static -o $$@ $$^ \ - 2>&1 | tee -a build/$(os)/python-$(sdk).libtool.log - # Copy headers from the first target associated with the SDK - cp -r $$(PYTHON_DIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/_install/include build/$(os)/python/$(sdk) + @echo ">>> Build Python fat library for the $(sdk) SDK" + mkdir -p $$(dir $$(PYTHON_FATLIB-$(sdk))) + lipo -create -output $$@ $$^ \ + 2>&1 | tee -a merge/$(os)/$(sdk)/python-$(PYTHON_VERSION).lipo.log + +$$(PYTHON_FATINCLUDE-$(sdk)): $$(PYTHON_LIB-$(sdk)) + @echo ">>> Build Python fat headers for the $(sdk) SDK" + # Copy headers as-is from the first target in the $(sdk) SDK + cp -r $$(PYTHON_INSTALL-$$(firstword $$(SDK_TARGETS-$(sdk))))/include/python$(PYTHON_VER) $$(PYTHON_FATINCLUDE-$(sdk)) + # Copy the cross-target header from the patch folder + cp $(PROJECT_DIR)/patch/Python/pyconfig-$(os).h $$(PYTHON_FATINCLUDE-$(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_FATINCLUDE-$(sdk))/pyconfig-$$(ARCH-$$(target)).h; ) + +$$(PYTHON_FATSTDLIB-$(sdk)): $$(PYTHON_FATLIB-$(sdk)) + @echo ">>> Build Python stdlib for the $(sdk) SDK" + mkdir -p $$(PYTHON_FATSTDLIB-$(sdk)) + # Copy stdlib from the first target associated with the $(sdk) SDK + cp -r $$(PYTHON_INSTALL-$$(firstword $$(SDK_TARGETS-$(sdk))))/lib/python$(PYTHON_VER)/ $$(PYTHON_FATSTDLIB-$(sdk)) + + # Delete the single-SDK parts of the standard library + rm -rf \ + $$(PYTHON_FATSTDLIB-$(sdk))/_sysconfigdata__*.py \ + $$(PYTHON_FATSTDLIB-$(sdk))/config-* \ + $$(PYTHON_FATSTDLIB-$(sdk))/lib-dynload/* + + # Copy the cross-target _sysconfigdata module from the patch folder + cp $(PROJECT_DIR)/patch/Python/_sysconfigdata__$$(OS_LOWER-$(sdk))_$(sdk).py $$(PYTHON_FATSTDLIB-$(sdk)) + + # 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__$$(OS_LOWER-$(sdk))_$(sdk).py $$(PYTHON_FATSTDLIB-$(sdk))/_sysconfigdata__$$(OS_LOWER-$(sdk))_$(sdk)_$$(ARCH-$$(target)).py; ) + + # 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) $$(PYTHON_FATSTDLIB-$(sdk))/config-$(PYTHON_VER)-$$(target); ) + + # 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_FATSTDLIB-$(sdk))/lib-dynload/$$(notdir $$(module)) $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_INSTALL-$$(target))/lib/python$(PYTHON_VER)/lib-dynload/$$(notdir $$(module))); ) endif + ########################################################################### # SDK: Debug ########################################################################### @@ -603,12 +867,27 @@ vars-$(sdk): @echo ">>> Environment variables for $(sdk)" @echo "SDK_TARGETS-$(sdk): $$(SDK_TARGETS-$(sdk))" @echo "SDK_ARCHES-$(sdk): $$(SDK_ARCHES-$(sdk))" + @echo "SDK_SLICE-$(sdk): $$(SDK_SLICE-$(sdk))" + @echo "CC-$(sdk): $$(CC-$(sdk))" + @echo "CFLAGS-$(sdk): $$(CFLAGS-$(sdk))" + @echo "LDFLAGS-$(sdk): $$(LDFLAGS-$(sdk))" + @echo "BZIP2_MERGE-$(sdk): $$(BZIP2_MERGE-$(sdk))" @echo "BZIP2_FATLIB-$(sdk): $$(BZIP2_FATLIB-$(sdk))" + @echo "XZ_MERGE-$(sdk): $$(XZ_MERGE-$(sdk))" @echo "XZ_FATLIB-$(sdk): $$(XZ_FATLIB-$(sdk))" - @echo "OPENSSL_FATLIB-$(sdk): $$(OPENSSL_FATLIB-$(sdk))" + @echo "OPENSSL_MERGE-$(sdk): $$(OPENSSL_MERGE-$(sdk))" + @echo "OPENSSL_FATINCLUDE-$(sdk): $$(OPENSSL_FATINCLUDE-$(sdk))" + @echo "OPENSSL_SSL_FATLIB-$(sdk): $$(OPENSSL_SSL_FATLIB-$(sdk))" + @echo "OPENSSL_CRYPTO_FATLIB-$(sdk): $$(OPENSSL_CRYPTO_FATLIB-$(sdk))" + @echo "LIBFFI_MERGE-$(sdk): $$(LIBFFI_MERGE-$(sdk))" @echo "LIBFFI_FATLIB-$(sdk): $$(LIBFFI_FATLIB-$(sdk))" - @echo "PYTHON_DIR-$(sdk): $$(PYTHON_DIR-$(sdk))" + @echo "PYTHON_MERGE-$(sdk): $$(PYTHON_MERGE-$(sdk))" @echo "PYTHON_FATLIB-$(sdk): $$(PYTHON_FATLIB-$(sdk))" + @echo "PYTHON_FATINCLUDE-$(sdk): $$(PYTHON_FATINCLUDE-$(sdk))" + @echo "PYTHON_FATSTDLIB-$(sdk): $$(PYTHON_FATSTDLIB-$(sdk))" + @echo "PYTHON_SRCDIR-$(sdk): $$(PYTHON_SRCDIR-$(sdk))" + @echo "PYTHON_INSTALL-$(sdk): $$(PYTHON_INSTALL-$(sdk))" + @echo "PYTHON_LIB-$(sdk): $$(PYTHON_LIB-$(sdk))" @echo endef # build-sdk @@ -628,78 +907,83 @@ os=$1 # Build: Macro Expansions ########################################################################### -# Expand the build-target macro for target on this OS -$$(foreach target,$$(TARGETS-$(os)),$$(eval $$(call build-target,$$(target),$(os)))) +SDKS-$(os)=$$(sort $$(basename $$(TARGETS-$(os)))) + +# Predeclare the Python XCFramework files so they can be referenced in SDK targets +PYTHON_XCFRAMEWORK-$(os)=support/$(os)/Python.xcframework +PYTHON_STDLIB-$(os)=support/$(os)/python-stdlib # Expand the build-sdk macro for all the sdks on this OS (e.g., iphoneos, iphonesimulator) -SDKS-$(os)=$$(sort $$(basename $$(TARGETS-$(os)))) $$(foreach sdk,$$(SDKS-$(os)),$$(eval $$(call build-sdk,$$(sdk),$(os)))) ########################################################################### # Build: BZip2 ########################################################################### -BZIP2_XCFRAMEWORK-$(os)=build/$(os)/Support/BZip2.xcframework - -$$(BZIP2_XCFRAMEWORK-$(os)): $$(foreach sdk,$$(SDKS-$(os)),$$(BZIP2_FATLIB-$$(sdk))) - @echo ">>> Create BZip2.XCFramework on $(os)" - mkdir -p $$(BZIP2_XCFRAMEWORK-$(os)) - xcodebuild -create-xcframework \ - -output $$@ $$(foreach sdk,$$(SDKS-$(os)),-library $$(BZIP2_FATLIB-$$(sdk)) -headers build/$(os)/bzip2/$$(sdk)/include) \ - 2>&1 | tee -a build/$(os)/bzip2-$(os).xcframework.log - -BZip2-$(os): $$(BZIP2_XCFRAMEWORK-$(os)) +BZip2-$(os): $$(foreach sdk,$$(SDKS-$(os)),$$(BZIP2_FATLIB-$$(sdk))) +BZip2-wheels-$(os): $$(foreach target,$$(TARGETS-$(os)),$$(BZIP2_WHEEL-$$(target))) clean-BZip2-$(os): @echo ">>> Clean BZip2 build products on $(os)" - rm -rf build/$(os)/bzip2-$(BZIP2_VERSION)-* \ - build/$(os)/bzip2 \ - build/$(os)/bzip2-*.log \ - build/$(os)/Support/BZip2.xcframework + rm -rf \ + build/$(os)/*/bzip2-$(BZIP2_VERSION) \ + build/$(os)/*/bzip2-$(BZIP2_VERSION).*.log \ + install/$(os)/*/bzip2-$(BZIP2_VERSION) \ + install/$(os)/*/bzip2-$(BZIP2_VERSION).*.log \ + merge/$(os)/*/bzip2-$(BZIP2_VERSION) \ + merge/$(os)/*/bzip2-$(BZIP2_VERSION).*.log \ + wheels/dist/bzip2 + +clean-BZip2-wheels-$(os): + rm -rf \ + install/$(os)/*/bzip2-$(BZIP2_VERSION)/wheel \ + wheels/dist/bzip2 ########################################################################### # Build: XZ (LZMA) ########################################################################### -XZ_XCFRAMEWORK-$(os)=build/$(os)/Support/XZ.xcframework - -$$(XZ_XCFRAMEWORK-$(os)): $$(foreach sdk,$$(SDKS-$(os)),$$(XZ_FATLIB-$$(sdk))) - @echo ">>> Create XZ.XCFramework on $(os)" - mkdir -p $$(XZ_XCFRAMEWORK-$(os)) - xcodebuild -create-xcframework \ - -output $$@ $$(foreach sdk,$$(SDKS-$(os)),-library $$(XZ_FATLIB-$$(sdk)) -headers build/$(os)/xz/$$(sdk)/include) \ - 2>&1 | tee -a build/$(os)/xz-$(os).xcframework.log - -XZ-$(os): $$(XZ_XCFRAMEWORK-$(os)) +XZ-$(os): $$(foreach sdk,$$(SDKS-$(os)),$$(XZ_FATLIB-$$(sdk))) +XZ-wheels-$(os): $$(foreach target,$$(TARGETS-$(os)),$$(XZ_WHEEL-$$(target))) clean-XZ-$(os): @echo ">>> Clean XZ build products on $(os)" - rm -rf build/$(os)/xz-$(XZ_VERSION)-* \ - build/$(os)/xz \ - build/$(os)/xz-*.log \ - build/$(os)/Support/XZ.xcframework + rm -rf \ + build/$(os)/*/xz-$(XZ_VERSION) \ + build/$(os)/*/xz-$(XZ_VERSION).*.log \ + install/$(os)/*/xz-$(XZ_VERSION) \ + install/$(os)/*/xz-$(XZ_VERSION).*.log \ + merge/$(os)/*/xz-$(XZ_VERSION) \ + merge/$(os)/*/xz-$(XZ_VERSION).*.log \ + wheels/dist/xz + +clean-XZ-wheels-$(os): + rm -rf \ + install/$(os)/*/xz-$(XZ_VERSION)/wheel \ + wheels/dist/xz ########################################################################### # Build: OpenSSL ########################################################################### -OPENSSL_XCFRAMEWORK-$(os)=build/$(os)/Support/OpenSSL.xcframework - -$$(OPENSSL_XCFRAMEWORK-$(os)): $$(foreach sdk,$$(SDKS-$(os)),$$(OPENSSL_FATLIB-$$(sdk))) - @echo ">>> Create OpenSSL.XCFramework on $(os)" - mkdir -p $$(OPENSSL_XCFRAMEWORK-$(os)) - xcodebuild -create-xcframework \ - -output $$@ $$(foreach sdk,$$(SDKS-$(os)),-library $$(OPENSSL_FATLIB-$$(sdk)) -headers build/$(os)/openssl/$$(sdk)/include) \ - 2>&1 | tee -a build/$(os)/openssl-$(os).xcframework.log - -OpenSSL-$(os): $$(OPENSSL_XCFRAMEWORK-$(os)) +OpenSSL-$(os): $$(foreach sdk,$$(SDKS-$(os)),$$(OPENSSL_FATINCLUDE-$$(sdk)) $$(OPENSSL_SSL_FATLIB-$$(sdk)) $$(OPENSSL_CRYPTO_FATLIB-$$(sdk))) +OpenSSL-wheels-$(os): $$(foreach target,$$(TARGETS-$(os)),$$(OPENSSL_WHEEL-$$(target))) clean-OpenSSL-$(os): @echo ">>> Clean OpenSSL build products on $(os)" - rm -rf build/$(os)/openssl-$(OPENSSL_VERSION)-* \ - build/$(os)/openssl \ - build/$(os)/openssl-*.log \ - build/$(os)/Support/OpenSSL.xcframework + rm -rf \ + build/$(os)/*/openssl-$(OPENSSL_VERSION) \ + build/$(os)/*/openssl-$(OPENSSL_VERSION).*.log \ + install/$(os)/*/openssl-$(OPENSSL_VERSION) \ + install/$(os)/*/openssl-$(OPENSSL_VERSION).*.log \ + merge/$(os)/*/openssl-$(OPENSSL_VERSION) \ + merge/$(os)/*/openssl-$(OPENSSL_VERSION).*.log \ + wheels/dist/openssl + +clean-OpenSSL-wheels-$(os): + rm -rf \ + install/$(os)/*/openssl-$(OPENSSL_VERSION)/wheel \ + wheels/dist/openssl ########################################################################### # Build: libFFI @@ -709,179 +993,156 @@ clean-OpenSSL-$(os): # a libFFI framework for macOS. ifneq ($(os),macOS) -LIBFFI_XCFRAMEWORK-$(os)=build/$(os)/Support/libFFI.xcframework -LIBFFI_DIR-$(os)=build/$(os)/libffi-$(LIBFFI_VERSION) - -$$(LIBFFI_DIR-$(os))/darwin_common/include/ffi.h: downloads/libffi-$(LIBFFI_VERSION).tgz $$(PYTHON_XCFRAMEWORK-macOS) +$$(LIBFFI_SRCDIR-$(os))/darwin_common/include/ffi.h: downloads/libffi-$(LIBFFI_VERSION).tar.gz $(HOST_PYTHON_EXE) @echo ">>> Unpack and configure libFFI sources on $(os)" - mkdir -p $$(LIBFFI_DIR-$(os)) - tar zxf downloads/libffi-$(LIBFFI_VERSION).tgz --strip-components 1 -C $$(LIBFFI_DIR-$(os)) + mkdir -p $$(LIBFFI_SRCDIR-$(os)) + tar zxf $$< --strip-components 1 -C $$(LIBFFI_SRCDIR-$(os)) # Patch the build to add support for new platforms - cd $$(LIBFFI_DIR-$(os)) && patch -p1 < $(PROJECT_DIR)/patch/libffi.patch + cd $$(LIBFFI_SRCDIR-$(os)) && patch -p1 < $(PROJECT_DIR)/patch/libffi-$(LIBFFI_VERSION).patch # Configure the build - cd $$(LIBFFI_DIR-$(os)) && \ - PATH="$(PROJECT_DIR)/$(PYTHON_DIR-macOS)/_install/bin:$(PATH)" \ - python$(PYTHON_VER) generate-darwin-source-and-headers.py --only-$(shell echo $(os) | tr '[:upper:]' '[:lower:]') \ - 2>&1 | tee -a ../libffi-$(os).config.log - -$$(LIBFFI_XCFRAMEWORK-$(os)): $$(foreach sdk,$$(SDKS-$(os)),$$(LIBFFI_FATLIB-$$(sdk))) - @echo ">>> Create libFFI.XCFramework on $(os)" - mkdir -p $$(LIBFFI_XCFRAMEWORK-$(os)) - xcodebuild -create-xcframework \ - -output $$@ $$(foreach sdk,$$(SDKS-$(os)),-library $$(LIBFFI_FATLIB-$$(sdk)) -headers $$(LIBFFI_DIR-$(os))/_install/$$(sdk)/include) \ - 2>&1 | tee -a build/$(os)/libffi-$(os).xcframework.log + cd $$(LIBFFI_SRCDIR-$(os)) && \ + $(PROJECT_DIR)/$(HOST_PYTHON_EXE) generate-darwin-source-and-headers.py --only-$(shell echo $(os) | tr '[:upper:]' '[:lower:]') \ + 2>&1 | tee -a ../libffi-$(LIBFFI_VERSION).config.log endif -libFFI-$(os): $$(LIBFFI_XCFRAMEWORK-$(os)) +libFFI-$(os): $$(foreach sdk,$$(SDKS-$(os)),$$(LIBFFI_FATLIB-$$(sdk))) +libFFI-wheels-$(os): $$(foreach target,$$(TARGETS-$(os)),$$(LIBFFI_WHEEL-$$(target))) clean-libFFI-$(os): @echo ">>> Clean libFFI build products on $(os)" - rm -rf build/$(os)/libffi-$(LIBFFI_VERSION) \ - build/$(os)/libffi-*.log \ - build/$(os)/Support/libFFI.xcframework + rm -rf \ + build/$(os)/libffi-$(LIBFFI_VERSION) \ + build/$(os)/libffi-$(LIBFFI_VERSION).*.log \ + merge/$(os)/libffi-$(LIBFFI_VERSION) \ + merge/$(os)/libffi-$(LIBFFI_VERSION).*.log \ + wheels/dist/libffi +clean-libFFI-wheels-$(os): + rm -rf \ + build/$(os)/libffi-$(LIBFFI_VERSION)/build_*/wheel \ + wheels/dist/libffi ########################################################################### # Build: Python ########################################################################### -PYTHON_XCFRAMEWORK-$(os)=build/$(os)/Support/Python.xcframework -PYTHON_RESOURCES-$(os)=build/$(os)/Support/Python/Resources/lib +$$(PYTHON_XCFRAMEWORK-$(os)): \ + $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_FATLIB-$$(sdk)) $$(PYTHON_FATINCLUDE-$$(sdk))) + @echo ">>> Create Python.XCFramework on $(os)" + mkdir -p $$(dir $$(PYTHON_XCFRAMEWORK-$(os))) + xcodebuild -create-xcframework \ + -output $$@ $$(foreach sdk,$$(SDKS-$(os)),-library $$(PYTHON_FATLIB-$$(sdk)) -headers $$(PYTHON_FATINCLUDE-$$(sdk))) \ + 2>&1 | tee -a support/python-$(os).xcframework.log -# macOS builds a single Python universal2 target; thus it needs to be -# configured in the `build` macro, not the `build-target` macro. -ifeq ($(os),macOS) +$$(PYTHON_STDLIB-$(os)): \ + $$(PYTHON_XCFRAMEWORK-$(os)) \ + $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_FATSTDLIB-$$(sdk))) + @echo ">>> Create Python stdlib on $(os)" + # Copy stdlib from first SDK in $(os) + cp -r $$(PYTHON_FATSTDLIB-$$(firstword $$(SDKS-$(os)))) $$(PYTHON_STDLIB-$(os)) -# On macOS, there's a single target and a single output dir, -# rather than a target for each architecture. -PYTHON_TARGETS-$(os)=macOS - -# For convenience on macOS, define an OS-level PYTHON_DIR and PYTHON_LIB. -# They are proxies of the values set for the first target, since all target -# constants should have the same value for macOS builds -PYTHON_DIR-$(os)=$$(PYTHON_DIR-$$(firstword $$(TARGETS-$(os)))) -PYTHON_LIB-$(os)=$$(PYTHON_LIB-$$(firstword $$(TARGETS-$(os)))) - -$$(PYTHON_DIR-$(os))/Makefile: \ - $$(BZIP2_XCFRAMEWORK-$(os)) \ - $$(XZ_XCFRAMEWORK-$(os)) \ - $$(OPENSSL_XCFRAMEWORK-$(os)) \ - downloads/Python-$(PYTHON_VERSION).tgz - @echo ">>> Unpack and configure Python for $(os)" - mkdir -p $$(PYTHON_DIR-$(os)) - tar zxf downloads/Python-$(PYTHON_VERSION).tgz --strip-components 1 -C $$(PYTHON_DIR-$(os)) - # Apply target Python patches - cd $$(PYTHON_DIR-$(os)) && patch -p1 < $(PROJECT_DIR)/patch/Python/Python.patch - cat $(PROJECT_DIR)/patch/Python/Setup.embedded \ - $(PROJECT_DIR)/patch/Python/Setup.$(os) | \ - sed -e "s/{{slice}}/$$(SLICE-macosx)/g" \ - > $$(PYTHON_DIR-$(os))/Modules/Setup.local - # Configure target Python - cd $$(PYTHON_DIR-$(os)) && \ - ./configure \ - CC="$(CC-macosx)" LD="$(CC-macosx)" \ - --prefix="$(PROJECT_DIR)/$$(PYTHON_DIR-$(os))/_install" \ - --without-doc-strings --enable-ipv6 --without-ensurepip --enable-universalsdk --with-universal-archs=universal2 \ - --with-openssl=../openssl/macosx \ - $$(PYTHON_CONFIGURE-$(os)) \ - 2>&1 | tee -a ../python-$(os).config.log + # Delete the single-SDK stdlib artefacts from $(os) + rm -rf \ + $$(PYTHON_STDLIB-$(os))/_sysconfigdata__*.py \ + $$(PYTHON_STDLIB-$(os))/config-* \ + $$(PYTHON_STDLIB-$(os))/lib-dynload/* -$$(PYTHON_DIR-$(os))/python.exe: \ - $$(PYTHON_DIR-$(os))/Makefile - @echo ">>> Build Python for $(os)" - cd $$(PYTHON_DIR-$(os)) && \ - PATH="$(PROJECT_DIR)/$(PYTHON_DIR-$(os))/_install/bin:$(PATH)" \ - make all \ - 2>&1 | tee -a ../python-$(os).build.log + # Copy the config-* contents from every SDK in $(os) into the support folder. + $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_FATSTDLIB-$$(sdk))/config-$(PYTHON_VER)-* $$(PYTHON_STDLIB-$(os)); ) -$$(PYTHON_LIB-$(os)): $$(PYTHON_DIR-$(os))/python.exe - @echo ">>> Install Python for $(os)" - cd $$(PYTHON_DIR-$(os)) && \ - PATH="$(PROJECT_DIR)/$(PYTHON_DIR-$(os))/_install/bin:$(PATH)" \ - make install \ - 2>&1 | tee -a ../python-$(os).install.log + # Copy the _sysconfigdata modules from every SDK in $(os) into the support folder. + $$(foreach sdk,$$(SDKS-$(os)),cp $$(PYTHON_FATSTDLIB-$$(sdk))/_sysconfigdata__*.py $$(PYTHON_STDLIB-$(os)); ) -else + # Copy the lib-dynload contents from every SDK in $(os) into the support folder. + $$(foreach sdk,$$(SDKS-$(os)),cp $$(PYTHON_FATSTDLIB-$$(sdk))/lib-dynload/* $$(PYTHON_STDLIB-$(os))/lib-dynload; ) -# The targets for Python on OSes other than macOS -# are the same as they are for every other library -PYTHON_TARGETS-$(os)=$$(TARGETS-$(os)) +dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz: $$(PYTHON_XCFRAMEWORK-$(os)) $$(PYTHON_STDLIB-$(os)) + @echo ">>> Create VERSIONS file for $(os)" + echo "Python version: $(PYTHON_VERSION) " > support/$(os)/VERSIONS + echo "Build: $(BUILD_NUMBER)" >> support/$(os)/VERSIONS + echo "Min $(os) version: $$(VERSION_MIN-$(os))" >> support/$(os)/VERSIONS + echo "---------------------" >> support/$(os)/VERSIONS +ifeq ($(os),macOS) + echo "libFFI: macOS native" >> support/$(os)/VERSIONS +else + echo "libFFI: $(LIBFFI_VERSION)" >> support/$(os)/VERSIONS +endif + echo "BZip2: $(BZIP2_VERSION)" >> support/$(os)/VERSIONS + echo "OpenSSL: $(OPENSSL_VERSION)" >> support/$(os)/VERSIONS + echo "XZ: $(XZ_VERSION)" >> support/$(os)/VERSIONS +ifneq ($(os),macOS) + @echo ">>> Create cross-platform site sitecustomize.py for $(os)" + mkdir -p support/$(os)/platform-site + cat $(PROJECT_DIR)/patch/Python/sitecustomize.py \ + | sed -e "s/{{os}}/$(os)/g" \ + | sed -e "s/{{tag}}/$$(shell echo $(os) | tr '[:upper:]' '[:lower:]')_$$(shell echo $$(VERSION_MIN-$(os)) | sed "s/\./_/g")/g" \ + > support/$(os)/platform-site/sitecustomize.py endif -$$(PYTHON_XCFRAMEWORK-$(os)): $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_FATLIB-$$(sdk))) $$(foreach target,$$(PYTHON_TARGETS-$(os)),$$(PYCONFIG_H-$$(target))) - @echo ">>> Create Python.XCFramework on $(os)" - mkdir -p $$(PYTHON_XCFRAMEWORK-$(os)) - xcodebuild -create-xcframework \ - -output $$@ $$(foreach sdk,$$(SDKS-$(os)),-library $$(PYTHON_FATLIB-$$(sdk)) -headers $$(PYTHON_DIR-$$(sdk))/include/python$(PYTHON_VER)) \ - 2>&1 | tee -a build/$(os)/python-$(os).xcframework.log - # Copy the standard library from the first target listed - mkdir -p $$(PYTHON_RESOURCES-$(os)) - cp -f -r $$(PYTHON_DIR-$$(firstword $$(PYTHON_TARGETS-$(os))))/_install/lib/python$(PYTHON_VER) \ - $$(PYTHON_RESOURCES-$(os)) + @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/$(os) `ls -A support/$(os)` + # Build a distributable tarball + tar zcvf $$@ -X patch/Python/release.common.exclude -X patch/Python/release.$(os).exclude -C support/$(os) `ls -A support/$(os)` Python-$(os): dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz clean-Python-$(os): @echo ">>> Clean Python build products on $(os)" rm -rf \ - dist/Python-$(PYTHON_VER)-$(os) \ - build/$(os)/Python-$(PYTHON_VERSION)-* \ - build/$(os)/python \ - build/$(os)/python-*.log \ - build/$(os)/Support/Python.xcframework \ - build/$(os)/Support/Python + build/$(os)/*/python-$(PYTHON_VERSION) \ + build/$(os)/*/python-$(PYTHON_VERSION).*.log \ + install/$(os)/*/python-$(PYTHON_VERSION) \ + install/$(os)/*/python-$(PYTHON_VERSION).*.log \ + merge/$(os)/*/python-$(PYTHON_VERSION) \ + merge/$(os)/*/python-$(PYTHON_VERSION).*.log \ + support/$(os) \ + support/*-$(os).*.log \ + dist/Python-$(PYTHON_VER)-$(os)-* dev-clean-Python-$(os): @echo ">>> Partially clean Python build products on $(os) so that local code modifications can be made" rm -rf \ - dist/Python-$(PYTHON_VER)-$(os)-* \ - build/$(os)/Python-$(PYTHON_VERSION)-*/python.exe \ - build/$(os)/Python-$(PYTHON_VERSION)-*/_install \ - build/$(os)/python \ - build/$(os)/python-*.log \ - build/$(os)/Support/Python.xcframework \ - build/$(os)/Support/Python + build/$(os)/*/Python-$(PYTHON_VERSION)/python.exe \ + build/$(os)/*/python-$(PYTHON_VERSION).*.log \ + install/$(os)/*/python-$(PYTHON_VERSION) \ + install/$(os)/*/python-$(PYTHON_VERSION).*.log \ + merge/$(os)/*/python-$(PYTHON_VERSION) \ + merge/$(os)/*/python-$(PYTHON_VERSION).*.log \ + support/$(os) \ + support/*-$(os).*.log \ + dist/Python-$(PYTHON_VER)-$(os)-* + +merge-clean-Python-$(os): + @echo ">>> Partially clean Python build products on $(os) so that merge modifications can be made" + rm -rf \ + merge/$(os)/*/python-$(PYTHON_VERSION) \ + merge/$(os)/*/python-$(PYTHON_VERSION).*.log \ + support/$(os) \ + support/*-$(os).*.log \ + dist/Python-$(PYTHON_VER)-$(os)-* ########################################################################### # Build ########################################################################### -dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz: \ - $$(BZIP2_XCFRAMEWORK-$(os)) \ - $$(XZ_XCFRAMEWORK-$(os)) \ - $$(OPENSSL_XCFRAMEWORK-$(os)) \ - $$(LIBFFI_XCFRAMEWORK-$(os)) \ - $$(PYTHON_XCFRAMEWORK-$(os)) - @echo ">>> Create final distribution artefact for $(os)" - mkdir -p dist - echo "Python version: $(PYTHON_VERSION) " > build/$(os)/Support/VERSIONS - echo "Build: $(BUILD_NUMBER)" >> build/$(os)/Support/VERSIONS - echo "---------------------" >> build/$(os)/Support/VERSIONS -ifeq ($(os),macOS) - echo "libFFI: macOS native" >> build/$(os)/Support/VERSIONS -else - echo "libFFI: $(LIBFFI_VERSION)" >> build/$(os)/Support/VERSIONS -endif - echo "BZip2: $(BZIP2_VERSION)" >> build/$(os)/Support/VERSIONS - echo "OpenSSL: $(OPENSSL_VERSION)" >> build/$(os)/Support/VERSIONS - echo "XZ: $(XZ_VERSION)" >> build/$(os)/Support/VERSIONS - - # 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 build/$(os)/Support `ls -A build/$(os)/Support` - # Build a distributable tarball - tar zcvf $$@ -X patch/Python/release.common.exclude -X patch/Python/release.$(os).exclude -C build/$(os)/Support `ls -A build/$(os)/Support` - $(os): dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz +$(os)-wheels: $(foreach dep,$(DEPENDENCIES),$(dep)-wheels-$(os)) clean-$(os): @echo ">>> Clean $(os) build products" rm -rf \ build/$(os) \ + install/$(os) \ + merge/$(os) \ dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz \ dist/Python-$(PYTHON_VER)-$(os)-support.test-$(BUILD_NUMBER).tar.gz \ +clean-wheels-$(os): $(foreach dep,$(DEPENDENCIES),clean-$(dep)-wheels-$(os)) + ########################################################################### # Build: Debug ########################################################################### @@ -889,39 +1150,49 @@ clean-$(os): vars-$(os): $$(foreach target,$$(TARGETS-$(os)),vars-$$(target)) $$(foreach sdk,$$(SDKS-$(os)),vars-$$(sdk)) @echo ">>> Environment variables for $(os)" @echo "SDKS-$(os): $$(SDKS-$(os))" - @echo "BZIP2_XCFRAMEWORK-$(os): $$(BZIP2_XCFRAMEWORK-$(os))" - @echo "XZ_XCFRAMEWORK-$(os): $$(XZ_XCFRAMEWORK-$(os))" - @echo "OPENSSL_XCFRAMEWORK-$(os): $$(OPENSSL_XCFRAMEWORK-$(os))" - @echo "LIBFFI_XCFRAMEWORK-$(os): $$(LIBFFI_XCFRAMEWORK-$(os))" - @echo "LIBFFI_DIR-$(os): $$(LIBFFI_DIR-$(os))" + @echo "LIBFFI_SRCDIR-$(os): $$(LIBFFI_SRCDIR-$(os))" + @echo "LIBPYTHON_XCFRAMEWORK-$(os): $$(LIBPYTHON_XCFRAMEWORK-$(os))" @echo "PYTHON_XCFRAMEWORK-$(os): $$(PYTHON_XCFRAMEWORK-$(os))" - @echo "PYTHON_RESOURCES-$(os): $$(PYTHON_RESOURCES-$(os))" - @echo "PYTHON_TARGETS-$(os): $$(PYTHON_TARGETS-$(os))" - @echo "PYTHON_DIR-$(os): $$(PYTHON_DIR-$(os))" - @echo "PYTHON_LIB-$(os): $$(PYTHON_LIB-$(os))" @echo endef # build +$(BDIST_WHEEL): $(HOST_PYTHON_EXE) + @echo ">>> Ensure the macOS python install has pip and wheel" + $(HOST_PYTHON_EXE) -m ensurepip + PIP_REQUIRE_VIRTUALENV=false $(HOST_PYTHON_EXE) -m pip install wheel + +# Binary support wheels +wheels: $(foreach dep,$(DEPENDENCIES),$(dep)-wheels) +clean-wheels: $(foreach dep,$(DEPENDENCIES),clean-wheels-$(dep)) + # Dump environment variables (for debugging purposes) vars: $(foreach os,$(OS_LIST),vars-$(os)) # Expand cross-platform build and clean targets for each output product -XZ: $(foreach os,$(OS_LIST),XZ-$(os)) -clean-XZ: $(foreach os,$(OS_LIST),clean-XZ-$(os)) - BZip2: $(foreach os,$(OS_LIST),BZip2-$(os)) +BZip2-wheels: $(foreach os,$(OS_LIST),BZip2-wheels-$(os)) clean-BZip2: $(foreach os,$(OS_LIST),clean-BZip2-$(os)) +clean-BZip2-wheels: $(foreach os,$(OS_LIST),clean-BZip2-wheels-$(os)) + +XZ: $(foreach os,$(OS_LIST),XZ-$(os)) +XZ-wheels: $(foreach os,$(OS_LIST),XZ-wheels-$(os)) +clean-XZ: $(foreach os,$(OS_LIST),clean-XZ-$(os)) +clean-XZ-wheels: $(foreach os,$(OS_LIST),clean-XZ-wheels-$(os)) OpenSSL: $(foreach os,$(OS_LIST),OpenSSL-$(os)) +OpenSSL-wheels: $(foreach os,$(OS_LIST),OpenSSL-wheels-$(os)) clean-OpenSSL: $(foreach os,$(OS_LIST),clean-OpenSSL-$(os)) +clean-OpenSSL-wheels: $(foreach os,$(OS_LIST),clean-OpenSSL-wheels-$(os)) libFFI: $(foreach os,$(OS_LIST),libFFI-$(os)) +libFFI-wheels: $(foreach os,$(OS_LIST),libFFI-wheels-$(os)) clean-libFFI: $(foreach os,$(OS_LIST),clean-libFFI-$(os)) +clean-libFFI-wheels: $(foreach os,$(OS_LIST),clean-libFFI-wheels-$(os)) Python: $(foreach os,$(OS_LIST),Python-$(os)) clean-Python: $(foreach os,$(OS_LIST),clean-Python-$(os)) dev-clean-Python: $(foreach os,$(OS_LIST),dev-clean-Python-$(os)) # Expand the build macro for every OS -$(foreach os,$(OS_LIST),$(eval $(call build,$(os)))) \ No newline at end of file +$(foreach os,$(OS_LIST),$(eval $(call build,$(os)))) diff --git a/README.rst b/README.rst index dacbbe12..d8f8ab12 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ Python Apple Support ==================== -**This repository branch builds a packaged version of Python 3.9.12**. +**This repository branch builds a packaged version of Python 3.9.14**. Other Python versions are available by cloning other branches of the main repository. @@ -10,9 +10,11 @@ into a macOS, iOS, tvOS or watchOS project. 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. +incorporated into an XCode project. The binary modules in the Python standard +library are statically compiled, but are distribted as ``.so`` objects that +can be dynamically loaded at runtime. -It exposed *almost* all the modules in the Python standard library except for: +It exposes *almost* all the modules in the Python standard library except for: * dbm.gnu * tkinter * readline @@ -23,7 +25,11 @@ It exposed *almost* all the modules in the Python standard library except for: The following standard library modules are available on macOS, but not the other Apple platforms: * curses + * grp + * multiprocessing * posixshmem + * posixsubprocess + * syslog 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 @@ -35,7 +41,7 @@ x86_64 and M1 hardware. This should enable the code to run on: * Mac Mini (including M1 Apple Silicon Mac minis) * Mac Studio (all models) * Mac Pro (all models) -* iOS 13.0 or later, on: +* iOS 12.0 or later, on: * iPhone (6s or later) * iPad (5th gen or later) * iPad Air (all models) @@ -48,6 +54,11 @@ x86_64 and M1 hardware. This should enable the code to run on: Quickstart ---------- +The easist way to use these packages is by creating a project with `Briefcase +`__. Briefcase will download pre-compiled +versions of these support packages, and add them to an XCode project (or +pre-build stub application, in the case of macOS). + Pre-built versions of the frameworks can be downloaded `for macOS`_, `for iOS`_, `for tvOS`_, and `for watchOS`_, and added to your project. @@ -66,10 +77,76 @@ This should: 2. Patch them as required for compatibility with the selected OS 3. Build the packages as XCode-compatible XCFrameworks. -The build products will be in the `build` directory; the compiled frameworks -will be in the `dist` directory. +The resulting support packages will be packaged as a ``.tar.gz`` file +in the ``dist`` folder. + +Each support package contains: + +* ``VERSIONS``, a text file describing the specific versions of code used to + build the support package; +* ``Python.xcframework``, a multi-architecture build of libPython3.9.a +* ``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. + +Non-macOS platforms also contain a ``platform-site`` folder. This contains a +site customization script that can be used to make your local Python install +look like it is an on-device install. This is needed because when you run +``pip`` you'll be on a macOS machine; if ``pip`` tries to install a binary +package, it will install a macOS binary wheel (which won't work on +iOS/tvOS/watchOS). However, if you add the ``platform-site`` folder to your +``PYTHONPATH`` when invoking pip, the site customization will make your Python +install return ``platform`` and ``sysconfig`` responses consistent with +on-device behavior, which will cause ``pip`` to install platform-appropriate +packages. + +To add a support package to your own Xcode project: + +1. Drag ``Python.xcframework`` and ``python-stdlib`` into your Xcode project + tree. +2. Ensure that these two objects are added to any targets that need to use + them; +3. Add a custom build phase to purge any binary modules for the platform you are + *not* targetting; and +4. Add a custom build phase to sign any of the binary modules in your app. +5. Add CPython API code to your app to create an instance of the Python + interpreter. + +For examples of the scripts needed for steps 3 and 4, and the code needed for +step 5, compare with a project generated with Briefcase. + +On macOS, you must also either: +1. Enable the "Disable Library Validation" entitlement (found on the "Signing + & Capabilities" tab in XCode); or +2. Sign your app with a Development or Distribution certificate. This will + require a paid Apple Developer subscription. + +It is not possible to use an ad-hoc signing certificate with the "Disable +Library Validation" entitlement disabled. + +On iOS/tvOS/watchOS, you can use the default developer certificate for deploying +to a device simulator. However, to deploy to a physical device (including your +own), you will require a Development or Distribution certificate, which requires +a paid Apple Developer subscription. + +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 `server/pypi/dist` directory of the [binary dependency builder +project](https://github.com/freakboy3742/chaquopy). + +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 -.. _for macOS: https://briefcase-support.org/python?platform=macOS&version=3.9 -.. _for iOS: https://briefcase-support.org/python?platform=iOS&version=3.9 -.. _for tvOS: https://briefcase-support.org/python?platform=tvOS&version=3.9 -.. _for watchOS: https://briefcase-support.org/python?platform=watchOS&version=3.9 +.. _for macOS: https://briefcase-support.s3.amazonaws.com/python/3.9/macOS/Python-3.9-macOS-support.b8.tar.gz +.. _for iOS: https://briefcase-support.s3.amazonaws.com/python/3.9/iOS/Python-3.9-iOS-support.b8.tar.gz +.. _for tvOS: https://briefcase-support.s3.amazonaws.com/python/3.9/tvOS/Python-3.9-tvOS-support.b8.tar.gz +.. _for watchOS: https://briefcase-support.s3.amazonaws.com/python/3.9/watchOS/Python-3.9-watchOS-support.b8.tar.gz diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch index 15545936..fbf14484 100644 --- a/patch/Python/Python.patch +++ b/patch/Python/Python.patch @@ -1,523 +1,42 @@ -diff --git a/Doc/library/os.rst b/Doc/library/os.rst -index 2f7b37019e..a9de70284a 100644 ---- a/Doc/library/os.rst -+++ b/Doc/library/os.rst -@@ -3163,6 +3163,13 @@ - - .. versionadded:: 3.8 - -+.. data:: allows_subprocesses -+ -+ Boolean that describes whether subprocesses can be by the operating system. -+ Some platforms (e.g., iOS mobile devices) *implement* calls like -+ :func:`execv` and :func:`spawnv`, but will raise errors or break if -+ called. Calls to create subprocesses should only be invoked if -+ :data:`os.allows_subprocesses` is `True`. - - .. data:: MFD_CLOEXEC - MFD_ALLOW_SEALING -diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst -index f9e9f63f21..25f22d6f71 100644 ---- a/Doc/library/subprocess.rst -+++ b/Doc/library/subprocess.rst -@@ -25,6 +25,11 @@ - - :pep:`324` -- PEP proposing the subprocess module - -+:mod:`subprocess` can only be used on platforms that support subprocess -+creation. Some platforms (especially mobile platforms) may not support -+subprocesses; if :data:`os.allows_subprocesses` is `False`, any calls in -+this module that request a subprocess be created will raise a -+:exc:`RuntimeError`. - - Using the :mod:`subprocess` Module - ---------------------------------- -diff --git a/Include/datetime.h b/Include/datetime.h -index 5d9f2558f9..fc66471923 100644 ---- a/Include/datetime.h -+++ b/Include/datetime.h -@@ -179,7 +179,6 @@ - - #define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI" - -- - /* This block is only used as part of the public API and should not be - * included in _datetimemodule.c, which does not use the C API capsule. - * See bpo-35081 for more details. -diff --git a/Lib/ctypes/test/test_as_parameter.py b/Lib/ctypes/test/test_as_parameter.py -index f9d27cb89d..da172b345a 100644 ---- a/Lib/ctypes/test/test_as_parameter.py -+++ b/Lib/ctypes/test/test_as_parameter.py -@@ -1,9 +1,11 @@ -+import os - import unittest - from ctypes import * - from ctypes.test import need_symbol - import _ctypes_test - --dll = CDLL(_ctypes_test.__file__) -+ -+dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - - try: - CALLBACK_FUNCTYPE = WINFUNCTYPE -diff --git a/Lib/ctypes/test/test_bitfields.py b/Lib/ctypes/test/test_bitfields.py -index 66acd62e68..95216920e6 100644 ---- a/Lib/ctypes/test/test_bitfields.py -+++ b/Lib/ctypes/test/test_bitfields.py -@@ -25,7 +25,7 @@ - ("R", c_short, 6), - ("S", c_short, 7)] - --func = CDLL(_ctypes_test.__file__).unpack_bitfields -+func = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])).unpack_bitfields - func.argtypes = POINTER(BITS), c_char - - ##for n in "ABCDEFGHIMNOPQRS": -diff --git a/Lib/ctypes/test/test_callbacks.py b/Lib/ctypes/test/test_callbacks.py -index d8e9c5a760..52820932b0 100644 ---- a/Lib/ctypes/test/test_callbacks.py -+++ b/Lib/ctypes/test/test_callbacks.py -@@ -160,7 +160,7 @@ - - def test_integrate(self): - # Derived from some then non-working code, posted by David Foster -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - - # The function prototype called by 'integrate': double func(double); - CALLBACK = CFUNCTYPE(c_double, c_double) -@@ -211,7 +211,7 @@ - def test_callback_register_int(self): - # Issue #8275: buggy handling of callback args under Win64 - # NOTE: should be run on release builds as well -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int) - # All this function does is call the callback with its args squared - func = dll._testfunc_cbk_reg_int -@@ -227,7 +227,7 @@ - def test_callback_register_double(self): - # Issue #8275: buggy handling of callback args under Win64 - # NOTE: should be run on release builds as well -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double, - c_double, c_double) - # All this function does is call the callback with its args squared -diff --git a/Lib/ctypes/test/test_cfuncs.py b/Lib/ctypes/test/test_cfuncs.py -index ac2240fa19..b08b5f7581 100644 ---- a/Lib/ctypes/test/test_cfuncs.py -+++ b/Lib/ctypes/test/test_cfuncs.py -@@ -1,6 +1,7 @@ - # A lot of failures in these tests on Mac OS X. - # Byte order related? - -+import os - import unittest - from ctypes import * - from ctypes.test import need_symbol -@@ -8,7 +9,7 @@ - import _ctypes_test - - class CFunctions(unittest.TestCase): -- _dll = CDLL(_ctypes_test.__file__) -+ _dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - - def S(self): - return c_longlong.in_dll(self._dll, "last_tf_arg_s").value -@@ -206,7 +207,7 @@ - - @need_symbol('WinDLL') - class stdcallCFunctions(CFunctions): -- _dll = stdcall_dll(_ctypes_test.__file__) -+ _dll = stdcall_dll(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - - if __name__ == '__main__': - unittest.main() -diff --git a/Lib/ctypes/test/test_checkretval.py b/Lib/ctypes/test/test_checkretval.py -index e9567dc391..3c3fbf103c 100644 ---- a/Lib/ctypes/test/test_checkretval.py -+++ b/Lib/ctypes/test/test_checkretval.py -@@ -1,3 +1,4 @@ -+import os - import unittest - - from ctypes import * -@@ -14,7 +15,7 @@ - def test_checkretval(self): - - import _ctypes_test -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - self.assertEqual(42, dll._testfunc_p_p(42)) - - dll._testfunc_p_p.restype = CHECKED -diff --git a/Lib/ctypes/test/test_funcptr.py b/Lib/ctypes/test/test_funcptr.py -index e0b9b54e97..a5b1b55294 100644 ---- a/Lib/ctypes/test/test_funcptr.py -+++ b/Lib/ctypes/test/test_funcptr.py -@@ -1,4 +1,4 @@ --import unittest -+import os, unittest - from ctypes import * - - try: -@@ -8,7 +8,10 @@ - WINFUNCTYPE = CFUNCTYPE - - import _ctypes_test --lib = CDLL(_ctypes_test.__file__) -+ -+ -+lib = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) -+ - - class CFuncPtrTestCase(unittest.TestCase): - def test_basic(self): -diff --git a/Lib/ctypes/test/test_functions.py b/Lib/ctypes/test/test_functions.py -index bdb044e594..624ce9a388 100644 ---- a/Lib/ctypes/test/test_functions.py -+++ b/Lib/ctypes/test/test_functions.py -@@ -7,6 +7,7 @@ - - from ctypes import * - from ctypes.test import need_symbol -+import os - import sys, unittest - - try: -@@ -16,7 +17,9 @@ - WINFUNCTYPE = CFUNCTYPE - - import _ctypes_test --dll = CDLL(_ctypes_test.__file__) -+ -+ -+dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - if sys.platform == "win32": - windll = WinDLL(_ctypes_test.__file__) - -diff --git a/Lib/ctypes/test/test_libc.py b/Lib/ctypes/test/test_libc.py -index 56285b5ff8..f78a152ade 100644 ---- a/Lib/ctypes/test/test_libc.py -+++ b/Lib/ctypes/test/test_libc.py -@@ -1,9 +1,12 @@ -+import os - import unittest - - from ctypes import * - import _ctypes_test - --lib = CDLL(_ctypes_test.__file__) +--- /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 + -+lib = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) + - - def three_way_cmp(x, y): - """Return -1 if x < y, 0 if x == y and 1 if x > y""" -diff --git a/Lib/ctypes/test/test_parameters.py b/Lib/ctypes/test/test_parameters.py -index 38af7ac13d..db0d4986d6 100644 ---- a/Lib/ctypes/test/test_parameters.py -+++ b/Lib/ctypes/test/test_parameters.py -@@ -140,7 +140,7 @@ - import _ctypes_test - from ctypes import CDLL, c_void_p, ArgumentError - -- func = CDLL(_ctypes_test.__file__)._testfunc_p_p -+ func = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE']))._testfunc_p_p - func.restype = c_void_p - # TypeError: has no from_param method - self.assertRaises(TypeError, setattr, func, "argtypes", (object,)) -diff --git a/Lib/ctypes/test/test_pickling.py b/Lib/ctypes/test/test_pickling.py -index c4a79b9779..833608b629 100644 ---- a/Lib/ctypes/test/test_pickling.py -+++ b/Lib/ctypes/test/test_pickling.py -@@ -1,8 +1,11 @@ - import unittest -+import os - import pickle - from ctypes import * - import _ctypes_test --dll = CDLL(_ctypes_test.__file__) ++def get_platform_ios(): ++ 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] + -+dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - - class X(Structure): - _fields_ = [("a", c_int), ("b", c_double)] -diff --git a/Lib/ctypes/test/test_pointers.py b/Lib/ctypes/test/test_pointers.py -index e97515879f..d678be3800 100644 ---- a/Lib/ctypes/test/test_pointers.py -+++ b/Lib/ctypes/test/test_pointers.py -@@ -1,3 +1,4 @@ -+import os - import unittest, sys - - from ctypes import * -@@ -20,7 +21,7 @@ - self.assertRaises(TypeError, A, c_ulong(33)) - - def test_pass_pointers(self): -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - func = dll._testfunc_p_p - if sizeof(c_longlong) == sizeof(c_void_p): - func.restype = c_longlong -@@ -38,7 +39,7 @@ - self.assertEqual(res[0], 12345678) - - def test_change_pointers(self): -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - func = dll._testfunc_p_p - - i = c_int(87654) -@@ -77,7 +78,7 @@ - return 0 - callback = PROTOTYPE(func) - -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - # This function expects a function pointer, - # and calls this with an integer pointer as parameter. - # The int pointer points to a table containing the numbers 1..10 -@@ -143,7 +144,7 @@ - - def test_charpp(self): - """Test that a character pointer-to-pointer is correctly passed""" -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - func = dll._testfunc_c_p_p - func.restype = c_char_p - argv = (c_char_p * 2)() -diff --git a/Lib/ctypes/test/test_prototypes.py b/Lib/ctypes/test/test_prototypes.py -index cd0c649de3..539351f798 100644 ---- a/Lib/ctypes/test/test_prototypes.py -+++ b/Lib/ctypes/test/test_prototypes.py -@@ -1,3 +1,4 @@ -+import os - from ctypes import * - from ctypes.test import need_symbol - import unittest -@@ -23,7 +24,9 @@ - # In this case, there would have to be an additional reference to the argument... - - import _ctypes_test --testdll = CDLL(_ctypes_test.__file__) ++ 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)) + -+testdll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - - # Return machine address `a` as a (possibly long) non-negative integer. - # Starting with Python 2.5, id(anything) is always non-negative, and -diff --git a/Lib/ctypes/test/test_refcounts.py b/Lib/ctypes/test/test_refcounts.py -index f2edfa6400..0e4dd7c126 100644 ---- a/Lib/ctypes/test/test_refcounts.py -+++ b/Lib/ctypes/test/test_refcounts.py -@@ -1,3 +1,4 @@ -+import os - import unittest - from test import support - import ctypes -@@ -7,7 +8,10 @@ - OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong) - - import _ctypes_test --dll = ctypes.CDLL(_ctypes_test.__file__) ++ 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)) + -+dll = ctypes.CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) ++ # UTF8String returns a const char*; ++ SEL_UTF8String = c_void_p(objc.sel_registerName(b'UTF8String')) ++ objc.objc_msgSend.restype = c_char_p + - - class RefcountTestCase(unittest.TestCase): - -diff --git a/Lib/ctypes/test/test_returnfuncptrs.py b/Lib/ctypes/test/test_returnfuncptrs.py -index 1974f40df6..7b76fae44c 100644 ---- a/Lib/ctypes/test/test_returnfuncptrs.py -+++ b/Lib/ctypes/test/test_returnfuncptrs.py -@@ -1,5 +1,6 @@ - import unittest - from ctypes import * -+import os - - import _ctypes_test - -@@ -8,7 +9,7 @@ - def test_with_prototype(self): - # The _ctypes_test shared lib/dll exports quite some functions for testing. - # The get_strchr function returns a *pointer* to the C strchr function. -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - get_strchr = dll.get_strchr - get_strchr.restype = CFUNCTYPE(c_char_p, c_char_p, c_char) - strchr = get_strchr() -@@ -20,7 +21,7 @@ - self.assertRaises(TypeError, strchr, b"abcdef") - - def test_without_prototype(self): -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - get_strchr = dll.get_strchr - # the default 'c_int' would not work on systems where sizeof(int) != sizeof(void *) - get_strchr.restype = c_void_p -@@ -34,7 +35,7 @@ - self.assertRaises(TypeError, strchr, b"abcdef") - - def test_from_dll(self): -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - # _CFuncPtr instances are now callable with a tuple argument - # which denotes a function name and a dll: - strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)(("my_strchr", dll)) -@@ -50,13 +51,13 @@ - if key == 0: - return "my_strchr" - if key == 1: -- return CDLL(_ctypes_test.__file__) -+ return CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - raise IndexError - - # _CFuncPtr instances are now callable with a tuple argument - # which denotes a function name and a dll: - strchr = CFUNCTYPE(c_char_p, c_char_p, c_char)( -- BadSequence(("my_strchr", CDLL(_ctypes_test.__file__)))) -+ BadSequence(("my_strchr", CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE']))))) - self.assertTrue(strchr(b"abcdef", b"b"), "bcdef") - self.assertEqual(strchr(b"abcdef", b"x"), None) - self.assertRaises(ArgumentError, strchr, b"abcdef", 3.0) -diff --git a/Lib/ctypes/test/test_slicing.py b/Lib/ctypes/test/test_slicing.py -index a3932f1767..6d7bfff8f2 100644 ---- a/Lib/ctypes/test/test_slicing.py -+++ b/Lib/ctypes/test/test_slicing.py -@@ -1,3 +1,4 @@ -+import os - import unittest - from ctypes import * - from ctypes.test import need_symbol -@@ -62,7 +63,7 @@ - def test_char_ptr(self): - s = b"abcdefghijklmnopqrstuvwxyz" - -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - dll.my_strdup.restype = POINTER(c_char) - dll.my_free.restype = None - res = dll.my_strdup(s) -@@ -94,7 +95,7 @@ - dll.my_free(res) - - def test_char_ptr_with_free(self): -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - s = b"abcdefghijklmnopqrstuvwxyz" - - class allocated_c_char_p(c_char_p): -@@ -130,7 +131,7 @@ - def test_wchar_ptr(self): - s = "abcdefghijklmnopqrstuvwxyz\0" - -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - dll.my_wcsdup.restype = POINTER(c_wchar) - dll.my_wcsdup.argtypes = POINTER(c_wchar), - dll.my_free.restype = None -diff --git a/Lib/ctypes/test/test_stringptr.py b/Lib/ctypes/test/test_stringptr.py -index c20951f4ce..fde0eef1c7 100644 ---- a/Lib/ctypes/test/test_stringptr.py -+++ b/Lib/ctypes/test/test_stringptr.py -@@ -1,10 +1,12 @@ -+import os - import unittest - from test import support - from ctypes import * - - import _ctypes_test - --lib = CDLL(_ctypes_test.__file__) ++ system = objc.objc_msgSend(systemName, SEL_UTF8String).decode() ++ release = objc.objc_msgSend(systemVersion, SEL_UTF8String).decode() ++ model = objc.objc_msgSend(systemModel, SEL_UTF8String).decode() + -+lib = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - - class StringPtrTestCase(unittest.TestCase): - -diff --git a/Lib/ctypes/test/test_unicode.py b/Lib/ctypes/test/test_unicode.py -index 60c75424b7..8c008b466b 100644 ---- a/Lib/ctypes/test/test_unicode.py -+++ b/Lib/ctypes/test/test_unicode.py -@@ -1,3 +1,4 @@ -+import os - import unittest - import ctypes - from ctypes.test import need_symbol -@@ -7,7 +8,7 @@ - @need_symbol('c_wchar') - class UnicodeTestCase(unittest.TestCase): - def test_wcslen(self): -- dll = ctypes.CDLL(_ctypes_test.__file__) -+ dll = ctypes.CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - wcslen = dll.my_wcslen - wcslen.argtypes = [ctypes.c_wchar_p] - -@@ -34,7 +35,7 @@ - t.unicode = "foo\0bar\0\0" - - --func = ctypes.CDLL(_ctypes_test.__file__)._testfunc_p_p -+func = ctypes.CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE']))._testfunc_p_p - - class StringTestCase(UnicodeTestCase): - def setUp(self): -diff --git a/Lib/ctypes/test/test_values.py b/Lib/ctypes/test/test_values.py -index 87eb9198ad..e40b82506f 100644 ---- a/Lib/ctypes/test/test_values.py -+++ b/Lib/ctypes/test/test_values.py -@@ -2,6 +2,7 @@ - A testcase which accesses *values* in a dll. - """ - -+import os - import unittest - import sys - from ctypes import * -@@ -13,7 +14,7 @@ - def test_an_integer(self): - # This test checks and changes an integer stored inside the - # _ctypes_test dll/shared lib. -- ctdll = CDLL(_ctypes_test.__file__) -+ ctdll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - an_integer = c_int.in_dll(ctdll, "an_integer") - x = an_integer.value - self.assertEqual(x, ctdll.get_an_integer()) -@@ -25,7 +26,7 @@ - self.assertEqual(x, ctdll.get_an_integer()) - - def test_undefined(self): -- ctdll = CDLL(_ctypes_test.__file__) -+ ctdll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - self.assertRaises(ValueError, c_int.in_dll, ctdll, "Undefined_Symbol") - - class PythonValuesTestCase(unittest.TestCase): -diff --git a/Lib/ctypes/test/test_win32.py b/Lib/ctypes/test/test_win32.py -index e51bdc8ad6..78ba8e6786 100644 ---- a/Lib/ctypes/test/test_win32.py -+++ b/Lib/ctypes/test/test_win32.py -@@ -1,6 +1,7 @@ - # Windows specific tests - - from ctypes import * -+import os - import unittest, sys - from test import support - -@@ -102,7 +103,7 @@ - ("right", c_long), - ("bottom", c_long)] - -- dll = CDLL(_ctypes_test.__file__) -+ dll = CDLL(getattr(_ctypes_test, '__file__', os.environ['TEST_EXECUTABLE'])) - - pt = POINT(15, 25) - left = c_long.in_dll(dll, 'left') ++ return system, release, model diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py index 0c2510e161..6c3c43f11d 100644 --- a/Lib/ctypes/util.py @@ -532,54 +51,77 @@ index 0c2510e161..6c3c43f11d 100644 def find_library(name): possible = ['lib%s.dylib' % name, diff --git a/Lib/distutils/tests/test_build_ext.py b/Lib/distutils/tests/test_build_ext.py -index 808c0dc287..b4813efe0c 100644 +index 808c0dc287..a7a7887f70 100644 --- a/Lib/distutils/tests/test_build_ext.py +++ b/Lib/distutils/tests/test_build_ext.py -@@ -52,6 +52,8 @@ +@@ -15,6 +15,7 @@ + + import unittest + from test import support ++from test.support import os_helper, has_subprocess_support + from test.support.script_helper import assert_python_ok + + # http://bugs.python.org/issue4373 +@@ -52,6 +53,7 @@ def build_ext(self, *args, **kwargs): return build_ext(*args, **kwargs) -+ @unittest.skipUnless(os.name == 'nt' or (os.name == 'posix' and hasattr(os, 'fork') and os.allows_subprocesses), -+ "distutils cannot spawn child processes") ++ @unittest.skipUnless(has_subprocess_support, "distutils cannot spawn child processes") def test_build_ext(self): cmd = support.missing_compiler_executable() if cmd is not None: -@@ -328,6 +330,8 @@ +@@ -328,6 +330,7 @@ cmd.run() self.assertEqual(cmd.compiler, 'unix') -+ @unittest.skipUnless(os.name == 'nt' or (os.name == 'posix' and hasattr(os, 'fork') and os.allows_subprocesses), -+ "distutils cannot spawn child processes") ++ @unittest.skipUnless(has_subprocess_support, "distutils cannot spawn child processes") def test_get_outputs(self): cmd = support.missing_compiler_executable() if cmd is not None: diff --git a/Lib/distutils/tests/test_build_py.py b/Lib/distutils/tests/test_build_py.py -index 0712e92c6a..52a0121250 100644 +index 0712e92c6a..4c05e8d968 100644 --- a/Lib/distutils/tests/test_build_py.py +++ b/Lib/distutils/tests/test_build_py.py -@@ -106,6 +106,8 @@ +@@ -9,7 +9,7 @@ + from distutils.errors import DistutilsFileError + + from distutils.tests import support +-from test.support import run_unittest ++from test.support import run_unittest, has_subprocess_support + + + class BuildPyTestCase(support.TempdirManager, +@@ -106,6 +106,7 @@ ['boiledeggs.%s.pyc' % sys.implementation.cache_tag]) @unittest.skipIf(sys.dont_write_bytecode, 'byte-compile disabled') -+ @unittest.skipUnless(os.name == 'nt' or (os.name == 'posix' and hasattr(os, 'fork') and os.allows_subprocesses), -+ "distutils cannot spawn child processes") ++ @unittest.skipUnless(has_subprocess_support, "distutils cannot spawn child processes") def test_byte_compile_optimized(self): project_dir, dist = self.create_dist(py_modules=['boiledeggs']) os.chdir(project_dir) diff --git a/Lib/distutils/tests/test_config_cmd.py b/Lib/distutils/tests/test_config_cmd.py -index 9aeab07b46..3c6dfc0439 100644 +index 9aeab07b46..a729c0907b 100644 --- a/Lib/distutils/tests/test_config_cmd.py +++ b/Lib/distutils/tests/test_config_cmd.py +@@ -2,7 +2,7 @@ + import unittest + import os + import sys +-from test.support import run_unittest, missing_compiler_executable ++from test.support import run_unittest, missing_compiler_executable, has_subprocess_support + + from distutils.command.config import dump_file, config + from distutils.tests import support @@ -38,6 +38,7 @@ self.assertEqual(len(self._logs), numlines+1) @unittest.skipIf(sys.platform == 'win32', "can't test on Windows") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_search_cpp(self): cmd = missing_compiler_executable(['preprocessor']) if cmd is not None: diff --git a/Lib/distutils/tests/test_cygwinccompiler.py b/Lib/distutils/tests/test_cygwinccompiler.py -index 9dc869de4c..176a87f8a8 100644 +index 9dc869de4c..9a1b18aba9 100644 --- a/Lib/distutils/tests/test_cygwinccompiler.py +++ b/Lib/distutils/tests/test_cygwinccompiler.py @@ -5,11 +5,14 @@ @@ -610,78 +152,108 @@ index 9dc869de4c..176a87f8a8 100644 class CygwinCCompilerTestCase(support.TempdirManager, unittest.TestCase): -@@ -118,7 +122,7 @@ - def test_get_msvcr(self): - - # none -- sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) ' -+ sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) ' - '\n[GCC 4.0.1 (Apple Computer, Inc. build 5370)]') - self.assertEqual(get_msvcr(), None) - diff --git a/Lib/distutils/tests/test_install.py b/Lib/distutils/tests/test_install.py -index 51c80e0421..11008da5f2 100644 +index 51c80e0421..57b50380fd 100644 --- a/Lib/distutils/tests/test_install.py +++ b/Lib/distutils/tests/test_install.py -@@ -197,6 +197,8 @@ +@@ -5,7 +5,7 @@ + import unittest + import site + +-from test.support import captured_stdout, run_unittest ++from test.support import captured_stdout, run_unittest, has_subprocess_support + + from distutils import sysconfig + from distutils.command.install import install +@@ -197,6 +197,7 @@ 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]] self.assertEqual(found, expected) -+ @unittest.skipUnless(os.name == 'nt' or (os.name == 'posix' and hasattr(os, 'fork') and os.allows_subprocesses), -+ "distutils cannot spawn child processes") ++ @unittest.skipUnless(has_subprocess_support, "distutils cannot spawn child processes") def test_record_extensions(self): cmd = test_support.missing_compiler_executable() if cmd is not None: diff --git a/Lib/distutils/tests/test_install_lib.py b/Lib/distutils/tests/test_install_lib.py -index fda6315bbc..63c71a8d46 100644 +index fda6315bbc..121664b722 100644 --- a/Lib/distutils/tests/test_install_lib.py +++ b/Lib/distutils/tests/test_install_lib.py -@@ -35,6 +35,8 @@ +@@ -8,7 +8,7 @@ + from distutils.extension import Extension + from distutils.tests import support + from distutils.errors import DistutilsOptionError +-from test.support import run_unittest ++from test.support import run_unittest, has_subprocess_support + + + class InstallLibTestCase(support.TempdirManager, +@@ -35,6 +35,7 @@ self.assertEqual(cmd.optimize, 2) @unittest.skipIf(sys.dont_write_bytecode, 'byte-compile disabled') -+ @unittest.skipUnless(os.name == 'nt' or (os.name == 'posix' and hasattr(os, 'fork') and os.allows_subprocesses), -+ "distutils cannot spawn child processes") ++ @unittest.skipUnless(has_subprocess_support, "distutils cannot spawn child processes") def test_byte_compile(self): project_dir, dist = self.create_dist() os.chdir(project_dir) diff --git a/Lib/distutils/tests/test_spawn.py b/Lib/distutils/tests/test_spawn.py -index ad5038142f..856afe86c1 100644 +index ad5038142f..62236514e2 100644 --- a/Lib/distutils/tests/test_spawn.py +++ b/Lib/distutils/tests/test_spawn.py -@@ -15,8 +15,8 @@ - support.LoggingSilencer, - unittest.TestCase): - -- @unittest.skipUnless(os.name in ('nt', 'posix'), -- 'Runs only under posix or nt') -+ @unittest.skipUnless(os.name == 'nt' or (os.name == 'posix' and hasattr(os, 'fork') and os.allows_subprocesses), -+ "distutils cannot spawn child processes") +@@ -3,7 +3,7 @@ + import stat + import sys + import unittest.mock +-from test.support import run_unittest, unix_shell ++from test.support import run_unittest, unix_shell, has_subprocess_support + from test import support as test_support + + from distutils.spawn import find_executable +@@ -17,6 +17,7 @@ + + @unittest.skipUnless(os.name in ('nt', 'posix'), + 'Runs only under posix or nt') ++ @unittest.skipUnless(has_subprocess_support, "distutils cannot spawn child processes") def test_spawn(self): tmpdir = self.mkdtemp() diff --git a/Lib/distutils/tests/test_sysconfig.py b/Lib/distutils/tests/test_sysconfig.py -index 236755d095..721bc91093 100644 +index 236755d095..a941290dc1 100644 --- a/Lib/distutils/tests/test_sysconfig.py +++ b/Lib/distutils/tests/test_sysconfig.py +@@ -10,7 +10,7 @@ + from distutils import sysconfig + from distutils.ccompiler import get_default_compiler + from distutils.tests import support +-from test.support import TESTFN, run_unittest, check_warnings, swap_item ++from test.support import TESTFN, run_unittest, check_warnings, swap_item, has_subprocess_support + + class SysconfigTestCase(support.EnvironGuard, unittest.TestCase): + def setUp(self): @@ -244,6 +244,7 @@ self.assertIsNotNone(vars['SO']) self.assertEqual(vars['SO'], vars['EXT_SUFFIX']) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_customize_compiler_before_get_config_vars(self): # Issue #21923: test that a Distribution compiler # instance can be called without an explicit call to diff --git a/Lib/distutils/tests/test_util.py b/Lib/distutils/tests/test_util.py -index bf0d4333f9..09ba51bcea 100644 +index bf0d4333f9..8a4ba3666a 100644 --- a/Lib/distutils/tests/test_util.py +++ b/Lib/distutils/tests/test_util.py -@@ -233,6 +233,8 @@ +@@ -3,7 +3,7 @@ + import sys + import unittest + from copy import copy +-from test.support import run_unittest ++from test.support import run_unittest, has_subprocess_support + from unittest import mock + + from distutils.errors import DistutilsPlatformError, DistutilsByteCompileError +@@ -233,6 +233,7 @@ # XXX platforms to be covered: mac -+ @unittest.skipUnless(os.name == 'nt' or (os.name == 'posix' and hasattr(os, 'fork') and os.allows_subprocesses), -+ "distutils cannot spawn child processes") ++ @unittest.skipUnless(has_subprocess_support, "distutils cannot spawn child processes") def test_check_environ(self): util._environ_checked = 0 os.environ.pop('HOME', None) @@ -698,85 +270,45 @@ index f3828b10e1..7e86539bfa 100644 _CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY + _CASE_INSENSITIVE_PLATFORMS_STR_KEY) -diff --git a/Lib/os.py b/Lib/os.py -index b794159f86..78aab1ea2a 100644 ---- a/Lib/os.py -+++ b/Lib/os.py -@@ -36,7 +36,7 @@ - __all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep", - "defpath", "name", "path", "devnull", "SEEK_SET", "SEEK_CUR", - "SEEK_END", "fsencode", "fsdecode", "get_exec_path", "fdopen", -- "popen", "extsep"] -+ "popen", "extsep", "allows_subprocesses"] - - def _exists(name): - return name in globals() -@@ -830,6 +830,13 @@ - fsencode, fsdecode = _fscodec() - del _fscodec - -+ -+if sys.platform in ('ios', 'tvos', 'watchos'): -+ allows_subprocesses = False -+else: -+ allows_subprocesses = True -+ -+ - # Supply spawn*() (probably only for Unix) - if _exists("fork") and not _exists("spawnv") and _exists("execv"): - diff --git a/Lib/platform.py b/Lib/platform.py -index d6412e169b..c1acaf19bc 100755 +index d6412e169b..3229a13a39 100755 --- a/Lib/platform.py +++ b/Lib/platform.py -@@ -449,6 +449,46 @@ +@@ -449,6 +449,33 @@ # If that also doesn't work return the default values return release, versioninfo, machine ++ +def iOS_ver(): + """ Get iOS/tvOS version information, and return it as a -+ tuple (system, release). All tuple entries are strings. -+ ++ tuple (system, release, model). All tuple entries are strings. + Equivalent of: -+ system = [[UIDevice currentDevice].model] UTF8String] ++ system = [[UIDevice currentDevice].systemName] UTF8String] + release = [[UIDevice currentDevice].systemVersion] UTF8String] -+ ++ model = [[UIDevice currentDevice].model] UTF8String] + """ -+ from ctypes import cast, cdll, c_void_p, c_char_p -+ from ctypes import util -+ objc = cdll.LoadLibrary(util.find_library(b'objc')) -+ uikit = cdll.LoadLibrary(util.find_library(b'UIKit')) -+ -+ 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)) -+ -+ # 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() ++ import _ios_support ++ return _ios_support.get_platform_ios() ++ ++def is_simulator(): ++ """Determine if the current platform is a device 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. ++ """ ++ if sys.platform in ('ios', 'tvos', 'watchos'): ++ return sys.implementation._multiarch.endswith('simulator') + -+ return system, release ++ # All other platforms aren't simulators. ++ return False + def _java_getprop(name, default): from java.lang import System -@@ -615,7 +655,7 @@ +@@ -615,7 +642,7 @@ default in case the command should fail. """ @@ -785,21 +317,47 @@ index d6412e169b..c1acaf19bc 100755 # XXX Others too ? return default -@@ -757,6 +797,13 @@ +@@ -757,6 +784,24 @@ csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0) return 'Alpha' if cpu_number >= 128 else 'VAX' -+ # iOS, tvOS and watchOS processor is the same as machine ++ # 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(): -+ return '' ++ if sys.implementation._multiarch.endswith('simulator'): ++ return os.uname().machine ++ return 'arm64' + -+ get_tvos = get_ios -+ get_watchos = get_ios ++ def get_tvos(): ++ if sys.implementation._multiarch.endswith('simulator'): ++ return os.uname().machine ++ return 'arm64' ++ ++ def get_watchos(): ++ if sys.implementation._multiarch.endswith('simulator'): ++ return os.uname().machine ++ return 'arm64_32' + def from_subprocess(): """ Fall back to `uname -p` -@@ -1216,11 +1263,14 @@ +@@ -904,6 +949,14 @@ + system = 'Windows' + release = 'Vista' + ++ # Normalize responses on Apple mobile platforms ++ if sys.platform in ('ios', 'tvos'): ++ system, release, model = iOS_ver() ++ # Simulator devices report as "arm64" or "x86_64"; ++ # use the model as the basis for the normalized machine name. ++ if sys.implementation._multiarch.endswith('simulator'): ++ machine = f'{model} Simulator' ++ + vals = system, node, release, version, machine + # Replace 'unknown' values with the more portable '' + _uname_cache = uname_result(*map(_unknown_as_blank, vals)) +@@ -1216,11 +1269,14 @@ system, release, version = system_alias(system, release, version) if system == 'Darwin': @@ -810,7 +368,7 @@ index d6412e169b..c1acaf19bc 100755 - release = macos_release + # macOS/iOS/tvOS/watchOS (darwin kernel) + if sys.platform in ('ios', 'tvos'): -+ system, release = iOS_ver() ++ system, release, model = iOS_ver() + else: + macos_release = mac_ver()[0] + if macos_release: @@ -834,20 +392,29 @@ index 9e617afb00..41305298d3 100644 return f'{userbase}/lib/python{version[0]}.{version[1]}/site-packages' diff --git a/Lib/subprocess.py b/Lib/subprocess.py -index 4effc1d8b3..b0e4a5acac 100644 +index 4effc1d8b3..0a96cd3a75 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py -@@ -762,6 +762,9 @@ +@@ -100,6 +100,8 @@ + "CREATE_NO_WINDOW", "DETACHED_PROCESS", + "CREATE_DEFAULT_ERROR_MODE", "CREATE_BREAKAWAY_FROM_JOB"]) + ++# Some platforms do not support processes ++_can_fork_exec = sys.platform not in {"ios", "tvos", "watchos"} + + # Exception classes used by this module. + class SubprocessError(Exception): pass +@@ -762,6 +764,9 @@ pass_fds=(), *, user=None, group=None, extra_groups=None, encoding=None, errors=None, text=None, umask=-1): """Create new Popen instance.""" -+ if not os.allows_subprocesses: ++ if not _can_fork_exec: + raise RuntimeError(f"Subprocesses are not supported on {sys.platform}") + _cleanup() # Held while anything is calling waitpid before returncode has been # updated to prevent clobbering returncode if wait() or poll() are -@@ -1834,7 +1837,7 @@ +@@ -1834,7 +1839,7 @@ else: self.returncode = waitstatus_to_exitcode(sts) @@ -856,7 +423,7 @@ index 4effc1d8b3..b0e4a5acac 100644 _WNOHANG=os.WNOHANG, _ECHILD=errno.ECHILD): """Check if child process has terminated. Returns returncode attribute. -@@ -1843,6 +1846,8 @@ +@@ -1843,6 +1848,8 @@ outside of the local scope (nor can any methods it calls). """ @@ -866,7 +433,7 @@ index 4effc1d8b3..b0e4a5acac 100644 if not self._waitpid_lock.acquire(False): # Something else is busy calling waitpid. Don't allow two diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py -index e3f79bfde5..2850eaeb5e 100644 +index e3f79bfde5..8c0d7908a9 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -84,6 +84,33 @@ @@ -924,11 +491,67 @@ index e3f79bfde5..2850eaeb5e 100644 return joinuser("~", ".local") +@@ -688,10 +722,16 @@ + if m: + 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, model = _ios_support.get_platform_ios() ++ 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 "%s-%s-%s" % (osname, release, machine) + diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py -index 86ac8f0966..0777ccc56d 100644 +index 6dc08135e0..5b268e98bc 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py -@@ -813,8 +813,8 @@ +@@ -56,7 +56,7 @@ + "check__all__", "skip_if_buggy_ucrt_strfptime", + "ignore_warnings", "check_sanitizer", "skip_if_sanitizer", + # sys +- "is_jython", "is_android", "check_impl_detail", "unix_shell", ++ "is_jython", "is_android", "is_apple_mobile", "check_impl_detail", "unix_shell", + "setswitchinterval", + # network + "open_urlresource", +@@ -743,11 +743,24 @@ + + is_android = hasattr(sys, 'getandroidapilevel') + +-if sys.platform != 'win32': ++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 + ++# 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_apple_mobile ++) ++ ++has_subprocess_support = ( ++ not is_apple_mobile ++) ++ + # Filename used for testing + if os.name == 'java': + # Jython disallows @ in module names +@@ -813,8 +826,8 @@ # TESTFN_UNICODE is a non-ascii filename TESTFN_UNICODE = TESTFN_ASCII + "-\xe0\xf2\u0258\u0141\u011f" @@ -939,7 +562,7 @@ index 86ac8f0966..0777ccc56d 100644 # decomposed Unicode, encoded using UTF-8. See QA1173: # http://developer.apple.com/mac/library/qa/qa2001/qa1173.html import unicodedata -@@ -840,8 +840,8 @@ +@@ -840,8 +853,8 @@ 'Unicode filename tests may not be effective' % (TESTFN_UNENCODABLE, TESTFN_ENCODING)) TESTFN_UNENCODABLE = None @@ -951,10 +574,10 @@ index 86ac8f0966..0777ccc56d 100644 # ascii and utf-8 cannot encode the byte 0xff b'\xff'.decode(TESTFN_ENCODING) diff --git a/Lib/test/support/script_helper.py b/Lib/test/support/script_helper.py -index 37e576d4a7..1d7176bf13 100644 +index 37e576d4a7..bb458f566b 100644 --- a/Lib/test/support/script_helper.py +++ b/Lib/test/support/script_helper.py -@@ -8,6 +8,7 @@ +@@ -8,15 +8,19 @@ import os.path import subprocess import py_compile @@ -962,203 +585,216 @@ index 37e576d4a7..1d7176bf13 100644 import zipfile from importlib.util import source_from_cache -@@ -17,6 +18,8 @@ ++from test.support import has_subprocess_support + from test.support import make_legacy_pyc + + # Cached result of the expensive test performed in the function below. __cached_interp_requires_environment = None + -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def interpreter_requires_environment(): """ Returns True if our sys.executable interpreter requires environment -@@ -136,6 +139,7 @@ +@@ -136,6 +140,7 @@ rc = proc.returncode return _PythonRunResult(rc, out, err), cmd_line -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def _assert_python(expected_success, /, *args, **env_vars): res, cmd_line = run_python_until_end(*args, **env_vars) if (res.rc and expected_success) or (not res.rc and not expected_success): -@@ -165,6 +169,8 @@ +@@ -165,6 +170,8 @@ """ return _assert_python(False, *args, **env_vars) + -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def spawn_python(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw): """Run a Python subprocess with the given arguments. diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py -index 72189bfd38..84940caf8a 100644 +index 72189bfd38..c5a5ce79da 100644 --- a/Lib/test/test_asyncio/test_events.py +++ b/Lib/test/test_asyncio/test_events.py -@@ -516,6 +516,8 @@ +@@ -32,6 +32,7 @@ + from asyncio import selector_events + from test.test_asyncio import utils as test_utils + from test import support ++from test.support import is_apple_mobile, has_subprocess_support + from test.support import socket_helper + from test.support import ALWAYS_EQ, LARGEST, SMALLEST + +@@ -516,6 +517,7 @@ self._basetest_create_connection(conn_fut) @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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. -@@ -608,6 +610,8 @@ +@@ -608,6 +610,7 @@ self.assertEqual(cm.exception.reason, 'CERTIFICATE_VERIFY_FAILED') @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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( -@@ -619,6 +623,8 @@ +@@ -619,6 +622,7 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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. -@@ -842,6 +848,8 @@ +@@ -842,6 +846,7 @@ return server, path @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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) -@@ -870,6 +878,8 @@ +@@ -870,6 +875,7 @@ server.close() @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets') -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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() -@@ -935,6 +945,8 @@ +@@ -935,6 +941,7 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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( -@@ -965,6 +977,8 @@ +@@ -965,6 +972,7 @@ server.close() @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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( -@@ -995,6 +1009,8 @@ +@@ -995,6 +1003,7 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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( -@@ -1055,6 +1071,8 @@ +@@ -1055,6 +1064,7 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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( -@@ -1714,6 +1732,7 @@ +@@ -1714,6 +1724,7 @@ next(it) -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') 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 38f4d84d47..1ed2ceb5ae 100644 +index 38f4d84d47..b6c725937c 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py -@@ -5,6 +5,7 @@ - import queue - import pickle - import socket -+import subprocess - import sys - import threading - import unittest -@@ -67,6 +68,8 @@ +@@ -17,6 +17,7 @@ + + import asyncio + from test.test_asyncio import utils as test_utils ++from test.support import is_apple_mobile, has_subprocess_support + + + def tearDownModule(): +@@ -67,6 +68,7 @@ self._basetest_open_connection(conn_fut) @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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, -@@ -101,6 +104,8 @@ +@@ -101,6 +103,7 @@ @socket_helper.skip_unless_bind_unix_socket @unittest.skipIf(ssl is None, 'No ssl module') -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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( -@@ -131,6 +136,8 @@ +@@ -131,6 +134,7 @@ self._basetest_open_connection_error(conn_fut) @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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, -@@ -656,6 +663,8 @@ +@@ -656,6 +660,7 @@ self.assertEqual(messages, []) @socket_helper.skip_unless_bind_unix_socket -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) def test_start_unix_server(self): class MyServer: -@@ -732,6 +741,7 @@ +@@ -732,6 +737,7 @@ self.assertEqual(messages, []) @unittest.skipIf(sys.platform == 'win32', "Don't have pipes") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') 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 3f6fc15b27..2633e04fc8 100644 +index 3f6fc15b27..9d8d43efbe 100644 --- a/Lib/test/test_asyncio/test_subprocess.py +++ b/Lib/test/test_asyncio/test_subprocess.py -@@ -103,6 +103,7 @@ +@@ -10,6 +10,7 @@ + from asyncio import subprocess + from test.test_asyncio import utils as test_utils + from test import support ++from test.support import has_subprocess_support + + if sys.platform != 'win32': + from asyncio import unix_events +@@ -103,6 +104,7 @@ transport.close() -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for 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 70d306ffe8..590dfc9fd4 100644 +index 70d306ffe8..1b0fcf631e 100644 --- a/Lib/test/test_asyncio/test_unix_events.py +++ b/Lib/test/test_asyncio/test_unix_events.py -@@ -267,6 +267,8 @@ +@@ -15,6 +15,7 @@ + import unittest + from unittest import mock + from test import support ++from test.support import is_apple_mobile, has_subprocess_support + from test.support import socket_helper + + if sys.platform == 'win32': +@@ -267,6 +268,7 @@ @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'UNIX Sockets are not supported') -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) class SelectorEventLoopUnixSocketTests(test_utils.TestCase): def setUp(self): @@ -1166,36 +802,43 @@ index 70d306ffe8..590dfc9fd4 100644 )) -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') class ChildWatcherTestsMixin: ignore_warnings = mock.patch.object(log.logger, "warning") diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py -index 1dbeac41dc..73e63d1c31 100644 +index 1dbeac41dc..94959a2534 100644 --- a/Lib/test/test_base64.py +++ b/Lib/test/test_base64.py -@@ -644,7 +644,7 @@ - def test_ErrorHeritage(self): +@@ -645,6 +645,7 @@ self.assertTrue(issubclass(binascii.Error, ValueError)) -- + +@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') class TestMain(unittest.TestCase): def tearDown(self): if os.path.exists(support.TESTFN): diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py -index 39b1b64651..f9c0614003 100644 +index 39b1b64651..e6552352e5 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py -@@ -54,6 +54,7 @@ +@@ -17,6 +17,7 @@ + import importlib.util + from test import support + from test.support import MISSING_C_DOCSTRINGS ++from test.support import has_subprocess_support + from test.support.script_helper import assert_python_failure, assert_python_ok + try: + import _posixsubprocess +@@ -54,6 +55,7 @@ self.assertEqual(testfunction.attribute, "test") self.assertRaises(AttributeError, setattr, inst.testfunction, "attribute", "test") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_no_FatalError_infinite_loop(self): with support.SuppressCrashReport(): p = subprocess.Popen([sys.executable, "-c", -@@ -720,6 +721,7 @@ +@@ -720,6 +722,7 @@ self.assertEqual(main_attr_id, subinterp_attr_id) @@ -1204,115 +847,126 @@ index 39b1b64651..f9c0614003 100644 @support.reap_threads diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py -index 4b3e33c4fd..3f15078807 100644 +index e38fc698c5..ae503199d1 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py -@@ -67,6 +67,7 @@ +@@ -9,6 +9,7 @@ + import textwrap + import unittest + from test import support ++from test.support import has_subprocess_support + from test.support.script_helper import ( + spawn_python, kill_python, assert_python_ok, assert_python_failure, + interpreter_requires_environment +@@ -67,6 +68,7 @@ rc, out, err = assert_python_ok('-vv') self.assertNotIn(b'stack overflow', err) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') @unittest.skipIf(interpreter_requires_environment(), 'Cannot run -E tests when PYTHON env vars are required.') def test_xoptions(self): -@@ -85,6 +86,7 @@ +@@ -85,6 +87,7 @@ opts = get_xoptions('-Xa', '-Xb=c,d=e') self.assertEqual(opts, {'a': True, 'b': 'c,d=e'}) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_showrefcount(self): def run_python(*args): # this is similar to assert_python_ok but doesn't strip -@@ -169,6 +171,7 @@ +@@ -169,6 +172,7 @@ # arguments as unicode (using wmain() instead of main()). @unittest.skipIf(sys.platform == 'win32', 'Windows has a native unicode API') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_undecodable_code(self): undecodable = b"\xff" env = os.environ.copy() -@@ -284,6 +287,7 @@ +@@ -284,6 +288,7 @@ 'False False False\n' 'False False True\n') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_unbuffered_output(self): # Test expected operation of the '-u' switch for stream in ('stdout', 'stderr'): -@@ -342,6 +346,7 @@ +@@ -342,6 +347,7 @@ # for empty and unset PYTHONPATH self.assertEqual(out1, out2) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_displayhook_unencodable(self): for encoding in ('ascii', 'latin-1', 'utf-8'): env = os.environ.copy() -@@ -360,6 +365,7 @@ +@@ -360,6 +366,7 @@ escaped = repr(text).encode(encoding, 'backslashreplace') self.assertIn(escaped, data) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def check_input(self, code, expected): with tempfile.NamedTemporaryFile("wb+") as stdin: sep = os.linesep.encode('ASCII') -@@ -435,6 +441,7 @@ +@@ -435,6 +442,7 @@ @unittest.skipIf(os.name != 'posix', "test needs POSIX semantics") @unittest.skipIf(sys.platform == "vxworks", "test needs preexec support in subprocess.Popen") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def _test_no_stdio(self, streams): code = """if 1: import os, sys -diff --git a/Lib/test/test_compileall.py b/Lib/test/test_compileall.py -index a904f426b1..40ac29c516 100644 ---- a/Lib/test/test_compileall.py -+++ b/Lib/test/test_compileall.py -@@ -219,7 +219,8 @@ - compileall.compile_dir(self.directory, quiet=True, workers=5) - self.assertTrue(pool_mock.called) - -- def test_compile_workers_non_positive(self): -+ @mock.patch('compileall.ProcessPoolExecutor') -+ def test_compile_workers_non_positive(self, pool_mock): - with self.assertRaisesRegex(ValueError, - "workers must be greater or equal to 0"): - compileall.compile_dir(self.directory, workers=-1) diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py -index d421b02754..cc1b1ce16a 100644 +index 2d27a294b1..a091f30929 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py -@@ -160,6 +160,7 @@ +@@ -5,7 +5,7 @@ + # Skip tests if sem_open implementation is broken. + support.skip_if_broken_multiprocessing_synchronize() + +-from test.support import hashlib_helper ++from test.support import hashlib_helper, has_subprocess_support + from test.support.script_helper import assert_python_ok + + import contextlib +@@ -151,6 +151,7 @@ executor_type = futures.ThreadPoolExecutor -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') class ProcessPoolForkMixin(ExecutorMixin): executor_type = futures.ProcessPoolExecutor ctx = "fork" -@@ -170,11 +171,13 @@ +@@ -161,11 +162,13 @@ return super().get_context() -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') class ProcessPoolSpawnMixin(ExecutorMixin): executor_type = futures.ProcessPoolExecutor ctx = "spawn" -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') class ProcessPoolForkserverMixin(ExecutorMixin): executor_type = futures.ProcessPoolExecutor ctx = "forkserver" diff --git a/Lib/test/test_doctest.py b/Lib/test/test_doctest.py -index dba19103e8..68e0d5cff9 100644 +index dba19103e8..d56399e18a 100644 --- a/Lib/test/test_doctest.py +++ b/Lib/test/test_doctest.py -@@ -2838,7 +2838,12 @@ +@@ -3,6 +3,7 @@ + """ + + from test import support ++from test.support import is_apple_mobile + import doctest + import functools + import os +@@ -2838,7 +2839,12 @@ TestResults(failed=1, attempted=1) """ -def test_CLI(): r""" -+if sys.platform in ('iOS', 'tvos', 'watchos'): ++if is_apple_mobile: + # Mobile platforms can't invoke doctest from the command line, + # so skip this test. + pass @@ -1322,34 +976,39 @@ index dba19103e8..68e0d5cff9 100644 These tests test this CLI functionality. diff --git a/Lib/test/test_eintr.py b/Lib/test/test_eintr.py -index a5f8f6465e..00287fea2b 100644 +index a5f8f6465e..e4366a1289 100644 --- a/Lib/test/test_eintr.py +++ b/Lib/test/test_eintr.py -@@ -9,6 +9,7 @@ +@@ -5,10 +5,11 @@ + import unittest + + from test import support +-from test.support import script_helper ++from test.support import script_helper, has_subprocess_support @unittest.skipUnless(os.name == "posix", "only supported on Unix") -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') class EINTRTests(unittest.TestCase): @unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()") diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py -index 2f8f5eec47..9629ef5226 100644 +index 2f8f5eec47..2d4f1456ff 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py -@@ -43,6 +43,7 @@ - finally: - support.unlink(filename) - -+ - class FaultHandlerTests(unittest.TestCase): - def get_output(self, code, filename=None, fd=None): - """ +@@ -6,6 +6,7 @@ + import subprocess + import sys + from test import support ++from test.support import has_subprocess_support + from test.support import script_helper, is_android + from test.support import skip_if_sanitizer + import tempfile @@ -342,6 +343,7 @@ finally: sys.stderr = orig_stderr -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_disabled_by_default(self): # By default, the module should be disabled code = "import faulthandler; print(faulthandler.is_enabled())" @@ -1357,7 +1016,7 @@ index 2f8f5eec47..9629ef5226 100644 output = subprocess.check_output(args) self.assertEqual(output.rstrip(), b"False") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_sys_xoptions(self): # Test python -X faulthandler code = "import faulthandler; print(faulthandler.is_enabled())" @@ -1365,45 +1024,71 @@ index 2f8f5eec47..9629ef5226 100644 output = subprocess.check_output(args, env=env) self.assertEqual(output.rstrip(), b"True") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_env_var(self): # empty env var code = "import faulthandler; print(faulthandler.is_enabled())" diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py -index 2a3209eb7d..fb27155fa4 100644 +index 2a3209eb7d..8e2a041f4b 100644 --- a/Lib/test/test_fcntl.py +++ b/Lib/test/test_fcntl.py +@@ -7,7 +7,7 @@ + import unittest + from multiprocessing import Process + from test.support import (verbose, TESTFN, unlink, import_module, +- cpython_only) ++ cpython_only, is_apple_mobile) + + # Skip test if no fcntl module. + fcntl = import_module('fcntl') @@ -23,7 +23,7 @@ start_len = "qq" if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd')) - or sys.platform == 'darwin'): -+ or sys.platform in ('darwin', 'ios', 'tvos', 'watchos')): ++ or sys.platform == 'darwin' or is_apple_mobile): if struct.calcsize('l') == 8: off_t = 'l' pid_t = 'i' diff --git a/Lib/test/test_file_eintr.py b/Lib/test/test_file_eintr.py -index f1efd266ff..db6d3ec5ad 100644 +index f1efd266ff..5a68c60cc2 100644 --- a/Lib/test/test_file_eintr.py +++ b/Lib/test/test_file_eintr.py -@@ -69,6 +69,7 @@ +@@ -15,6 +15,7 @@ + import sys + import time + import unittest ++from test.support import has_subprocess_support + + # Test import all of the things we're about to try testing up front. + import _io +@@ -69,6 +70,7 @@ self.fail('Error from IO process %s:\nSTDOUT:\n%sSTDERR:\n%s\n' % (why, stdout.decode(), stderr.decode())) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def _test_reading(self, data_to_write, read_and_verify_code): """Generic buffered read method test harness to validate EINTR behavior. diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py -index 3313804703..1e0cfc7324 100644 +index 3313804703..10415ed4b2 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py +@@ -3,7 +3,7 @@ + from test.support import (verbose, refcount_test, + cpython_only, start_threads, + temp_dir, TESTFN, unlink, +- import_module) ++ import_modul, has_subprocess_support) + from test.support.script_helper import assert_python_ok, make_script + + import gc @@ -680,6 +680,8 @@ del x gc.set_debug(%s) """ + -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def run_command(code): p = subprocess.Popen([sys.executable, "-Wd", "-c", code], stdout=subprocess.PIPE, @@ -1421,110 +1106,90 @@ index b3aa855a5b..3304cb9606 100644 # Regex to parse: # 'GNU gdb (GDB; SUSE Linux Enterprise 12) 7.7\n' -> 7.7 diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py -index c1494d29ca..e42244ccfe 100644 +index 4acf7a6fea..8f3de2f4cc 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py -@@ -398,7 +398,7 @@ +@@ -30,6 +30,8 @@ + + import unittest + from test import support ++from test.support import is_apple_mobile ++from test.support import has_subprocess_support + + + class NoLogRequestHandler: +@@ -398,7 +400,7 @@ with open(os.path.join(self.tempdir, filename), 'wb') as f: f.write(support.TESTFN_UNDECODABLE) response = self.request(self.base_url + '/') - if sys.platform == 'darwin': -+ if sys.platform in ('darwin', 'ios', 'tvos', 'watchos'): ++ 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. for name in os.listdir(self.tempdir): -@@ -608,6 +608,7 @@ +@@ -657,6 +659,7 @@ @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, "This test can't be run reliably as root (issue #13308).") -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') class CGIHTTPServerTestCase(BaseTestCase): class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler): pass -diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py -index fe394dc50c..6974ae7ea8 100644 ---- a/Lib/test/test_imp.py -+++ b/Lib/test/test_imp.py -@@ -18,7 +18,7 @@ - """Decorator to skip a test if not running under CPython or lacking - imp.load_dynamic().""" - meth = support.cpython_only(meth) -- return unittest.skipIf(not hasattr(imp, 'load_dynamic'), -+ return unittest.skipIf(not getattr(imp, 'load_dynamic'), - 'imp.load_dynamic() required')(meth) - - -diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py -index c9b4a3772c..1d87c8df65 100644 ---- a/Lib/test/test_importlib/extension/test_finder.py -+++ b/Lib/test/test_importlib/extension/test_finder.py -@@ -3,10 +3,13 @@ - - machinery = util.import_importlib('importlib.machinery') - -+import sys - import unittest - import warnings - - -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ '%s does not support dynamic loading' % sys.platform) - class FinderTests(abc.FinderTests): - - """Test the finder for extension modules.""" -diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py -index abd612fcd9..ebf7bc9aa5 100644 ---- a/Lib/test/test_importlib/extension/test_loader.py -+++ b/Lib/test/test_importlib/extension/test_loader.py -@@ -11,6 +11,8 @@ - import importlib - from test.support.script_helper import assert_python_failure - -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ '%s does not support dynamic loading' % sys.platform) - class LoaderTests(abc.LoaderTests): - - """Test load_module() for extension modules.""" -@@ -82,6 +84,9 @@ - Source_LoaderTests - ) = util.test_both(LoaderTests, machinery=machinery) - -+ -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ '%s does not support dynamic loading' % sys.platform) - class MultiPhaseExtensionModuleTests(abc.LoaderTests): - """Test loading extension modules with multi-phase initialization (PEP 489) - """ diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py -index feee861830..401b7ca493 100644 +index feee861830..5c2863acaf 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py +@@ -39,7 +39,7 @@ + from test import support + from test.support.script_helper import ( + assert_python_ok, assert_python_failure, run_python_until_end) +-from test.support import FakePath, skip_if_sanitizer ++from test.support import FakePath, skip_if_sanitizer, is_apple_mobile + + import codecs + import io # C implementation of io @@ -594,7 +594,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 in ('darwin', 'ios', 'tvos', 'watchos'): ++ 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_json/test_tool.py b/Lib/test/test_json/test_tool.py -index d441bb15a7..c3c7a052ba 100644 +index d441bb15a7..1e9ba2f3fe 100644 --- a/Lib/test/test_json/test_tool.py +++ b/Lib/test/test_json/test_tool.py -@@ -84,6 +84,7 @@ +@@ -6,6 +6,7 @@ + import subprocess + + from test import support ++from test.support import has_subprocess_support + from test.support.script_helper import assert_python_ok + + +@@ -84,6 +85,7 @@ } """) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_stdin_stdout(self): args = sys.executable, '-m', 'json.tool' process = subprocess.run(args, input=self.data, capture_output=True, text=True, check=True) diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py -index 0a9d449078..e58842a3fe 100644 +index 0a9d449078..af9395e33a 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py -@@ -1768,9 +1768,21 @@ +@@ -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 socket_helper + from test.support.logging_helper import TestHandler + import textwrap +@@ -1768,9 +1769,20 @@ # just need a name - file can't be present, or we'll get an # 'address already in use' error. os.remove(fn) @@ -1541,61 +1206,66 @@ index 0a9d449078..e58842a3fe 100644 return fn @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) class UnixSocketHandlerTest(SocketHandlerTest): """Test for SocketHandler with unix sockets.""" -@@ -1852,6 +1864,8 @@ +@@ -1852,6 +1864,7 @@ self.assertEqual(self.log_output, "spam\neggs\n") @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform) class UnixDatagramHandlerTest(DatagramHandlerTest): """Test for DatagramHandler using Unix sockets.""" -@@ -1936,6 +1950,8 @@ +@@ -1936,6 +1949,7 @@ self.assertEqual(self.log_output, b'<11>h\xc3\xa4m-sp\xc3\xa4m') @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required") -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@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_mailcap.py b/Lib/test/test_mailcap.py -index c08423c670..9673b07df3 100644 +index c08423c670..29b8ea06a3 100644 --- a/Lib/test/test_mailcap.py +++ b/Lib/test/test_mailcap.py -@@ -1,6 +1,7 @@ +@@ -1,8 +1,10 @@ import mailcap import os import copy +import sys import test.support import unittest ++from test.support import is_apple_mobile -@@ -212,7 +213,8 @@ + # Location of mailcap file + MAILCAPFILE = test.support.findfile("mailcap.txt") +@@ -212,7 +214,7 @@ ] self._run_cases(cases) - @unittest.skipUnless(os.name == "posix", "Requires 'test' command on system") -+ @unittest.skipUnless(os.name == "posix" and sys.platform not in('ios', 'tvos', 'watchos'), -+ "Requires 'test' command on system") ++ @unittest.skipUnless(os.name == "posix" and not is_apple_mobile, "Requires 'test' command on system") def test_test(self): # findmatch() will automatically check any "test" conditions and skip # the entry if the check fails. diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py -index ace1593999..69cc2cd06a 100644 +index ace1593999..2fa6603ed3 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py -@@ -240,7 +240,10 @@ +@@ -1,4 +1,5 @@ + from test import support ++from test.support import is_apple_mobile + import array + import io + import marshal +@@ -240,7 +241,10 @@ if os.name == 'nt': MAX_MARSHAL_STACK_DEPTH = 1000 else: - MAX_MARSHAL_STACK_DEPTH = 2000 -+ if sys.platform in ('ios', 'tvos', 'watchos'): ++ if is_apple_mobile: + MAX_MARSHAL_STACK_DEPTH = 1500 + else: + MAX_MARSHAL_STACK_DEPTH = 2000 @@ -1603,15 +1273,22 @@ index ace1593999..69cc2cd06a 100644 last.append([0]) last = last[-1] diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py -index 5400f25f50..5c7fb278ea 100644 +index 5400f25f50..c617345b2e 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py +@@ -1,5 +1,5 @@ + from test.support import (TESTFN, import_module, unlink, +- requires, _2G, _4G, gc_collect, cpython_only) ++ requires, _2G, _4G, gc_collect, cpython_only, is_apple_mobile) + import unittest + import os + import re @@ -230,7 +230,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 sys.platform not in ('iOS', 'tvos', 'watchos'): ++ 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, @@ -1620,229 +1297,282 @@ index 5400f25f50..5c7fb278ea 100644 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 in ('darwin', 'ios', 'tvos', 'watchos'): ++ 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_multiprocessing_fork.py b/Lib/test/test_multiprocessing_fork.py -index 5000edb7c5..5d1d2917bf 100644 +index 5000edb7c5..65a0fb67f9 100644 --- a/Lib/test/test_multiprocessing_fork.py +++ b/Lib/test/test_multiprocessing_fork.py @@ -1,4 +1,9 @@ -+import os import unittest ++from test.support import has_subprocess_support + -+if not os.allows_subprocesses: ++if not has_subprocess_support: + raise unittest.SkipTest('Test requires support for subprocesses.') + import test._test_multiprocessing import sys diff --git a/Lib/test/test_multiprocessing_forkserver.py b/Lib/test/test_multiprocessing_forkserver.py -index 6ad5faf9e8..4e05efb6df 100644 +index 6ad5faf9e8..a5285ef77a 100644 --- a/Lib/test/test_multiprocessing_forkserver.py +++ b/Lib/test/test_multiprocessing_forkserver.py @@ -1,4 +1,9 @@ -+import os import unittest ++from test.support import has_subprocess_support + -+if not os.allows_subprocesses: ++if not has_subprocess_support: + raise unittest.SkipTest('Test requires support for subprocesses.') + import test._test_multiprocessing import sys diff --git a/Lib/test/test_multiprocessing_spawn.py b/Lib/test/test_multiprocessing_spawn.py -index 6558952308..a121e8c2dd 100644 +index 6558952308..192096e2ac 100644 --- a/Lib/test/test_multiprocessing_spawn.py +++ b/Lib/test/test_multiprocessing_spawn.py @@ -1,4 +1,9 @@ -+import os import unittest ++from test.support import has_subprocess_support + -+if not os.allows_subprocesses: ++if not has_subprocess_support: + raise unittest.SkipTest('Test requires support for subprocesses.') + import test._test_multiprocessing from test import support diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py -index e48157a3de..6d856f31d6 100644 +index 78dd3151b3..cd6e6cbd83 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py -@@ -851,6 +851,7 @@ +@@ -31,6 +31,7 @@ + import uuid + import warnings + from test import support ++from test.support import has_subprocess_support + from test.support import socket_helper + from platform import win32_is_iot + +@@ -852,6 +853,7 @@ # Bug 1110478 @unittest.skipUnless(unix_shell and os.path.exists(unix_shell), 'requires a shell') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_update2(self): os.environ.clear() os.environ.update(HELLO="World") -@@ -860,6 +861,7 @@ +@@ -861,6 +863,7 @@ @unittest.skipUnless(unix_shell and os.path.exists(unix_shell), 'requires a shell') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_os_popen_iter(self): with os.popen("%s -c 'echo \"line1\nline2\nline3\"'" % unix_shell) as popen: -@@ -1811,6 +1813,7 @@ +@@ -1812,6 +1815,7 @@ @unittest.skipUnless(hasattr(os, 'execv'), "need os.execv()") -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') class ExecTests(unittest.TestCase): @unittest.skipIf(USING_LINUXTHREADS, "avoid triggering a linuxthreads bug: see issue #4970") -@@ -2132,6 +2135,7 @@ +@@ -2133,6 +2137,7 @@ self.assertRaises(OverflowError, os.setreuid, 0, self.UID_OVERFLOW) @unittest.skipUnless(hasattr(os, 'setreuid'), 'test needs os.setreuid()') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_setreuid_neg1(self): # Needs to accept -1. We run this in a subprocess to avoid # altering the test runner's process state (issue8045). -@@ -2140,6 +2144,7 @@ +@@ -2141,6 +2146,7 @@ 'import os,sys;os.setreuid(-1,-1);sys.exit(0)']) @unittest.skipUnless(hasattr(os, 'setregid'), 'test needs os.setregid()') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_setregid(self): if os.getuid() != 0 and not HAVE_WHEEL_GROUP: self.assertRaises(OSError, os.setregid, 0, 0) -@@ -2149,6 +2154,7 @@ +@@ -2150,6 +2156,7 @@ self.assertRaises(OverflowError, os.setregid, 0, self.GID_OVERFLOW) @unittest.skipUnless(hasattr(os, 'setregid'), 'test needs os.setregid()') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_setregid_neg1(self): # Needs to accept -1. We run this in a subprocess to avoid # altering the test runner's process state (issue8045). -@@ -2779,6 +2785,7 @@ +@@ -2822,6 +2829,7 @@ class PidTests(unittest.TestCase): @unittest.skipUnless(hasattr(os, 'getppid'), "test needs os.getppid") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_getppid(self): p = subprocess.Popen([sys.executable, '-c', 'import os; print(os.getppid())'], -@@ -2805,6 +2812,9 @@ +@@ -2848,6 +2856,7 @@ self.assertEqual(os.waitstatus_to_exitcode(status), exitcode) self.assertEqual(pid2, pid) -+ @unittest.skipUnless(hasattr(os, 'spawnv'), "test needs os.spawnv") -+ @unittest.skipUnless(hasattr(os, 'waitpid'), "test needs os.waitpid") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_waitpid(self): self.check_waitpid(code='pass', exitcode=0) -@@ -3474,6 +3484,7 @@ +@@ -3517,6 +3526,7 @@ self.assertGreaterEqual(size.columns, 0) self.assertGreaterEqual(size.lines, 0) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_stty_match(self): """Check if stty returns the same results diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py -index 58778300ee..a38a21dc99 100644 +index 58778300ee..7856be8429 100644 --- a/Lib/test/test_pdb.py +++ b/Lib/test/test_pdb.py -@@ -1293,6 +1293,7 @@ +@@ -14,6 +14,7 @@ + from contextlib import ExitStack, redirect_stdout + from io import StringIO + from test import support ++from test.support import has_subprocess_support + # This little helper class is essential for testing pdb under doctest. + from test.test_doctest import _FakeInput + from unittest.mock import patch +@@ -1293,6 +1294,7 @@ def tearDown(self): support.unlink(support.TESTFN) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def _run_pdb(self, pdb_args, commands): self.addCleanup(support.rmtree, '__pycache__') cmd = [sys.executable, '-m', 'pdb'] + pdb_args -@@ -1385,6 +1386,7 @@ +@@ -1385,6 +1387,7 @@ ('bÅ“r', 1), ) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_issue7964(self): # open the file as binary so we can force \r\n newline with open(support.TESTFN, 'wb') as f: diff --git a/Lib/test/test_pipes.py b/Lib/test/test_pipes.py -index 72e1cabab2..bd4da160e8 100644 +index 72e1cabab2..d62b516e5a 100644 --- a/Lib/test/test_pipes.py +++ b/Lib/test/test_pipes.py -@@ -1,12 +1,15 @@ +@@ -1,13 +1,17 @@ import pipes import os import string +import sys import unittest import shutil - from test.support import TESTFN, unlink, reap_children +-from test.support import TESTFN, unlink, reap_children ++from test.support import TESTFN, unlink, reap_children, is_apple_mobile if os.name != 'posix': raise unittest.SkipTest('pipes module only works on posix') -+if sys.platform in ('ios', 'tvos', 'watchos'): -+ raise unittest.SkipTest('pipes tests cannot run on %s' % sys.platform) ++if is_apple_mobile: ++ raise unittest.SkipTest('pipes tests cannot run on %s' % sys.platform) ++ TESTFN2 = TESTFN + "2" + # tr a-z A-Z is not portable, so make the ranges explicit diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py -index 9f04c79e09..8c92a660ed 100644 +index 9f04c79e09..ab2c1e507a 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py -@@ -9,7 +9,6 @@ +@@ -8,7 +8,7 @@ + from unittest import mock from test import support - - ++from test.support import has_subprocess_support, is_apple_mobile + class PlatformTest(unittest.TestCase): def clear_caches(self): - platform._platform_cache.clear() -@@ -20,6 +19,7 @@ +@@ -20,6 +20,7 @@ res = platform.architecture() @support.skip_unless_symlink -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_architecture_via_symlink(self): # issue3762 with support.PythonSymlink() as py: cmd = "-c", "import platform; print(platform.architecture())" -@@ -254,7 +254,7 @@ +@@ -254,7 +255,7 @@ def test_mac_ver(self): res = platform.mac_ver() - if platform.uname().system == 'Darwin': -+ if platform.uname().system == 'Darwin' and sys.platform not in ('ios', 'tvos', 'watchos'): ++ 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) +@@ -286,6 +287,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): diff --git a/Lib/test/test_poll.py b/Lib/test/test_poll.py -index 294131da79..a675153295 100644 +index 294131da79..c74979d9a7 100644 --- a/Lib/test/test_poll.py +++ b/Lib/test/test_poll.py +@@ -7,7 +7,7 @@ + import threading + import time + import unittest +-from test.support import TESTFN, reap_threads, cpython_only ++from test.support import TESTFN, reap_threads, cpython_only, has_subprocess_support + + try: + select.poll @@ -117,6 +117,7 @@ # Another test case for poll(). This is copied from the test case for # select(), modified to use poll() instead. -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_poll2(self): cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 1; done' proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, diff --git a/Lib/test/test_popen.py b/Lib/test/test_popen.py -index ab1bc77655..60be660d25 100644 +index ab1bc77655..c5850faddc 100644 --- a/Lib/test/test_popen.py +++ b/Lib/test/test_popen.py -@@ -16,6 +16,8 @@ +@@ -5,6 +5,7 @@ + + import unittest + from test import support ++from test.support import has_subprocess_support + import os, sys + + # Test that command-lines get down as we expect. +@@ -16,6 +17,7 @@ if ' ' in python: python = '"' + python + '"' # quote embedded space for cmdline -+ -+@unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++@unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') class PopenTest(unittest.TestCase): def _do_test_commandline(self, cmdline, expected): diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py -index a8db30679a..135af71f62 100644 +index 6ba14547bd..8ed2d7441d 100644 --- a/Lib/test/test_posix.py +++ b/Lib/test/test_posix.py -@@ -61,15 +61,21 @@ +@@ -1,6 +1,8 @@ + "Test posix functions" + + from test import support ++from test.support import has_subprocess_support ++from test.support import is_apple_mobile + from test.support.script_helper import assert_python_ok + + # Skip these tests if there is no posix module. +@@ -61,15 +63,22 @@ # no side-effects which we need to cleanup (e.g., fork, wait, abort) NO_ARG_FUNCTIONS = [ "ctermid", "getcwd", "getcwdb", "uname", "times", "getloadavg", @@ -1851,7 +1581,8 @@ index a8db30679a..135af71f62 100644 "getpid", "getpgrp", "getppid", "getuid", "sync", ] -+ if sys.platform not in ('ios', 'tvos', 'watchos'): ++ # getgroups can't be invoked on iOS/tvOS/watchOS. ++ if is_apple_mobile: + NO_ARG_FUNCTIONS.append("getgroups") + for name in NO_ARG_FUNCTIONS: @@ -1867,313 +1598,317 @@ index a8db30679a..135af71f62 100644 @unittest.skipUnless(hasattr(posix, 'getresuid'), 'test needs posix.getresuid()') -@@ -745,9 +751,10 @@ +@@ -745,9 +754,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 sys.platform not in ('ios', 'tvos', 'watchos'): ++ 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) -@@ -1020,6 +1027,7 @@ - os.chdir(curdir) - support.rmtree(base_path) - -+ - @unittest.skipUnless(hasattr(posix, 'getgrouplist'), "test needs posix.getgrouplist()") - @unittest.skipUnless(hasattr(pwd, 'getpwuid'), "test needs pwd.getpwuid()") - @unittest.skipUnless(hasattr(os, 'getuid'), "test needs os.getuid()") -@@ -1028,8 +1036,8 @@ +@@ -1028,8 +1038,8 @@ group = pwd.getpwuid(os.getuid())[3] self.assertIn(group, posix.getgrouplist(user, group)) - @unittest.skipUnless(hasattr(os, 'getegid'), "test needs os.getegid()") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_getgroups(self): with os.popen('id -G 2>/dev/null') as idg: groups = idg.read().strip() -@@ -1088,7 +1096,7 @@ +@@ -1088,7 +1098,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 not in ('darwin', 'ios', 'tvos', 'watchos'): ++ 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) diff --git a/Lib/test/test_pty.py b/Lib/test/test_pty.py -index 9c32467cbb..ce273f0b4d 100644 +index 9c32467cbb..89d266b27e 100644 --- a/Lib/test/test_pty.py +++ b/Lib/test/test_pty.py +@@ -1,4 +1,4 @@ +-from test.support import verbose, import_module, reap_children ++from test.support import verbose, import_module, reap_children, has_subprocess_support + + # Skip these tests if termios is not available + import_module('termios') @@ -138,6 +138,7 @@ # to ignore this signal. os.close(master_fd) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_fork(self): debug("calling pty.fork()") pid, master_fd = pty.fork() diff --git a/Lib/test/test_quopri.py b/Lib/test/test_quopri.py -index 715544c8a9..6e66178816 100644 +index 715544c8a9..0641b2fcef 100644 --- a/Lib/test/test_quopri.py +++ b/Lib/test/test_quopri.py -@@ -180,6 +180,7 @@ +@@ -1,4 +1,5 @@ + import unittest ++from test.support import has_subprocess_support + + import sys, io, subprocess + import quopri +@@ -180,6 +181,7 @@ for p, e in self.HSTRINGS: self.assertEqual(quopri.decodestring(e, header=True), p) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_scriptencode(self): (p, e) = self.STRINGS[-1] process = subprocess.Popen([sys.executable, "-mquopri"], -@@ -196,6 +197,7 @@ +@@ -196,6 +198,7 @@ self.assertEqual(cout[i], e[i]) self.assertEqual(cout, e) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_scriptdecode(self): (p, e) = self.STRINGS[-1] process = subprocess.Popen([sys.executable, "-mquopri", "-d"], diff --git a/Lib/test/test_script_helper.py b/Lib/test/test_script_helper.py -index 4ade2cbc0d..83ce283a04 100644 +index 4ade2cbc0d..63175fcc13 100644 --- a/Lib/test/test_script_helper.py +++ b/Lib/test/test_script_helper.py -@@ -1,5 +1,6 @@ - """Unittests for test.support.script_helper. Who tests the test helper?""" - -+import os +@@ -3,7 +3,7 @@ import subprocess import sys import os -@@ -35,6 +36,7 @@ +-from test.support import script_helper ++from test.support import script_helper, has_subprocess_support + import unittest + from unittest import mock + +@@ -35,6 +35,7 @@ self.assertIn('import sys; sys.exit(0)', error_msg, msg='unexpected command line.') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') @mock.patch('subprocess.Popen') def test_assert_python_isolated_when_env_not_required(self, mock_popen): with mock.patch.object(script_helper, -@@ -53,6 +55,7 @@ +@@ -53,6 +54,7 @@ self.assertIn('-I', popen_command) self.assertNotIn('-E', popen_command) # -I overrides this -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') @mock.patch('subprocess.Popen') def test_assert_python_not_isolated_when_env_is_required(self, mock_popen): """Ensure that -I is not passed when the environment is required.""" -@@ -82,6 +85,7 @@ +@@ -82,6 +84,7 @@ # Reset the private cached state. script_helper.__dict__['__cached_interp_requires_environment'] = None -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') @mock.patch('subprocess.check_call') def test_interpreter_requires_environment_true(self, mock_check_call): with mock.patch.dict(os.environ): -@@ -91,6 +95,7 @@ +@@ -91,6 +94,7 @@ self.assertTrue(script_helper.interpreter_requires_environment()) self.assertEqual(1, mock_check_call.call_count) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') @mock.patch('subprocess.check_call') def test_interpreter_requires_environment_false(self, mock_check_call): with mock.patch.dict(os.environ): -@@ -100,6 +105,7 @@ +@@ -100,6 +104,7 @@ self.assertFalse(script_helper.interpreter_requires_environment()) self.assertEqual(1, mock_check_call.call_count) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') @mock.patch('subprocess.check_call') def test_interpreter_requires_environment_details(self, mock_check_call): with mock.patch.dict(os.environ): diff --git a/Lib/test/test_select.py b/Lib/test/test_select.py -index 458998a62f..577cf5f385 100644 +index 458998a62f..607c533e12 100644 --- a/Lib/test/test_select.py +++ b/Lib/test/test_select.py -@@ -5,7 +5,8 @@ +@@ -4,6 +4,7 @@ + import sys import unittest from test import support ++from test.support import has_subprocess_support --@unittest.skipIf((sys.platform[:3]=='win'), -+ -+@unittest.skipIf((sys.platform[:3] == 'win'), + @unittest.skipIf((sys.platform[:3]=='win'), "can't easily test on this system") - class SelectTestCase(unittest.TestCase): - @@ -44,6 +45,7 @@ self.assertIsNot(r, x) self.assertIsNot(w, x) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_select(self): cmd = 'for i in 0 1 2 3 4 5 6 7 8 9; do echo testing...; sleep 1; done' with os.popen(cmd) as p: diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py -index 3890df93bb..663c5d1908 100644 +index 3890df93bb..8c84a05794 100644 --- a/Lib/test/test_shutil.py +++ b/Lib/test/test_shutil.py -@@ -1731,6 +1731,8 @@ +@@ -30,7 +30,7 @@ + posix = None + + from test import support +-from test.support import TESTFN, FakePath ++from test.support import TESTFN, FakePath, has_subprocess_support + + TESTFN2 = TESTFN + "2" + TESTFN_SRC = TESTFN + "_SRC" +@@ -1731,6 +1731,7 @@ check_chown(dirname, uid, gid) -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't support other executable." % sys.platform) ++@unittest.skipIf(support.has_subprocess_support, 'Test requires support for subprocesses.') class TestWhich(BaseTest, unittest.TestCase): def setUp(self): -@@ -2598,6 +2600,7 @@ +@@ -2598,6 +2599,7 @@ self.assertGreaterEqual(size.lines, 0) @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') @unittest.skipUnless(hasattr(os, 'get_terminal_size'), 'need os.get_terminal_size()') def test_stty_match(self): diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py -index 3d25d7e473..3f9859a90f 100644 +index 3d25d7e473..4ea33b64c9 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py -@@ -200,6 +200,7 @@ +@@ -7,6 +7,7 @@ + import unittest + import test.support + from test import support ++from test.support import has_subprocess_support + from test.support import socket_helper + from test.support import (captured_stderr, TESTFN, EnvironmentVarGuard, + change_cwd) +@@ -200,6 +201,7 @@ @unittest.skipUnless(site.ENABLE_USER_SITE, "requires access to PEP 370 " "user-site (site.ENABLE_USER_SITE)") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_s_option(self): # (ncoghlan) Change this to use script_helper... usersite = site.USER_SITE -@@ -474,6 +475,7 @@ +@@ -474,6 +476,7 @@ class StartupImportTests(unittest.TestCase): -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_startup_imports(self): # Get sys.path in isolated mode (python3 -I) popen = subprocess.Popen([sys.executable, '-I', '-c', diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py -index 5712b46f7f..769c66e5ac 100755 +index 127d61cb6a..c182b83edc 100755 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py -@@ -1030,6 +1030,12 @@ - with self.assertRaises(OSError, msg=explanation): - socket.gethostbyaddr(addr) - -+ @unittest.skipUnless(socket.has_ipv6, "test needs IPv6 support") -+ def test_host_resolution_ipv6(self): -+ for addr in ['::1q', '::1::2', '1:1:1:1:1:1:1:1:1']: -+ self.assertRaises(OSError, socket.gethostbyname, addr) -+ self.assertRaises(OSError, socket.gethostbyaddr, addr) -+ - @unittest.skipUnless(hasattr(socket, 'sethostname'), "test needs socket.sethostname()") - @unittest.skipUnless(hasattr(socket, 'gethostname'), "test needs socket.gethostname()") - def test_sethostname(self): -@@ -1143,7 +1149,7 @@ +@@ -1,5 +1,6 @@ + import unittest + from test import support ++from test.support import is_apple_mobile + from test.support import socket_helper + + import errno +@@ -1143,7 +1144,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', 'ios', 'tvos', 'watchos')): ++ 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') -@@ -3496,7 +3502,8 @@ +@@ -3496,7 +3497,7 @@ def _testFDPassCMSG_LEN(self): self.createAndSendFDs(1) - @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") -+ @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), -+ "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): -@@ -3507,7 +3514,8 @@ +@@ -3507,7 +3508,7 @@ maxcmsgs=2) @testFDPassSeparate.client_skip - @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") -+ @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), -+ "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) -@@ -3520,7 +3528,8 @@ +@@ -3520,7 +3521,7 @@ array.array("i", [fd1]))]), len(MSG)) - @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") -+ @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), -+ "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): -@@ -3534,7 +3543,8 @@ +@@ -3534,7 +3535,7 @@ maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC) @testFDPassSeparateMinSpace.client_skip - @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958") -+ @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), -+ "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) -@@ -3558,7 +3568,8 @@ +@@ -3558,7 +3559,7 @@ nbytes = self.sendmsgToServer([msg]) self.assertEqual(nbytes, len(msg)) - @unittest.skipIf(sys.platform == "darwin", "see issue #24725") -+ @unittest.skipIf(sys.platform in ("darwin", 'iOS', 'tvos', 'watchos'), -+ "skipping, see issue #12958") ++ @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. -@@ -4378,28 +4389,38 @@ +@@ -4378,28 +4379,33 @@ pass @requireAttrs(socket.socket, "sendmsg") -+@unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@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(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@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(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@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(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@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(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++@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 c9455adfd8..3ada09dcba 100644 +index c9455adfd8..a06d325d1e 100644 --- a/Lib/test/test_socketserver.py +++ b/Lib/test/test_socketserver.py -@@ -8,6 +8,7 @@ +@@ -8,13 +8,14 @@ import select import signal import socket @@ -2181,53 +1916,90 @@ index c9455adfd8..3ada09dcba 100644 import tempfile import threading import unittest + import socketserver + + import test.support +-from test.support import reap_children, reap_threads, verbose ++from test.support import reap_children, reap_threads, verbose, has_subprocess_support, is_apple_mobile + from test.support import socket_helper + + @@ -26,7 +27,7 @@ HAVE_UNIX_SOCKETS = hasattr(socket, "AF_UNIX") requires_unix_sockets = unittest.skipUnless(HAVE_UNIX_SOCKETS, 'requires Unix sockets') -HAVE_FORKING = hasattr(os, "fork") -+HAVE_FORKING = hasattr(os, "fork") and os.allows_subprocesses ++HAVE_FORKING = hasattr(os, "fork") and has_subprocess_support requires_forking = unittest.skipUnless(HAVE_FORKING, 'requires forking') def signal_alarm(n): -@@ -194,12 +195,16 @@ +@@ -194,12 +195,14 @@ self.stream_examine) @requires_unix_sockets -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't fully support UNIX sockets." % sys.platform) ++ @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_source_encoding.py b/Lib/test/test_source_encoding.py -index 5ca43461d9..1a66b1d258 100644 +index 5ca43461d9..2841c401a5 100644 --- a/Lib/test/test_source_encoding.py +++ b/Lib/test/test_source_encoding.py +@@ -1,7 +1,7 @@ + # -*- coding: koi8-r -*- + + import unittest +-from test.support import TESTFN, unlink, unload, rmtree, script_helper, captured_stdout ++from test.support import TESTFN, unlink, unload, rmtree, script_helper, captured_stdout, has_subprocess_support + import importlib + import os + import sys +@@ -12,11 +12,11 @@ + + def test_pep263(self): + self.assertEqual( +- "ðÉÔÏÎ".encode("utf-8"), ++ "�����".encode("utf-8"), + b'\xd0\x9f\xd0\xb8\xd1\x82\xd0\xbe\xd0\xbd' + ) + self.assertEqual( +- "\ð".encode("utf-8"), ++ "\�".encode("utf-8"), + b'\\\xd0\x9f' + ) + @@ -63,6 +63,7 @@ # two bytes in common with the UTF-8 BOM self.assertRaises(SyntaxError, eval, b'\xef\xbb\x20') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_20731(self): sub = subprocess.Popen([sys.executable, os.path.join(os.path.dirname(__file__), diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py -index f93fbe9264..ef16d62332 100644 +index f93fbe9264..a917f229cf 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py -@@ -42,6 +42,9 @@ +@@ -21,6 +21,7 @@ + import textwrap + import json + import pathlib ++from test.support import has_subprocess_support + from test.support import FakePath + + try: +@@ -42,6 +43,9 @@ mswindows = (sys.platform == "win32") -+if not os.allows_subprocesses: ++if not has_subprocess_support: + raise unittest.SkipTest('Test requires support for subprocesses.') + # @@ -2248,53 +2020,62 @@ index 2accad1aee..4824b6c8d0 100644 import distutils.text_file import distutils.unixccompiler diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py -index 2f1e5e971e..ef31d7a033 100644 +index ef32424eab..22a8914261 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py -@@ -108,6 +108,7 @@ - # Python/pythonrun.c::PyErr_PrintEx() is tricky. - - -+ - class SysModuleTest(unittest.TestCase): - - def tearDown(self): -@@ -551,6 +552,7 @@ +@@ -11,6 +11,7 @@ + import sys + import sysconfig + import test.support ++from test.support import has_subprocess_support + import textwrap + import unittest + import warnings +@@ -558,6 +559,7 @@ def test_clear_type_cache(self): sys._clear_type_cache() -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_ioencoding(self): env = dict(os.environ) -@@ -598,6 +600,7 @@ +@@ -605,6 +607,7 @@ 'requires OS support of non-ASCII encodings') @unittest.skipUnless(sys.getfilesystemencoding() == locale.getpreferredencoding(False), 'requires FS encoding to match locale') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_ioencoding_nonascii(self): env = dict(os.environ) -@@ -610,6 +613,7 @@ +@@ -617,6 +620,7 @@ @unittest.skipIf(sys.base_prefix != sys.prefix, 'Test is not venv-compatible') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_executable(self): # sys.executable should be absolute self.assertEqual(os.path.abspath(sys.executable), sys.executable) -@@ -644,6 +648,7 @@ +@@ -651,6 +655,7 @@ expected = None self.check_fsencoding(fs_encoding, expected) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def c_locale_get_error_handler(self, locale, isolated=False, encoding=None): # Force the POSIX locale env = os.environ.copy() diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py -index 0ca5c9390d..32430b41eb 100644 +index 0ca5c9390d..eca8dad7c7 100644 --- a/Lib/test/test_sysconfig.py +++ b/Lib/test/test_sysconfig.py +@@ -7,7 +7,7 @@ + + from test.support import (import_module, TESTFN, unlink, check_warnings, + captured_stdout, skip_unless_symlink, change_cwd, +- PythonSymlink) ++ PythonSymlink, has_subprocess_support) + + import sysconfig + from sysconfig import (get_paths, get_platform, get_config_vars, @@ -229,10 +229,12 @@ def test_get_scheme_names(self): @@ -2305,84 +2086,96 @@ index 0ca5c9390d..32430b41eb 100644 self.assertEqual(get_scheme_names(), wanted) @skip_unless_symlink -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_symlink(self): # Issue 7880 with PythonSymlink() as py: cmd = "-c", "import sysconfig; print(sysconfig.get_platform())" diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py -index 8ad1bb98e8..5bd5413dc9 100644 +index 8ad1bb98e8..eedc7fcf21 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py -@@ -19,7 +19,7 @@ +@@ -15,11 +15,12 @@ + + import unittest + from test import support ++from test_support import has_subprocess_support + from test.support import script_helper has_textmode = (tempfile._text_openflags != tempfile._bin_openflags) -has_spawnl = hasattr(os, 'spawnl') -+has_spawnl = hasattr(os, 'spawnl') and os.allows_subprocesses ++has_spawnl = hasattr(os, 'spawnl') and has_subprocess_support # TEST_FILES may need to be tweaked for systems depending on the maximum # number of files that can be opened at one time (see ulimit -n) diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py -index af480b9014..79fdf54e72 100644 +index af480b9014..a088feb7e9 100644 --- a/Lib/test/test_threading.py +++ b/Lib/test/test_threading.py -@@ -1028,6 +1028,8 @@ +@@ -3,7 +3,7 @@ + """ + + import test.support +-from test.support import verbose, import_module, cpython_only, unlink ++from test.support import verbose, import_module, cpython_only, unlink, is_apple_mobile + from test.support.script_helper import assert_python_ok, assert_python_failure + + import random +@@ -1028,6 +1028,7 @@ os.set_blocking(r, False) return (r, w) -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't have os.pipe" % sys.platform) ++ @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) -@@ -1056,6 +1058,8 @@ +@@ -1056,6 +1057,7 @@ # The thread was joined properly. self.assertEqual(os.read(r, 1), b"x") -+ @unittest.skipIf(sys.platform in ('ios', 'tvos', 'watchos'), -+ "%s doesn't have os.pipe" % sys.platform) ++ @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_traceback.py b/Lib/test/test_traceback.py -index c0b3388b2d..00f72730b3 100644 +index c0b3388b2d..68ffd3d669 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py -@@ -5,7 +5,9 @@ - import linecache - import sys +@@ -7,7 +7,7 @@ import unittest -+import os import re -+import subprocess from test import support - from test.support import TESTFN, Error, captured_output, unlink, cpython_only, ALWAYS_EQ +-from test.support import TESTFN, Error, captured_output, unlink, cpython_only, ALWAYS_EQ ++from test.support import TESTFN, Error, captured_output, unlink, cpython_only, ALWAYS_EQ, has_subprocess_support from test.support.script_helper import assert_python_ok -@@ -142,6 +144,7 @@ + import textwrap + +@@ -142,6 +142,7 @@ str_name = '.'.join([X.__module__, X.__qualname__]) self.assertEqual(err[0], "%s: %s\n" % (str_name, str_value)) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_encoded_file(self): # Test that tracebacks are correctly printed for encoded source files: # - correct line number (Issue2384) diff --git a/Lib/test/test_unicodedata.py b/Lib/test/test_unicodedata.py -index edfd860fd5..edbc8ce641 100644 +index edfd860fd5..e3bc801a8f 100644 --- a/Lib/test/test_unicodedata.py +++ b/Lib/test/test_unicodedata.py -@@ -8,6 +8,7 @@ - - import hashlib - from http.client import HTTPException -+import os +@@ -11,7 +11,7 @@ import sys import unicodedata import unittest -@@ -225,6 +226,7 @@ +-from test.support import open_urlresource, requires_resource, script_helper ++from test.support import open_urlresource, requires_resource, script_helper, has_subprocess_support + + + class UnicodeMethodsTest(unittest.TestCase): +@@ -225,6 +225,7 @@ class UnicodeMiscTest(UnicodeDatabaseTest): -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_failed_import_during_compiling(self): # Issue 4367 # Decoding \N escapes requires the unicodedata module. If it can't be @@ -2418,97 +2211,115 @@ index ba4c500e8e..1534b59cef 100644 redirect_url_with_frag = "http://www.pythontest.net/redir/with_frag/" with socket_helper.transient_internet(redirect_url_with_frag): diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py -index b1c92427dd..5141c9dece 100644 +index b1c92427dd..925a1f0354 100644 --- a/Lib/test/test_uuid.py +++ b/Lib/test/test_uuid.py -@@ -639,6 +639,7 @@ +@@ -1,5 +1,6 @@ + import unittest + from test import support ++from test.support import has_subprocess_support + import builtins + import contextlib + import copy +@@ -639,6 +640,7 @@ equal(str(u), v) @unittest.skipUnless(os.name == 'posix', 'requires Posix') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def testIssue8621(self): # On at least some versions of OSX self.uuid.uuid4 generates # the same sequence of UUIDs in the parent and any -@@ -824,6 +825,7 @@ +@@ -824,6 +826,7 @@ @unittest.skipUnless(_uuid._ifconfig_getnode in _uuid._GETTERS, "ifconfig is not used for introspection on this platform") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_ifconfig_getnode(self): node = self.uuid._ifconfig_getnode() self.check_node(node, 'ifconfig') -@@ -836,6 +838,7 @@ +@@ -836,6 +839,7 @@ @unittest.skipUnless(_uuid._arp_getnode in _uuid._GETTERS, "arp is not used for introspection on this platform") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_arp_getnode(self): node = self.uuid._arp_getnode() self.check_node(node, 'arp') -@@ -848,6 +851,7 @@ +@@ -848,6 +852,7 @@ @unittest.skipUnless(_uuid._netstat_getnode in _uuid._GETTERS, "netstat is not used for introspection on this platform") -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_netstat_getnode(self): node = self.uuid._netstat_getnode() self.check_node(node, 'netstat') diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py -index 480cb29f35..b1c4d2014f 100644 +index 480cb29f35..1a63f66028 100644 --- a/Lib/test/test_venv.py +++ b/Lib/test/test_venv.py -@@ -179,6 +179,7 @@ +@@ -16,8 +16,7 @@ + import tempfile + from test.support import (captured_stdout, captured_stderr, requires_zlib, + can_symlink, EnvironmentVarGuard, rmtree, +- import_module, +- skip_if_broken_multiprocessing_synchronize) ++ skip_if_broken_multiprocessing_synchronize, has_subprocess_support) + import unittest + import venv + from unittest.mock import patch +@@ -179,6 +178,7 @@ builder.upgrade_dependencies(fake_context) @requireVenvCreate -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_prefixes(self): """ Test that the prefix values are as expected. -@@ -316,6 +317,7 @@ +@@ -316,6 +316,7 @@ # point to the venv being used to run the test, and we lose the link # to the source build - so Python can't initialise properly. @requireVenvCreate -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_executable(self): """ Test that the sys.executable value is as expected. -@@ -329,6 +331,7 @@ +@@ -329,6 +330,7 @@ self.assertEqual(out.strip(), envpy.encode()) @unittest.skipUnless(can_symlink(), 'Needs symlinks') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_executable_symlinks(self): """ Test that the sys.executable value is as expected. -@@ -414,6 +417,7 @@ +@@ -414,6 +416,7 @@ @requireVenvCreate class EnsurePipTest(BaseTest): """Test venv module installation of pip.""" -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def assert_pip_not_installed(self): envpy = os.path.join(os.path.realpath(self.env_dir), self.bindir, self.exe) -@@ -538,6 +542,7 @@ +@@ -538,6 +541,7 @@ # Issue #26610: pip/pep425tags.py requires ctypes @unittest.skipUnless(ctypes, 'pip requires ctypes') -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') @requires_zlib() def test_with_pip(self): self.do_test_with_pip(False) diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py -index 519a9432ab..63008a88fe 100644 +index 519a9432ab..1a2ff78ca7 100644 --- a/Lib/test/test_webbrowser.py +++ b/Lib/test/test_webbrowser.py -@@ -4,8 +4,11 @@ +@@ -4,8 +4,12 @@ import sys import subprocess from unittest import mock +import sys from test import support ++from test.support import is_apple_mobile -+if sys.platform in ('ios', 'tvos', 'watchos'): ++if is_apple_mobile: + raise unittest.SkipTest("Can't run webbrowser tests on %s" % sys.platform) URL = 'http://www.example.com' @@ -2534,14 +2345,22 @@ index bd383d3f68..f5c830e610 100644 import test packagedir = os.path.dirname(test.__file__) diff --git a/Lib/unittest/test/test_runner.py b/Lib/unittest/test/test_runner.py -index 453e6c3d11..7f4ece1ace 100644 +index 453e6c3d11..dd9880f1d8 100644 --- a/Lib/unittest/test/test_runner.py +++ b/Lib/unittest/test/test_runner.py -@@ -1135,6 +1135,7 @@ +@@ -9,6 +9,7 @@ + + from unittest.test.support import (LoggingResult, + ResultWithNoStartTestRunStopTestRun) ++from test.support import has_subprocess_support + + + def resultFactory(*_): +@@ -1135,6 +1136,7 @@ expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY) self.assertEqual(runner._makeResult(), expectedresult) -+ @unittest.skipUnless(os.allows_subprocesses, 'Test requires support for subprocesses.') ++ @unittest.skipUnless(has_subprocess_support, 'Test requires support for subprocesses.') def test_warnings(self): """ Check that warnings argument of TextTestRunner correctly affects the @@ -2607,6 +2426,19 @@ index 6023c1e138..ae5803c4c8 100755 # # Platform support for Windows +diff --git a/Makefile.pre.in b/Makefile.pre.in +index c0272bfcdd..81e09ad4ec 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -301,6 +301,8 @@ + ########################################################################## + + LIBFFI_INCLUDEDIR= @LIBFFI_INCLUDEDIR@ ++LIBFFI_LIBDIR= @LIBFFI_LIBDIR@ ++LIBFFI_LIB=@LIBFFI_LIB@ + + ########################################################################## + # Parser diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c index d64e0a1cfa..38770238b2 100644 --- a/Modules/_posixsubprocess.c @@ -2664,50 +2496,6 @@ index 16f98ace3b..0d7e276ff2 100644 /* Using an alternative stack requires sigaltstack() and sigaction() SA_ONSTACK */ #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION) -diff --git a/Modules/makesetup b/Modules/makesetup -index 1a767838c9..708c65b25f 100755 ---- a/Modules/makesetup -+++ b/Modules/makesetup -@@ -133,7 +133,7 @@ - - # Output DEFS in reverse order so first definition overrides - case $line in -- *=*) DEFS="$line$NL$DEFS"; continue;; -+ [A-Z]*=*) DEFS="$line$NL$DEFS"; continue;; - 'include '*) DEFS="$line$NL$DEFS"; continue;; - '*noobjects*') - case $noobjects in -@@ -162,9 +162,12 @@ - esac - case $arg in - -framework) libs="$libs $arg"; skip=libs; -- # OSX/OSXS/Darwin framework link cmd -+ # OSX/iOS/Darwin framework - ;; -- -[IDUCfF]*) cpps="$cpps $arg";; -+ -F*) libs="$libs $arg"; skip=libs; -+ # OSX/iOS/Darwin framework directory -+ ;; -+ -[IDUCf]*) cpps="$cpps $arg";; - -Xcompiler) skip=cpps;; - -Xlinker) libs="$libs $arg"; skip=libs;; - -rpath) libs="$libs $arg"; skip=libs;; -@@ -182,6 +185,7 @@ - *.c++) srcs="$srcs $arg";; - *.cxx) srcs="$srcs $arg";; - *.cpp) srcs="$srcs $arg";; -+ *.S) srcs="$srcs $arg";; - \$*) libs="$libs $arg" - cpps="$cpps $arg";; - *.*) echo 1>&2 "bad word $arg in $line" -@@ -219,6 +223,7 @@ - *.C) obj=`basename $src .C`.o; cc='$(CXX)';; - *.cxx) obj=`basename $src .cxx`.o; cc='$(CXX)';; - *.cpp) obj=`basename $src .cpp`.o; cc='$(CXX)';; -+ *.S) obj=`basename $src .S`.o; cc='$(CC)';; # Assembly - *.m) obj=`basename $src .m`.o; cc='$(CC)';; # Obj-C - *) continue;; - esac diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c index 1f16849a3e..a7b16eadc9 100644 --- a/Modules/mathmodule.c @@ -2724,7 +2512,7 @@ index 1f16849a3e..a7b16eadc9 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 29d61268e1..0ae93041e3 100644 +index 1270af735e..bd0dd2f385 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -57,6 +57,8 @@ @@ -2852,7 +2640,7 @@ index 29d61268e1..0ae93041e3 100644 return d; } -@@ -4818,7 +4849,12 @@ +@@ -4828,7 +4859,12 @@ } Py_BEGIN_ALLOW_THREADS @@ -2865,7 +2653,7 @@ index 29d61268e1..0ae93041e3 100644 Py_END_ALLOW_THREADS return result; } -@@ -13424,6 +13460,7 @@ +@@ -13434,6 +13470,7 @@ int is_symlink; int need_stat; #endif @@ -2873,7 +2661,7 @@ index 29d61268e1..0ae93041e3 100644 #ifdef MS_WINDOWS unsigned long dir_bits; #endif -@@ -13484,6 +13521,7 @@ +@@ -13494,6 +13531,7 @@ #endif return result; @@ -3042,1625 +2830,55 @@ index baafa3ecfb..496ef9cf58 100644 #endif #define TYPE_NULL '0' ---- /dev/null -+++ b/Tools/iOS-test/app/iOS-test/main.py -@@ -0,0 +1,12 @@ -+from datetime import datetime -+import platform -+from test import regrtest -+ -+regrtest.start = datetime.now() -+print("Testing on %s" % platform.machine()) -+print("START:", regrtest.start) -+regrtest.main_in_temp_cwd() -+regrtest.end = datetime.now() -+print("END:", regrtest.end) -+print("Duration:", regrtest.end - regrtest.start) -+ ---- /dev/null -+++ b/Tools/iOS-test/app_packages/README -@@ -0,0 +1 @@ -+This directory exists so that 3rd party packages can be installed here. -\ No newline at end of file ---- /dev/null -+++ b/Tools/iOS-test/iOS-test.xcodeproj/project.pbxproj -@@ -0,0 +1,369 @@ -+// !$*UTF8*$! -+{ -+ archiveVersion = 1; -+ classes = { -+ }; -+ objectVersion = 46; -+ objects = { -+ -+/* Begin PBXBuildFile section */ -+ 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE519190F4100A9926B /* Foundation.framework */; }; -+ 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE719190F4100A9926B /* CoreGraphics.framework */; }; -+ 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE919190F4100A9926B /* UIKit.framework */; }; -+ 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60796EEE19190F4100A9926B /* InfoPlist.strings */; }; -+ 60796EF219190F4100A9926B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 60796EF119190F4100A9926B /* main.m */; }; -+ 60796EF819190F4100A9926B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60796EF719190F4100A9926B /* Images.xcassets */; }; -+ 60796F2C1919C70800A9926B /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F2B1919C70800A9926B /* Python.framework */; }; -+ 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F38191CDBBA00A9926B /* CoreFoundation.framework */; }; -+ 60EAF0931C26F7310003B8F5 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 60EAF0921C26F7310003B8F5 /* libsqlite3.tbd */; }; -+ 60EAF0951C26F73D0003B8F5 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 60EAF0941C26F73D0003B8F5 /* libz.tbd */; }; -+/* End PBXBuildFile section */ -+ -+/* Begin PBXFileReference section */ -+ 60796EE219190F4100A9926B /* iOS-test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS-test.app"; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 60796EE519190F4100A9926B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; -+ 60796EE719190F4100A9926B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; -+ 60796EE919190F4100A9926B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; -+ 60796EED19190F4100A9926B /* iOS-test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "iOS-test-Info.plist"; sourceTree = ""; }; -+ 60796EEF19190F4100A9926B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; -+ 60796EF119190F4100A9926B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; -+ 60796EF319190F4100A9926B /* iOS-test-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "iOS-test-Prefix.pch"; sourceTree = ""; }; -+ 60796EF719190F4100A9926B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; -+ 60796F2B1919C70800A9926B /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; -+ 60796F38191CDBBA00A9926B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; -+ 60DBD4B01B47DEF700068095 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = SOURCE_ROOT; }; -+ 60EAF0921C26F7310003B8F5 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; -+ 60EAF0941C26F73D0003B8F5 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; -+ 60F0BABF191FC868006EC268 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = SOURCE_ROOT; }; -+/* End PBXFileReference section */ -+ -+/* Begin PBXFrameworksBuildPhase section */ -+ 60796EDF19190F4100A9926B /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60EAF0951C26F73D0003B8F5 /* libz.tbd in Frameworks */, -+ 60EAF0931C26F7310003B8F5 /* libsqlite3.tbd in Frameworks */, -+ 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */, -+ 60796F2C1919C70800A9926B /* Python.framework in Frameworks */, -+ 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */, -+ 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */, -+ 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXFrameworksBuildPhase section */ -+ -+/* Begin PBXGroup section */ -+ 60796ED919190F4100A9926B = { -+ isa = PBXGroup; -+ children = ( -+ 60796EEB19190F4100A9926B /* iOS-test */, -+ 60796EE419190F4100A9926B /* Frameworks */, -+ 60796EE319190F4100A9926B /* Products */, -+ ); -+ sourceTree = ""; -+ }; -+ 60796EE319190F4100A9926B /* Products */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796EE219190F4100A9926B /* iOS-test.app */, -+ ); -+ name = Products; -+ sourceTree = ""; -+ }; -+ 60796EE419190F4100A9926B /* Frameworks */ = { -+ isa = PBXGroup; -+ children = ( -+ 60EAF0941C26F73D0003B8F5 /* libz.tbd */, -+ 60EAF0921C26F7310003B8F5 /* libsqlite3.tbd */, -+ 60796F2B1919C70800A9926B /* Python.framework */, -+ 60796EE519190F4100A9926B /* Foundation.framework */, -+ 60796F38191CDBBA00A9926B /* CoreFoundation.framework */, -+ 60796EE719190F4100A9926B /* CoreGraphics.framework */, -+ 60796EE919190F4100A9926B /* UIKit.framework */, -+ ); -+ name = Frameworks; -+ sourceTree = ""; -+ }; -+ 60796EEB19190F4100A9926B /* iOS-test */ = { -+ isa = PBXGroup; -+ children = ( -+ 60DBD4B01B47DEF700068095 /* app */, -+ 60F0BABF191FC868006EC268 /* app_packages */, -+ 60796EF719190F4100A9926B /* Images.xcassets */, -+ 60796EEC19190F4100A9926B /* Supporting Files */, -+ ); -+ path = "iOS-test"; -+ sourceTree = ""; -+ }; -+ 60796EEC19190F4100A9926B /* Supporting Files */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796EED19190F4100A9926B /* iOS-test-Info.plist */, -+ 60796EEE19190F4100A9926B /* InfoPlist.strings */, -+ 60796EF119190F4100A9926B /* main.m */, -+ 60796EF319190F4100A9926B /* iOS-test-Prefix.pch */, -+ ); -+ name = "Supporting Files"; -+ sourceTree = ""; -+ }; -+/* End PBXGroup section */ -+ -+/* Begin PBXNativeTarget section */ -+ 60796EE119190F4100A9926B /* iOS-test */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "iOS-test" */; -+ buildPhases = ( -+ 60796F2F1919C7E700A9926B /* Refresh Python source */, -+ 60796EDE19190F4100A9926B /* Sources */, -+ 60796EDF19190F4100A9926B /* Frameworks */, -+ 60796EE019190F4100A9926B /* Resources */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ ); -+ name = "iOS-test"; -+ productName = "iOS-test"; -+ productReference = 60796EE219190F4100A9926B /* iOS-test.app */; -+ productType = "com.apple.product-type.application"; -+ }; -+/* End PBXNativeTarget section */ -+ -+/* Begin PBXProject section */ -+ 60796EDA19190F4100A9926B /* Project object */ = { -+ isa = PBXProject; -+ attributes = { -+ CLASSPREFIX = Py; -+ LastUpgradeCheck = 0720; -+ ORGANIZATIONNAME = "Python Software Foundation"; -+ TargetAttributes = { -+ 60796EE119190F4100A9926B = { -+ DevelopmentTeam = 383DLEZ2K4; -+ }; -+ }; -+ }; -+ buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "iOS-test" */; -+ compatibilityVersion = "Xcode 3.2"; -+ developmentRegion = English; -+ hasScannedForEncodings = 0; -+ knownRegions = ( -+ en, -+ ); -+ mainGroup = 60796ED919190F4100A9926B; -+ productRefGroup = 60796EE319190F4100A9926B /* Products */; -+ projectDirPath = ""; -+ projectRoot = ""; -+ targets = ( -+ 60796EE119190F4100A9926B /* iOS-test */, -+ ); -+ }; -+/* End PBXProject section */ -+ -+/* Begin PBXResourcesBuildPhase section */ -+ 60796EE019190F4100A9926B /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */, -+ 60796EF819190F4100A9926B /* Images.xcassets in Resources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXResourcesBuildPhase section */ -+ -+/* Begin PBXShellScriptBuildPhase section */ -+ 60796F2F1919C7E700A9926B /* Refresh Python source */ = { -+ isa = PBXShellScriptBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Refresh Python source"; -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nmkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/lib $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/include $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app_packages/ $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\n"; -+ }; -+/* End PBXShellScriptBuildPhase section */ -+ -+/* Begin PBXSourcesBuildPhase section */ -+ 60796EDE19190F4100A9926B /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796EF219190F4100A9926B /* main.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXSourcesBuildPhase section */ -+ -+/* Begin PBXVariantGroup section */ -+ 60796EEE19190F4100A9926B /* InfoPlist.strings */ = { -+ isa = PBXVariantGroup; -+ children = ( -+ 60796EEF19190F4100A9926B /* en */, -+ ); -+ name = InfoPlist.strings; -+ sourceTree = ""; -+ }; -+/* End PBXVariantGroup section */ -+ -+/* Begin XCBuildConfiguration section */ -+ 60796F0C19190F4100A9926B /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ COPY_PHASE_STRIP = NO; -+ ENABLE_BITCODE = NO; -+ ENABLE_TESTABILITY = YES; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ GCC_DYNAMIC_NO_PIC = NO; -+ GCC_OPTIMIZATION_LEVEL = 0; -+ GCC_PREPROCESSOR_DEFINITIONS = ( -+ "DEBUG=1", -+ "$(inherited)", -+ ); -+ GCC_SYMBOLS_PRIVATE_EXTERN = NO; -+ 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 = 7.1; -+ ONLY_ACTIVE_ARCH = YES; -+ SDKROOT = iphoneos; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ }; -+ name = Debug; -+ }; -+ 60796F0D19190F4100A9926B /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ COPY_PHASE_STRIP = YES; -+ ENABLE_BITCODE = NO; -+ ENABLE_NS_ASSERTIONS = NO; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ 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 = 7.1; -+ SDKROOT = iphoneos; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ VALIDATE_PRODUCT = YES; -+ }; -+ name = Release; -+ }; -+ 60796F0F19190F4100A9926B /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ CODE_SIGN_IDENTITY = "iPhone Developer"; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ GCC_PRECOMPILE_PREFIX_HEADER = YES; -+ GCC_PREFIX_HEADER = "iOS-test/iOS-test-Prefix.pch"; -+ HEADER_SEARCH_PATHS = ( -+ "$(inherited)", -+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, -+ "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", -+ ); -+ INFOPLIST_FILE = "iOS-test/iOS-test-Info.plist"; -+ PRODUCT_BUNDLE_IDENTIFIER = "org.python.$(PRODUCT_NAME:rfc1034identifier)"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ PROVISIONING_PROFILE = ""; -+ USER_HEADER_SEARCH_PATHS = include/python2.7; -+ WRAPPER_EXTENSION = app; -+ }; -+ name = Debug; -+ }; -+ 60796F1019190F4100A9926B /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ CODE_SIGN_IDENTITY = "iPhone Developer"; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ GCC_PRECOMPILE_PREFIX_HEADER = YES; -+ GCC_PREFIX_HEADER = "iOS-test/iOS-test-Prefix.pch"; -+ HEADER_SEARCH_PATHS = ( -+ "$(inherited)", -+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, -+ "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", -+ ); -+ INFOPLIST_FILE = "iOS-test/iOS-test-Info.plist"; -+ PRODUCT_BUNDLE_IDENTIFIER = "org.python.$(PRODUCT_NAME:rfc1034identifier)"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ PROVISIONING_PROFILE = ""; -+ USER_HEADER_SEARCH_PATHS = include/python2.7; -+ WRAPPER_EXTENSION = app; -+ }; -+ name = Release; -+ }; -+/* End XCBuildConfiguration section */ -+ -+/* Begin XCConfigurationList section */ -+ 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "iOS-test" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 60796F0C19190F4100A9926B /* Debug */, -+ 60796F0D19190F4100A9926B /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "iOS-test" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 60796F0F19190F4100A9926B /* Debug */, -+ 60796F1019190F4100A9926B /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+/* End XCConfigurationList section */ -+ }; -+ rootObject = 60796EDA19190F4100A9926B /* Project object */; -+} ---- /dev/null -+++ b/Tools/iOS-test/iOS-test/Images.xcassets/AppIcon.appiconset/Contents.json -@@ -0,0 +1,58 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "iphone", -+ "size" : "29x29", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "40x40", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "60x60", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "60x60", -+ "scale" : "3x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "29x29", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "29x29", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "40x40", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "40x40", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "76x76", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "76x76", -+ "scale" : "2x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/iOS-test/iOS-test/Images.xcassets/LaunchImage.launchimage/Contents.json -@@ -0,0 +1,51 @@ -+{ -+ "images" : [ -+ { -+ "orientation" : "portrait", -+ "idiom" : "iphone", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "iphone", -+ "subtype" : "retina4", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "1x" -+ }, -+ { -+ "orientation" : "landscape", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "1x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "landscape", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/iOS-test/iOS-test/en.lproj/InfoPlist.strings -@@ -0,0 +1 @@ -+/* Localized versions of Info.plist keys */ ---- /dev/null -+++ b/Tools/iOS-test/iOS-test/iOS-test-Info.plist -@@ -0,0 +1,45 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ en -+ CFBundleDisplayName -+ ${PRODUCT_NAME} -+ CFBundleExecutable -+ ${EXECUTABLE_NAME} -+ CFBundleIdentifier -+ $(PRODUCT_BUNDLE_IDENTIFIER) -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundleName -+ ${PRODUCT_NAME} -+ CFBundlePackageType -+ APPL -+ CFBundleShortVersionString -+ 1.0 -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ 1.0 -+ LSRequiresIPhoneOS -+ -+ UIRequiredDeviceCapabilities -+ -+ armv7 -+ -+ UISupportedInterfaceOrientations -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ UISupportedInterfaceOrientations~ipad -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationPortraitUpsideDown -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ -+ ---- /dev/null -+++ b/Tools/iOS-test/iOS-test/iOS-test-Prefix.pch -@@ -0,0 +1,16 @@ -+// -+// Prefix header -+// -+// The contents of this file are implicitly included at the beginning of every source file. -+// -+ -+#import -+ -+#ifndef __IPHONE_3_0 -+#warning "This project uses features only available in iOS SDK 3.0 and later." -+#endif -+ -+#ifdef __OBJC__ -+ #import -+ #import -+#endif -\ No newline at end of file ---- /dev/null -+++ b/Tools/iOS-test/iOS-test/main.m -@@ -0,0 +1,149 @@ -+// -+// main.m -+// A main module for starting Python projects under iOS. -+// -+ -+#import -+#import -+#include -+#include -+ -+int main(int argc, char *argv[]) { -+ int ret = 0; -+ unsigned int i; -+ NSString *tmp_path; -+ NSString *exe; -+ NSString *python_home; -+ wchar_t *wpython_home; -+ const char* main_script; -+ wchar_t** python_argv; -+ @autoreleasepool { -+ -+ NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; -+ -+ // Special environment to avoid writing bytecode because -+ // the process will not have write attribute on the device. -+ putenv("PYTHONDONTWRITEBYTECODE=1"); -+ -+ python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; -+ NSLog(@"PythonHome is: %@", python_home); -+ wpython_home = Py_DecodeLocale([python_home UTF8String], NULL); -+ Py_SetPythonHome(wpython_home); -+ -+ // iOS provides a specific directory for temp files. -+ tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; -+ putenv((char *)[tmp_path UTF8String]); -+ -+ // Since iOS doesn't allow dynamic linking, we have to know -+ // the name of the executable so that we can find the ctypes -+ // test objects. However, sys.argv[0] will be updated to -+ // reflect the script name; the TEST_EXECUTABLE environment -+ // variable provides the mechanism for specifying the filename. -+ exe = [NSString stringWithFormat:@"TEST_EXECUTABLE=%s", argv[0], nil]; -+ putenv((char *)[exe UTF8String]); -+ -+ NSLog(@"Initializing Python runtime..."); -+ Py_Initialize(); -+ -+ /******************************************************* -+ To tell lldb not to stop on signals, use the following commands: -+ process handle SIGPIPE -n true -p true -s false -+ process handle SIGINT -n true -p true -s false -+ process handle SIGXFSZ -n true -p true -s false -+ process handle SIGUSR1 -n true -p true -s false -+ process handle SIGUSR2 -n true -p true -s false -+ *******************************************************/ -+ -+ // Arguments to pass to test runner -+ char *test_args[] = { -+ "-j", "1", -+ "-u", "all,-audio,-curses,-largefile,-subprocess,-gui", -+// "-v", // Verbose test output -+ "-W", // Display test output on failure -+ -+ "-x", // Arguments are tests to *exclude* -+// Simulator failures -+// "test_coroutines", // docstring not being populated -+// "test_module", // docstring not being populated -+ -+// ARM64 failures -+// "test_coroutines", // docstring not being populated -+// "test_ctypes", // DL loading? -+// "test_module" // docstring not being populated -+// "test_threading", // ctypes related; missing symbol PyThreadState_SetAsyncExc -+// "test_unicode", // encoding problem -+ -+// ARMv7 failures -+// "test_cmath", // math domain error -+// "test_ctypes", // DL loading? -+// "test_float", // rounding? -+// "test_math", // math domain error -+// "test_numeric_tower", // -+// "test_strtod", // -+// "test_importlib", // Thread locking problem -+// "test_threading", // ctypes related; missing symbol PyThreadState_SetAsyncExc -+ -+// COMMON FAILURES -+ "test_bytes" // HARD CRASH ctypes related; PyBytes_FromFormat -+ -+ }; -+ -+ // Set the name of the main script -+ main_script = [ -+ [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.iOS-test/app/iOS-test/main" -+ ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; -+ -+ if (main_script == NULL) { -+ NSLog(@"Unable to locate app/iOS-test/main.py file"); -+ exit(-1); -+ } -+ -+ // Construct argv for the interpreter -+ int n_test_args = sizeof(test_args) / sizeof (*test_args) + 1; -+ -+ python_argv = PyMem_RawMalloc(sizeof(wchar_t*) * n_test_args); -+ python_argv[0] = Py_DecodeLocale(main_script, NULL); -+ for (i = 1; i < n_test_args; i++) { -+ python_argv[i] = Py_DecodeLocale(test_args[i-1], NULL); -+ } -+ -+ PySys_SetArgv(n_test_args, python_argv); -+ -+ // If other modules are using thread, we need to initialize them before. -+ PyEval_InitThreads(); -+ -+ // Start the main.py script -+ NSLog(@"Running %s", main_script); -+ -+ @try { -+ FILE* fd = fopen(main_script, "r"); -+ if (fd == NULL) { -+ ret = 1; -+ NSLog(@"Unable to open main.py, abort."); -+ } else { -+ ret = PyRun_SimpleFileEx(fd, main_script, 1); -+ if (ret != 0) { -+ NSLog(@"Application quit abnormally!"); -+ } -+ } -+ } -+ @catch (NSException *exception) { -+ NSLog(@"Python runtime error: %@", [exception reason]); -+ } -+ @finally { -+ Py_Finalize(); -+ } -+ -+ PyMem_RawFree(wpython_home); -+ if (python_argv) { -+ for (i = 0; i < argc; i++) { -+ PyMem_RawFree(python_argv[i]); -+ } -+ PyMem_RawFree(python_argv); -+ } -+ NSLog(@"Leaving"); -+ } -+ -+ exit(ret); -+ return ret; -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/app/README -@@ -0,0 +1,3 @@ -+Your application code should be placed in this directory. -+ -+The native code will be looking for a tvOS-test/__main__.py file as the entry point. -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/app/tvOS-test/main.py -@@ -0,0 +1,14 @@ -+from __future__ import print_function -+ -+from datetime import datetime -+import platform -+from test import regrtest -+ -+regrtest.start = datetime.now() -+print("Testing on %s" % platform.machine()) -+print("START:", regrtest.start) -+regrtest.main_in_temp_cwd() -+regrtest.end = datetime.now() -+print("END:", regrtest.end) -+print("Duration:", regrtest.end - regrtest.start) -+ ---- /dev/null -+++ b/Tools/tvOS-test/app_packages/README -@@ -0,0 +1 @@ -+This directory exists so that 3rd party packages can be installed here. ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test.xcodeproj/project.pbxproj -@@ -0,0 +1,356 @@ -+// !$*UTF8*$! -+{ -+ archiveVersion = 1; -+ classes = { -+ }; -+ objectVersion = 46; -+ objects = { -+ -+/* Begin PBXBuildFile section */ -+ 6023B2AE1C28BA7A006F2562 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6023B2AD1C28BA7A006F2562 /* main.m */; }; -+ 6023B2B71C28BA7A006F2562 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6023B2B51C28BA7A006F2562 /* Main.storyboard */; }; -+ 6023B2B91C28BA7A006F2562 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6023B2B81C28BA7A006F2562 /* Assets.xcassets */; }; -+ 6023B2C71C28BD44006F2562 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C11C28BD44006F2562 /* CoreFoundation.framework */; }; -+ 6023B2C81C28BD44006F2562 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C21C28BD44006F2562 /* CoreGraphics.framework */; }; -+ 6023B2C91C28BD44006F2562 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C31C28BD44006F2562 /* Foundation.framework */; }; -+ 6023B2CA1C28BD44006F2562 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C41C28BD44006F2562 /* libsqlite3.tbd */; }; -+ 6023B2CB1C28BD44006F2562 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C51C28BD44006F2562 /* libz.tbd */; }; -+ 6023B2CC1C28BD44006F2562 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2C61C28BD44006F2562 /* UIKit.framework */; }; -+ 6023B2D01C28BDA3006F2562 /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6023B2CE1C28BDA3006F2562 /* Python.framework */; }; -+ 6023B2D31C28BDB7006F2562 /* app in Resources */ = {isa = PBXBuildFile; fileRef = 6023B2D11C28BDB7006F2562 /* app */; }; -+ 6023B2D41C28BDB7006F2562 /* app_packages in Resources */ = {isa = PBXBuildFile; fileRef = 6023B2D21C28BDB7006F2562 /* app_packages */; }; -+/* End PBXBuildFile section */ -+ -+/* Begin PBXFileReference section */ -+ 6023B2A91C28BA7A006F2562 /* tvOS-test.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "tvOS-test.app"; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 6023B2AD1C28BA7A006F2562 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; -+ 6023B2B61C28BA7A006F2562 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; -+ 6023B2B81C28BA7A006F2562 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; -+ 6023B2BA1C28BA7A006F2562 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -+ 6023B2C11C28BD44006F2562 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; -+ 6023B2C21C28BD44006F2562 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; -+ 6023B2C31C28BD44006F2562 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; -+ 6023B2C41C28BD44006F2562 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; -+ 6023B2C51C28BD44006F2562 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; -+ 6023B2C61C28BD44006F2562 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; -+ 6023B2CD1C28BDA3006F2562 /* OpenSSL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = OpenSSL.framework; sourceTree = ""; }; -+ 6023B2CE1C28BDA3006F2562 /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; -+ 6023B2D11C28BDB7006F2562 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; name = app; path = ../app; sourceTree = ""; }; -+ 6023B2D21C28BDB7006F2562 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = app_packages; path = ../app_packages; sourceTree = ""; }; -+/* End PBXFileReference section */ -+ -+/* Begin PBXFrameworksBuildPhase section */ -+ 6023B2A61C28BA7A006F2562 /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 6023B2CB1C28BD44006F2562 /* libz.tbd in Frameworks */, -+ 6023B2CA1C28BD44006F2562 /* libsqlite3.tbd in Frameworks */, -+ 6023B2D01C28BDA3006F2562 /* Python.framework in Frameworks */, -+ 6023B2C71C28BD44006F2562 /* CoreFoundation.framework in Frameworks */, -+ 6023B2C81C28BD44006F2562 /* CoreGraphics.framework in Frameworks */, -+ 6023B2C91C28BD44006F2562 /* Foundation.framework in Frameworks */, -+ 6023B2CC1C28BD44006F2562 /* UIKit.framework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXFrameworksBuildPhase section */ -+ -+/* Begin PBXGroup section */ -+ 6023B2A01C28BA7A006F2562 = { -+ isa = PBXGroup; -+ children = ( -+ 6023B2AB1C28BA7A006F2562 /* tvOS-test */, -+ 6023B2C01C28BD23006F2562 /* Frameworks */, -+ 6023B2AA1C28BA7A006F2562 /* Products */, -+ ); -+ sourceTree = ""; -+ }; -+ 6023B2AA1C28BA7A006F2562 /* Products */ = { -+ isa = PBXGroup; -+ children = ( -+ 6023B2A91C28BA7A006F2562 /* tvOS-test.app */, -+ ); -+ name = Products; -+ sourceTree = ""; -+ }; -+ 6023B2AB1C28BA7A006F2562 /* tvOS-test */ = { -+ isa = PBXGroup; -+ children = ( -+ 6023B2D11C28BDB7006F2562 /* app */, -+ 6023B2D21C28BDB7006F2562 /* app_packages */, -+ 6023B2B81C28BA7A006F2562 /* Assets.xcassets */, -+ 6023B2AC1C28BA7A006F2562 /* Supporting Files */, -+ ); -+ path = "tvOS-test"; -+ sourceTree = ""; -+ }; -+ 6023B2AC1C28BA7A006F2562 /* Supporting Files */ = { -+ isa = PBXGroup; -+ children = ( -+ 6023B2B51C28BA7A006F2562 /* Main.storyboard */, -+ 6023B2BA1C28BA7A006F2562 /* Info.plist */, -+ 6023B2AD1C28BA7A006F2562 /* main.m */, -+ ); -+ name = "Supporting Files"; -+ sourceTree = ""; -+ }; -+ 6023B2C01C28BD23006F2562 /* Frameworks */ = { -+ isa = PBXGroup; -+ children = ( -+ 6023B2C41C28BD44006F2562 /* libsqlite3.tbd */, -+ 6023B2C51C28BD44006F2562 /* libz.tbd */, -+ 6023B2CD1C28BDA3006F2562 /* OpenSSL.framework */, -+ 6023B2CE1C28BDA3006F2562 /* Python.framework */, -+ 6023B2C11C28BD44006F2562 /* CoreFoundation.framework */, -+ 6023B2C21C28BD44006F2562 /* CoreGraphics.framework */, -+ 6023B2C31C28BD44006F2562 /* Foundation.framework */, -+ 6023B2C61C28BD44006F2562 /* UIKit.framework */, -+ ); -+ name = Frameworks; -+ sourceTree = ""; -+ }; -+/* End PBXGroup section */ -+ -+/* Begin PBXNativeTarget section */ -+ 6023B2A81C28BA7A006F2562 /* tvOS-test */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 6023B2BD1C28BA7A006F2562 /* Build configuration list for PBXNativeTarget "tvOS-test" */; -+ buildPhases = ( -+ 6023B2D61C28CB97006F2562 /* Refresh Python source */, -+ 6023B2A51C28BA7A006F2562 /* Sources */, -+ 6023B2A61C28BA7A006F2562 /* Frameworks */, -+ 6023B2A71C28BA7A006F2562 /* Resources */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ ); -+ name = "tvOS-test"; -+ productName = "tvOS-test"; -+ productReference = 6023B2A91C28BA7A006F2562 /* tvOS-test.app */; -+ productType = "com.apple.product-type.application"; -+ }; -+/* End PBXNativeTarget section */ -+ -+/* Begin PBXProject section */ -+ 6023B2A11C28BA7A006F2562 /* Project object */ = { -+ isa = PBXProject; -+ attributes = { -+ LastUpgradeCheck = 0720; -+ ORGANIZATIONNAME = "Python Software Foundation"; -+ TargetAttributes = { -+ 6023B2A81C28BA7A006F2562 = { -+ CreatedOnToolsVersion = 7.2; -+ }; -+ }; -+ }; -+ buildConfigurationList = 6023B2A41C28BA7A006F2562 /* Build configuration list for PBXProject "tvOS-test" */; -+ compatibilityVersion = "Xcode 3.2"; -+ developmentRegion = English; -+ hasScannedForEncodings = 0; -+ knownRegions = ( -+ en, -+ Base, -+ ); -+ mainGroup = 6023B2A01C28BA7A006F2562; -+ productRefGroup = 6023B2AA1C28BA7A006F2562 /* Products */; -+ projectDirPath = ""; -+ projectRoot = ""; -+ targets = ( -+ 6023B2A81C28BA7A006F2562 /* tvOS-test */, -+ ); -+ }; -+/* End PBXProject section */ -+ -+/* Begin PBXResourcesBuildPhase section */ -+ 6023B2A71C28BA7A006F2562 /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 6023B2D31C28BDB7006F2562 /* app in Resources */, -+ 6023B2B91C28BA7A006F2562 /* Assets.xcassets in Resources */, -+ 6023B2B71C28BA7A006F2562 /* Main.storyboard in Resources */, -+ 6023B2D41C28BDB7006F2562 /* app_packages in Resources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXResourcesBuildPhase section */ -+ -+/* Begin PBXShellScriptBuildPhase section */ -+ 6023B2D61C28CB97006F2562 /* Refresh Python source */ = { -+ isa = PBXShellScriptBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Refresh Python source"; -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "mkdir -p \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\"\nmkdir -p \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application Support/org.python.tvOS-test\"\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git \"$PROJECT_DIR/Python.framework/Resources/lib\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\"\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git \"$PROJECT_DIR/Python.framework/Resources/include\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\"\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git \"$PROJECT_DIR/app\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application Support/org.python.tvOS-test\"\nmkdir -p \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\"\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git \"$PROJECT_DIR/app_packages/\" \"$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\"\n"; -+ }; -+/* End PBXShellScriptBuildPhase section */ -+ -+/* Begin PBXSourcesBuildPhase section */ -+ 6023B2A51C28BA7A006F2562 /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 6023B2AE1C28BA7A006F2562 /* main.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXSourcesBuildPhase section */ -+ -+/* Begin PBXVariantGroup section */ -+ 6023B2B51C28BA7A006F2562 /* Main.storyboard */ = { -+ isa = PBXVariantGroup; -+ children = ( -+ 6023B2B61C28BA7A006F2562 /* Base */, -+ ); -+ name = Main.storyboard; -+ sourceTree = ""; -+ }; -+/* End PBXVariantGroup section */ -+ -+/* Begin XCBuildConfiguration section */ -+ 6023B2BB1C28BA7A006F2562 /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ 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; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ 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; -+ MTL_ENABLE_DEBUG_INFO = YES; -+ ONLY_ACTIVE_ARCH = YES; -+ SDKROOT = appletvos; -+ TARGETED_DEVICE_FAMILY = 3; -+ TVOS_DEPLOYMENT_TARGET = 9.1; -+ }; -+ name = Debug; -+ }; -+ 6023B2BC1C28BA7A006F2562 /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ 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; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ 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; -+ MTL_ENABLE_DEBUG_INFO = NO; -+ SDKROOT = appletvos; -+ TARGETED_DEVICE_FAMILY = 3; -+ TVOS_DEPLOYMENT_TARGET = 9.1; -+ VALIDATE_PRODUCT = YES; -+ }; -+ name = Release; -+ }; -+ 6023B2BE1C28BA7A006F2562 /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ INFOPLIST_FILE = "tvOS-test/Info.plist"; -+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; -+ PRODUCT_BUNDLE_IDENTIFIER = "org.python.tvOS-test"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ }; -+ name = Debug; -+ }; -+ 6023B2BF1C28BA7A006F2562 /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image"; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ INFOPLIST_FILE = "tvOS-test/Info.plist"; -+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; -+ PRODUCT_BUNDLE_IDENTIFIER = "org.python.tvOS-test"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ }; -+ name = Release; -+ }; -+/* End XCBuildConfiguration section */ -+ -+/* Begin XCConfigurationList section */ -+ 6023B2A41C28BA7A006F2562 /* Build configuration list for PBXProject "tvOS-test" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 6023B2BB1C28BA7A006F2562 /* Debug */, -+ 6023B2BC1C28BA7A006F2562 /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 6023B2BD1C28BA7A006F2562 /* Build configuration list for PBXNativeTarget "tvOS-test" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 6023B2BE1C28BA7A006F2562 /* Debug */, -+ 6023B2BF1C28BA7A006F2562 /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+/* End XCConfigurationList section */ -+ }; -+ rootObject = 6023B2A11C28BA7A006F2562 /* Project object */; -+} ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "tv", -+ "filename" : "large.png", -+ "scale" : "1x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json -@@ -0,0 +1,17 @@ -+{ -+ "layers" : [ -+ { -+ "filename" : "Front.imagestacklayer" -+ }, -+ { -+ "filename" : "Middle.imagestacklayer" -+ }, -+ { -+ "filename" : "Back.imagestacklayer" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "tv", -+ "filename" : "large.png", -+ "scale" : "1x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "tv", -+ "filename" : "large.png", -+ "scale" : "1x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "tv", -+ "filename" : "small.png", -+ "scale" : "1x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json -@@ -0,0 +1,17 @@ -+{ -+ "layers" : [ -+ { -+ "filename" : "Front.imagestacklayer" -+ }, -+ { -+ "filename" : "Middle.imagestacklayer" -+ }, -+ { -+ "filename" : "Back.imagestacklayer" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "tv", -+ "filename" : "small.png", -+ "scale" : "1x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "tv", -+ "filename" : "small.png", -+ "scale" : "1x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json -@@ -0,0 +1,26 @@ -+{ -+ "assets" : [ -+ { -+ "size" : "1280x768", -+ "idiom" : "tv", -+ "filename" : "App Icon - Large.imagestack", -+ "role" : "primary-app-icon" -+ }, -+ { -+ "size" : "400x240", -+ "idiom" : "tv", -+ "filename" : "App Icon - Small.imagestack", -+ "role" : "primary-app-icon" -+ }, -+ { -+ "size" : "1920x720", -+ "idiom" : "tv", -+ "filename" : "Top Shelf Image.imageset", -+ "role" : "top-shelf-image" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json -@@ -0,0 +1,13 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "tv", -+ "filename" : "shelf.png", -+ "scale" : "1x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/Contents.json -@@ -0,0 +1,6 @@ -+{ -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Assets.xcassets/LaunchImage.launchimage/Contents.json -@@ -0,0 +1,16 @@ -+{ -+ "images" : [ -+ { -+ "orientation" : "landscape", -+ "idiom" : "tv", -+ "filename" : "launch.png", -+ "extent" : "full-screen", -+ "minimum-system-version" : "9.0", -+ "scale" : "1x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Base.lproj/Main.storyboard -@@ -0,0 +1,25 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/Info.plist -@@ -0,0 +1,32 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ en -+ CFBundleExecutable -+ $(EXECUTABLE_NAME) -+ CFBundleIdentifier -+ $(PRODUCT_BUNDLE_IDENTIFIER) -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundleName -+ $(PRODUCT_NAME) -+ CFBundlePackageType -+ APPL -+ CFBundleShortVersionString -+ 1.0 -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ 1 -+ LSRequiresIPhoneOS -+ -+ UIMainStoryboardFile -+ Main -+ UIRequiredDeviceCapabilities -+ -+ arm64 -+ -+ -+ ---- /dev/null -+++ b/Tools/tvOS-test/tvOS-test/main.m -@@ -0,0 +1,149 @@ -+// -+// main.m -+// A main module for starting Python projects under tvOS. -+// -+ -+#import -+#import -+#include -+#include -+ -+int main(int argc, char *argv[]) { -+ int ret = 0; -+ unsigned int i; -+ NSString *tmp_path; -+ NSString *exe; -+ NSString *python_home; -+ wchar_t *wpython_home; -+ const char* main_script; -+ wchar_t** python_argv; -+ @autoreleasepool { -+ -+ NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; -+ -+ // Special environment to avoid writing bytecode because -+ // the process will not have write attribute on the device. -+ putenv("PYTHONDONTWRITEBYTECODE=1"); -+ -+ python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; -+ NSLog(@"PythonHome is: %@", python_home); -+ wpython_home = Py_DecodeLocale([python_home UTF8String], NULL); -+ Py_SetPythonHome(wpython_home); -+ -+ // tvOS provides a specific directory for temp files. -+ tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; -+ putenv((char *)[tmp_path UTF8String]); -+ -+ // Since tvOS doesn't allow dynamic linking, we have to know -+ // the name of the executable so that we can find the ctypes -+ // test objects. However, sys.argv[0] will be updated to -+ // reflect the script name; the TEST_EXECUTABLE environment -+ // variable provides the mechanism for specifying the filename. -+ exe = [NSString stringWithFormat:@"TEST_EXECUTABLE=%s", argv[0], nil]; -+ putenv((char *)[exe UTF8String]); -+ -+ NSLog(@"Initializing Python runtime..."); -+ Py_Initialize(); -+ -+ /******************************************************* -+ To tell lldb not to stop on signals, use the following commands: -+ process handle SIGPIPE -n true -p true -s false -+ process handle SIGINT -n true -p true -s false -+ process handle SIGXFSZ -n true -p true -s false -+ process handle SIGUSR1 -n true -p true -s false -+ process handle SIGUSR2 -n true -p true -s false -+ *******************************************************/ -+ -+ // Arguments to pass to test runner -+ char *test_args[] = { -+ "-j", "1", -+ "-u", "all,-audio,-curses,-largefile,-subprocess,-gui", -+// "-v", // Verbose test output -+ "-W", // Display test output on failure -+ -+ "-x", // Arguments are tests to *exclude* -+// Simulator failures -+// "test_coroutines", // docstring not being populated -+// "test_module", // docstring not being populated -+ -+// ARM64 failures -+// "test_coroutines", // docstring not being populated -+// "test_ctypes", // DL loading? -+// "test_module" // docstring not being populated -+// "test_threading", // ctypes related; missing symbol PyThreadState_SetAsyncExc -+// "test_unicode", // encoding problem -+ -+// ARMv7 failures -+// "test_cmath", // math domain error -+// "test_ctypes", // DL loading? -+// "test_float", // rounding? -+// "test_math", // math domain error -+// "test_numeric_tower", // -+// "test_strtod", // -+// "test_importlib", // Thread locking problem -+// "test_threading", // ctypes related; missing symbol PyThreadState_SetAsyncExc -+ -+// COMMON FAILURES -+ "test_bytes" // HARD CRASH ctypes related; PyBytes_FromFormat -+ -+ }; -+ -+ // Set the name of the main script -+ main_script = [ -+ [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.tvOS-test/app/tvOS-test/main" -+ ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; -+ -+ if (main_script == NULL) { -+ NSLog(@"Unable to locate app/tvOS-test/main.py file"); -+ exit(-1); -+ } -+ -+ // Construct argv for the interpreter -+ int n_test_args = sizeof(test_args) / sizeof (*test_args) + 1; -+ -+ python_argv = PyMem_RawMalloc(sizeof(wchar_t*) * n_test_args); -+ python_argv[0] = Py_DecodeLocale(main_script, NULL); -+ for (i = 1; i < n_test_args; i++) { -+ python_argv[i] = Py_DecodeLocale(test_args[i-1], NULL); -+ } -+ -+ PySys_SetArgv(n_test_args, python_argv); -+ -+ // If other modules are using thread, we need to initialize them before. -+ PyEval_InitThreads(); -+ -+ // Start the main.py script -+ NSLog(@"Running %s", main_script); -+ -+ @try { -+ FILE* fd = fopen(main_script, "r"); -+ if (fd == NULL) { -+ ret = 1; -+ NSLog(@"Unable to open main.py, abort."); -+ } else { -+ ret = PyRun_SimpleFileEx(fd, main_script, 1); -+ if (ret != 0) { -+ NSLog(@"Application quit abnormally!"); -+ } -+ } -+ } -+ @catch (NSException *exception) { -+ NSLog(@"Python runtime error: %@", [exception reason]); -+ } -+ @finally { -+ Py_Finalize(); -+ } -+ -+ PyMem_RawFree(wpython_home); -+ if (python_argv) { -+ for (i = 0; i < argc; i++) { -+ PyMem_RawFree(python_argv[i]); -+ } -+ PyMem_RawFree(python_argv); -+ } -+ NSLog(@"Leaving"); -+ } -+ -+ exit(ret); -+ return ret; -+} diff --git a/aclocal.m4 b/aclocal.m4 -index e5e804276f..6a49224e6a 100644 +index e5e804276f..52102fe4bb 100644 --- a/aclocal.m4 +++ b/aclocal.m4 +@@ -1,6 +1,6 @@ +-# generated automatically by aclocal 1.16.3 -*- Autoconf -*- ++# generated automatically by aclocal 1.16.5 -*- Autoconf -*- + +-# Copyright (C) 1996-2020 Free Software Foundation, Inc. ++# Copyright (C) 1996-2021 Free Software Foundation, Inc. + + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -130,7 +130,7 @@ + # and this notice are preserved. This file is offered as-is, without any + # warranty. + +-#serial 10 ++#serial 11 + + AU_ALIAS([CHECK_SSL], [AX_CHECK_OPENSSL]) + AC_DEFUN([AX_CHECK_OPENSSL], [ +@@ -173,7 +173,7 @@ + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do +- AC_MSG_CHECKING([for openssl/ssl.h in $ssldir]) ++ AC_MSG_CHECKING([for include/openssl/ssl.h in $ssldir]) + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" +@@ -222,7 +222,7 @@ + ]) + + # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +-# serial 11 (pkg-config-0.29.1) ++# serial 12 (pkg-config-0.29.2) + + dnl Copyright © 2004 Scott James Remnant . + dnl Copyright © 2012-2015 Dan Nicholson +@@ -264,7 +264,7 @@ + dnl See the "Since" comment for each macro you use to see what version + dnl of the macros you require. + m4_defun([PKG_PREREQ], +-[m4_define([PKG_MACROS_VERSION], [0.29.1]) ++[m4_define([PKG_MACROS_VERSION], [0.29.2]) + m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) + ])dnl PKG_PREREQ @@ -365,7 +365,7 @@ AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl @@ -4693,10 +2911,91 @@ index e5e804276f..6a49224e6a 100644 m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full +@@ -497,71 +497,3 @@ + AS_VAR_IF([$1], [""], [$5], [$4])dnl + ])dnl PKG_CHECK_VAR + +-dnl PKG_WITH_MODULES(VARIABLE-PREFIX, MODULES, +-dnl [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND], +-dnl [DESCRIPTION], [DEFAULT]) +-dnl ------------------------------------------ +-dnl +-dnl Prepare a "--with-" configure option using the lowercase +-dnl [VARIABLE-PREFIX] name, merging the behaviour of AC_ARG_WITH and +-dnl PKG_CHECK_MODULES in a single macro. +-AC_DEFUN([PKG_WITH_MODULES], +-[ +-m4_pushdef([with_arg], m4_tolower([$1])) +- +-m4_pushdef([description], +- [m4_default([$5], [build with ]with_arg[ support])]) +- +-m4_pushdef([def_arg], [m4_default([$6], [auto])]) +-m4_pushdef([def_action_if_found], [AS_TR_SH([with_]with_arg)=yes]) +-m4_pushdef([def_action_if_not_found], [AS_TR_SH([with_]with_arg)=no]) +- +-m4_case(def_arg, +- [yes],[m4_pushdef([with_without], [--without-]with_arg)], +- [m4_pushdef([with_without],[--with-]with_arg)]) +- +-AC_ARG_WITH(with_arg, +- AS_HELP_STRING(with_without, description[ @<:@default=]def_arg[@:>@]),, +- [AS_TR_SH([with_]with_arg)=def_arg]) +- +-AS_CASE([$AS_TR_SH([with_]with_arg)], +- [yes],[PKG_CHECK_MODULES([$1],[$2],$3,$4)], +- [auto],[PKG_CHECK_MODULES([$1],[$2], +- [m4_n([def_action_if_found]) $3], +- [m4_n([def_action_if_not_found]) $4])]) +- +-m4_popdef([with_arg]) +-m4_popdef([description]) +-m4_popdef([def_arg]) +- +-])dnl PKG_WITH_MODULES +- +-dnl PKG_HAVE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +-dnl [DESCRIPTION], [DEFAULT]) +-dnl ----------------------------------------------- +-dnl +-dnl Convenience macro to trigger AM_CONDITIONAL after PKG_WITH_MODULES +-dnl check._[VARIABLE-PREFIX] is exported as make variable. +-AC_DEFUN([PKG_HAVE_WITH_MODULES], +-[ +-PKG_WITH_MODULES([$1],[$2],,,[$3],[$4]) +- +-AM_CONDITIONAL([HAVE_][$1], +- [test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"]) +-])dnl PKG_HAVE_WITH_MODULES +- +-dnl PKG_HAVE_DEFINE_WITH_MODULES(VARIABLE-PREFIX, MODULES, +-dnl [DESCRIPTION], [DEFAULT]) +-dnl ------------------------------------------------------ +-dnl +-dnl Convenience macro to run AM_CONDITIONAL and AC_DEFINE after +-dnl PKG_WITH_MODULES check. HAVE_[VARIABLE-PREFIX] is exported as make +-dnl and preprocessor variable. +-AC_DEFUN([PKG_HAVE_DEFINE_WITH_MODULES], +-[ +-PKG_HAVE_WITH_MODULES([$1],[$2],[$3],[$4]) +- +-AS_IF([test "$AS_TR_SH([with_]m4_tolower([$1]))" = "yes"], +- [AC_DEFINE([HAVE_][$1], 1, [Enable ]m4_tolower([$1])[ support])]) +-])dnl PKG_HAVE_DEFINE_WITH_MODULES +- diff --git a/config.sub b/config.sub -index d74fb6deac..249b391d71 100755 +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* \ @@ -4706,11 +3005,29 @@ index d74fb6deac..249b391d71 100755 | 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 b7be60eaa3..77822c198a 100755 +index b7be60eaa3..4de2037f24 100755 --- a/configure +++ b/configure -@@ -788,7 +788,6 @@ +@@ -655,6 +655,8 @@ + DTRACE + TCLTK_LIBS + TCLTK_INCLUDES ++LIBFFI_LIB ++LIBFFI_LIBDIR + LIBFFI_INCLUDEDIR + PKG_CONFIG_LIBDIR + PKG_CONFIG_PATH +@@ -788,7 +790,6 @@ docdir oldincludedir includedir @@ -4718,7 +3035,7 @@ index b7be60eaa3..77822c198a 100755 localstatedir sharedstatedir sysconfdir -@@ -906,7 +905,6 @@ +@@ -906,7 +907,6 @@ sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' @@ -4726,7 +3043,7 @@ index b7be60eaa3..77822c198a 100755 includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -@@ -1159,15 +1157,6 @@ +@@ -1159,15 +1159,6 @@ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; @@ -4742,7 +3059,7 @@ index b7be60eaa3..77822c198a 100755 -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ -@@ -1305,7 +1294,7 @@ +@@ -1305,7 +1296,7 @@ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ @@ -4751,7 +3068,7 @@ index b7be60eaa3..77822c198a 100755 do eval ac_val=\$$ac_var # Remove trailing slashes. -@@ -1458,7 +1447,6 @@ +@@ -1458,7 +1449,6 @@ --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] @@ -4759,23 +3076,23 @@ index b7be60eaa3..77822c198a 100755 --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] -@@ -3316,6 +3304,15 @@ +@@ -3316,6 +3306,15 @@ *-*-cygwin*) ac_sys_system=Cygwin ;; -+ *-apple-ios) ++ *-apple-ios*) + ac_sys_system=iOS + ;; -+ *-apple-tvos) ++ *-apple-tvos*) + ac_sys_system=tvOS + ;; -+ *-apple-watchos) ++ *-apple-watchos*) + ac_sys_system=watchOS + ;; *-*-vxworks*) ac_sys_system=VxWorks ;; -@@ -3366,6 +3363,15 @@ +@@ -3366,6 +3365,15 @@ *-*-cygwin*) _host_cpu= ;; @@ -4791,7 +3108,7 @@ index b7be60eaa3..77822c198a 100755 *-*-vxworks*) _host_cpu=$host_cpu ;; -@@ -3441,6 +3447,13 @@ +@@ -3441,6 +3449,13 @@ define_xopen_source=no;; Darwin/[12][0-9].*) define_xopen_source=no;; @@ -4805,7 +3122,39 @@ index b7be60eaa3..77822c198a 100755 # On AIX 4 and 5.1, mbstate_t is defined only when _XOPEN_SOURCE == 500 but # used in wcsnrtombs() and mbsnrtowcs() even if _XOPEN_SOURCE is not defined # or has another value. By not (re)defining it, the defaults come in place. -@@ -5371,6 +5384,12 @@ +@@ -5347,7 +5362,30 @@ + #elif defined(__gnu_hurd__) + i386-gnu + #elif defined(__APPLE__) +- darwin ++# include "TargetConditionals.h" ++# if TARGET_OS_IOS ++# if TARGET_OS_SIMULATOR ++ iphonesimulator ++# else ++ iphoneos ++# endif ++# elif TARGET_OS_TV ++# if TARGET_OS_SIMULATOR ++ appletvsimulator ++# else ++ appletvos ++# endif ++# elif TARGET_OS_WATCH ++# if TARGET_OS_SIMULATOR ++ watchsimulator ++# else ++ watchos ++# endif ++# elif TARGET_OS_OSX ++ darwin ++# else ++# error unknown Apple platform ++# endif + #elif defined(__VXWORKS__) + vxworks + #else +@@ -5371,6 +5409,12 @@ case $ac_sys_system in #( Darwin*) : MULTIARCH="" ;; #( @@ -4818,7 +3167,7 @@ index b7be60eaa3..77822c198a 100755 FreeBSD*) : MULTIARCH="" ;; #( *) : -@@ -6234,11 +6253,17 @@ +@@ -6234,11 +6278,23 @@ fi if test "$cross_compiling" = yes; then @@ -4828,9 +3177,15 @@ index b7be60eaa3..77822c198a 100755 - ;; - esac + case "$host" in -+ *-apple-*os) ++ *-apple-ios*) + # readelf not required for iOS cross builds. + ;; ++ *-apple-tvos*) ++ # readelf not required for tvOS cross builds. ++ ;; ++ *-apple-watchos*) ++ # readelf not required for watchOS cross builds. ++ ;; + *) + case "$READELF" in + readelf|:) @@ -4841,55 +3196,85 @@ index b7be60eaa3..77822c198a 100755 fi -@@ -6992,8 +7017,6 @@ - # tweak BASECFLAGS based on compiler and platform - case $GCC in - yes) -- CFLAGS_NODIST="$CFLAGS_NODIST -std=c99" -- - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wextra" >&5 - $as_echo_n "checking for -Wextra... " >&6; } - ac_save_cc="$CC" -@@ -11743,6 +11766,10 @@ - fi - ;; - hp*|HP*) DYNLOADFILE="dynload_hpux.o";; -+ # Disable dynamic loading on iOS -+ iOS/*) DYNLOADFILE="dynload_stub.o";; -+ tvOS/*) DYNLOADFILE="dynload_stub.o";; -+ watchOS/*) DYNLOADFILE="dynload_stub.o";; - *) - # use dynload_shlib.c and dlopen() if we have it; otherwise stub - # out any dynamic loading -@@ -19026,7 +19053,7 @@ - echo "creating Modules/Setup.local" >&6 - if test ! -f Modules/Setup.local - then -- echo "# Edit this file for local setup changes" >Modules/Setup.local -+ echo "# Edit this file for local setup changes" >Modules/Setup.local +@@ -9574,6 +9630,10 @@ + BLDSHARED="$LDSHARED" + fi + ;; ++ iOS/*|tvOS/*|watchOS/*) ++ LDSHARED='$(CC) -bundle -undefined dynamic_lookup' ++ LDCXXSHARED='$(CXX) -bundle -undefined dynamic_lookup' ++ ;; + Linux*|GNU*|QNX*|VxWorks*) + LDSHARED='$(CC) -shared' + LDCXXSHARED='$(CXX) -shared';; +@@ -10642,23 +10702,35 @@ + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_system_ffi" >&5 + $as_echo "$with_system_ffi" >&6; } + else +- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +-$as_echo "yes" >&6; } +- if test "$with_system_ffi" != "" ++ if test "$ac_sys_system" = "iOS" || test "$ac_sys_system" = "tvOS" || test "$ac_sys_system" = "watchOS" + then +- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with(out)-system-ffi is ignored on this platform" >&5 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 ++$as_echo "no" >&6; } ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Using user-provided libffi configuration" >&5 ++$as_echo "$as_me: WARNING: Using user-provided libffi configuration" >&2;} ++ LIBFFI_LIBDIR="${LIBFFI_LIBDIR}" ++ LIBFFI_LIB="${LIBFFI_LIB}" ++ else ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 ++$as_echo "yes" >&6; } ++ if test "$with_system_ffi" != "" ++ then ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --with(out)-system-ffi is ignored on this platform" >&5 + $as_echo "$as_me: WARNING: --with(out)-system-ffi is ignored on this platform" >&2;} ++ fi ++ with_system_ffi="yes" + fi +- with_system_ffi="yes" fi - echo "creating Makefile" >&6 -@@ -19043,4 +19070,3 @@ - echo "" >&6 - echo "" >&6 + if test "$with_system_ffi" = "yes" && test -n "$PKG_CONFIG"; then + LIBFFI_INCLUDEDIR="`"$PKG_CONFIG" libffi --cflags-only-I 2>/dev/null | sed -e 's/^-I//;s/ *$//'`" + else +- LIBFFI_INCLUDEDIR="" ++ LIBFFI_INCLUDEDIR="${LIBFFI_INCLUDEDIR}" fi -- + + ++ ++ + # Check for use of the system libmpdec library + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-system-libmpdec" >&5 + $as_echo_n "checking for --with-system-libmpdec... " >&6; } +@@ -17516,8 +17588,8 @@ + if ! $found; then + OPENSSL_INCLUDES= + for ssldir in $ssldirs; do +- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/ssl.h in $ssldir" >&5 +-$as_echo_n "checking for openssl/ssl.h in $ssldir... " >&6; } ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for include/openssl/ssl.h in $ssldir" >&5 ++$as_echo_n "checking for include/openssl/ssl.h in $ssldir... " >&6; } + if test -f "$ssldir/include/openssl/ssl.h"; then + OPENSSL_INCLUDES="-I$ssldir/include" + OPENSSL_LDFLAGS="-L$ssldir/lib" diff --git a/configure.ac b/configure.ac -index aa515da465..da2eb9029b 100644 +index aa515da465..81f956f3d2 100644 --- a/configure.ac +++ b/configure.ac @@ -400,6 +400,15 @@ *-*-cygwin*) ac_sys_system=Cygwin ;; -+ *-apple-ios) ++ *-apple-ios*) + ac_sys_system=iOS + ;; -+ *-apple-tvos) ++ *-apple-tvos*) + ac_sys_system=tvOS + ;; -+ *-apple-watchos) ++ *-apple-watchos*) + ac_sys_system=watchOS + ;; *-*-vxworks*) @@ -4925,7 +3310,39 @@ index aa515da465..da2eb9029b 100644 # On AIX 4 and 5.1, mbstate_t is defined only when _XOPEN_SOURCE == 500 but # used in wcsnrtombs() and mbsnrtowcs() even if _XOPEN_SOURCE is not defined # or has another value. By not (re)defining it, the defaults come in place. -@@ -885,6 +910,9 @@ +@@ -865,7 +890,30 @@ + #elif defined(__gnu_hurd__) + i386-gnu + #elif defined(__APPLE__) +- darwin ++# include "TargetConditionals.h" ++# if TARGET_OS_IOS ++# if TARGET_OS_SIMULATOR ++ iphonesimulator ++# else ++ iphoneos ++# endif ++# elif TARGET_OS_TV ++# if TARGET_OS_SIMULATOR ++ appletvsimulator ++# else ++ appletvos ++# endif ++# elif TARGET_OS_WATCH ++# if TARGET_OS_SIMULATOR ++ watchsimulator ++# else ++ watchos ++# endif ++# elif TARGET_OS_OSX ++ darwin ++# else ++# error unknown Apple platform ++# endif + #elif defined(__VXWORKS__) + vxworks + #else +@@ -885,6 +933,9 @@ AC_MSG_CHECKING([for multiarch]) AS_CASE([$ac_sys_system], [Darwin*], [MULTIARCH=""], @@ -4935,7 +3352,7 @@ index aa515da465..da2eb9029b 100644 [FreeBSD*], [MULTIARCH=""], [MULTIARCH=$($CC --print-multiarch 2>/dev/null)] ) -@@ -1223,11 +1251,17 @@ +@@ -1223,11 +1274,23 @@ AC_CHECK_TOOLS([READELF], [readelf], [:]) if test "$cross_compiling" = yes; then @@ -4945,9 +3362,15 @@ index aa515da465..da2eb9029b 100644 - ;; - esac + case "$host" in -+ *-apple-*os) ++ *-apple-ios*) + # readelf not required for iOS cross builds. + ;; ++ *-apple-tvos*) ++ # readelf not required for tvOS cross builds. ++ ;; ++ *-apple-watchos*) ++ # readelf not required for watchOS cross builds. ++ ;; + *) + case "$READELF" in + readelf|:) @@ -4958,2603 +3381,104 @@ index aa515da465..da2eb9029b 100644 fi AC_SUBST(READELF) -@@ -1613,8 +1647,6 @@ - # tweak BASECFLAGS based on compiler and platform - case $GCC in - yes) -- CFLAGS_NODIST="$CFLAGS_NODIST -std=c99" -- - AC_MSG_CHECKING(for -Wextra) - ac_save_cc="$CC" - CC="$CC -Wextra -Werror" -@@ -3670,6 +3702,10 @@ - fi - ;; - hp*|HP*) DYNLOADFILE="dynload_hpux.o";; -+ # Disable dynamic loading on iOS -+ iOS/*) DYNLOADFILE="dynload_stub.o";; -+ tvOS/*) DYNLOADFILE="dynload_stub.o";; -+ watchOS/*) DYNLOADFILE="dynload_stub.o";; - *) - # use dynload_shlib.c and dlopen() if we have it; otherwise stub - # out any dynamic loading -@@ -5862,7 +5898,7 @@ - echo "creating Modules/Setup.local" >&AS_MESSAGE_FD - if test ! -f Modules/Setup.local - then -- echo "# Edit this file for local setup changes" >Modules/Setup.local -+ echo "# Edit this file for local setup changes" >Modules/Setup.local +@@ -2681,6 +2744,10 @@ + BLDSHARED="$LDSHARED" + fi + ;; ++ iOS/*|tvOS/*|watchOS/*) ++ LDSHARED='$(CC) -bundle -undefined dynamic_lookup' ++ LDCXXSHARED='$(CXX) -bundle -undefined dynamic_lookup' ++ ;; + Linux*|GNU*|QNX*|VxWorks*) + LDSHARED='$(CC) -shared' + LDCXXSHARED='$(CXX) -shared';; +@@ -3115,20 +3182,30 @@ + esac + AC_MSG_RESULT($with_system_ffi) + else +- AC_MSG_RESULT(yes) +- if test "$with_system_ffi" != "" ++ if test "$ac_sys_system" = "iOS" || test "$ac_sys_system" = "tvOS" || test "$ac_sys_system" = "watchOS" + then +- AC_MSG_WARN([--with(out)-system-ffi is ignored on this platform]) ++ AC_MSG_RESULT(no) ++ AC_MSG_WARN([Using user-provided libffi configuration]) ++ LIBFFI_LIBDIR="${LIBFFI_LIBDIR}" ++ LIBFFI_LIB="${LIBFFI_LIB}" ++ else ++ AC_MSG_RESULT(yes) ++ if test "$with_system_ffi" != "" ++ then ++ AC_MSG_WARN([--with(out)-system-ffi is ignored on this platform]) ++ fi ++ with_system_ffi="yes" + fi +- with_system_ffi="yes" fi - echo "creating Makefile" >&AS_MESSAGE_FD -@@ -5879,4 +5915,3 @@ - echo "" >&AS_MESSAGE_FD - echo "" >&AS_MESSAGE_FD + if test "$with_system_ffi" = "yes" && test -n "$PKG_CONFIG"; then + LIBFFI_INCLUDEDIR="`"$PKG_CONFIG" libffi --cflags-only-I 2>/dev/null | sed -e 's/^-I//;s/ *$//'`" + else +- LIBFFI_INCLUDEDIR="" ++ LIBFFI_INCLUDEDIR="${LIBFFI_INCLUDEDIR}" fi -- ---- /dev/null -+++ b/iOS/Info.plist -@@ -0,0 +1,20 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ English -+ CFBundleExecutable -+ Python -+ CFBundleIdentifier -+ org.python -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundlePackageType -+ FMWK -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ xxxVERSIONxxx -+ -+ ---- /dev/null -+++ b/iOS/README -@@ -0,0 +1,165 @@ -+==================== -+Python on iOS README -+==================== -+ -+:Authors: -+ Russell Keith-Magee (2015) -+ -+:Version: 3.5.2 -+ -+This document provides a overview of eccentricities of building and using -+Python on iOS. -+ -+Build instructions -+================== -+ -+The iOS build must be run on an Mac with XCode installed. To build the iOS -+framework, unpack the Python sources, move into the iOS subdirectory, and -+run ``make``. There are no configuration options to this build process - -+it will use XCode utilities to identify the location of compilers, -+resource directories, and so on. -+ -+The build process will configure and build Python 6 times, producing: -+ -+ * A "host" version of Python -+ * A version of Python compiled for the x86-64 iOS Simulator -+ * A version of Python compiled for the i386 iOS Simulator -+ * A version of Python compiled for ARM64 iOS devices -+ * A version of Python compiled for ARMv7s iOS devices -+ * A version of Python compiled for ARMv7 iOS devices -+ -+Build products will be "installed" into iOS/build. The built products will -+then be combined into a single "fat" ``Python.framework`` that can be added to -+an XCode project. The resulting framework will be located in the root -+directory of the Python source tree. -+ -+A ``make clean`` target also exists to clean out all build products; -+``make distclean`` will clean out all user-specific files from the test and -+sample projects. -+ -+Test instructions -+----------------- -+ -+The ``Tools`` directory contains an ``iOS-Test`` project that enables you to -+run the Python regression test suite. When you run ``make`` in the iOS -+directory, a copy of ``Python.framework`` will also be installed into this -+test project. -+ -+To run the test project, load the project into XCode, and run (either on a -+device or in the simulator). The test suite takes around 10 minutes to run on -+an iPhone6S. -+ -+.. note:: If you run the test project in debug mode, the XCode debugger will -+ stop whenever a signal is raised. The Python regression test suite checks -+ a number of signal handlers, and the test suite will stop mid-execution -+ when this occurs. -+ -+ To disable this signal handling, set a breakpoint at the start of -+ ``main.c``; when execution stops at the breakpoint, run the following -+ commands in the debugger (at the ``(lldb)`` prompt in the console log -+ window):: -+ -+ process handle SIGPIPE -n true -p true -s false -+ process handle SIGINT -n true -p true -s false -+ process handle SIGXFSZ -n true -p true -s false -+ process handle SIGUSR1 -n true -p true -s false -+ process handle SIGUSR2 -n true -p true -s false -+ -+ Unfortunately, this has to be done every time the test suite is executed. -+ -+iOS-specific details -+==================== -+ -+* ``import sys; sys.platform`` will report as `'ios'`, regardless of whether you -+ are on a simulator or a real platform. -+ -+* ``import platform; platform.machine()`` will return the device identifier. -+ For example, an iPhone 5S will return `'iPhone6,2'` -+ -+* The following modules are not currently supported: -+ -+ - ``bsddb`` -+ - ``bz2`` -+ - ``curses`` -+ - ``dbm`` -+ - ``gdbm`` -+ - ``hotshot`` -+ - ``idlelib`` -+ - ``lzma`` -+ - ``nis`` -+ - ``ossaudiodev`` -+ - ``readline`` -+ - ``spwd`` -+ - ``sqlite3`` -+ - ``ssl`` -+ - ``tkinter`` -+ - ``turtledemo`` -+ - ``wsgiref`` -+ -+* Due to limitations in using dynamic loading on iOS, binary Python modules must be -+ statically-linked into the executable. The framework package produced by the iOS -+ ``make install`` statically links all the supported standard library modules. -+ If you have a third-party Python binary module, you'll need to incorporate the -+ source files for that module into the sources for your own app. -+ -+ If you want to add or remove a binary module from the set that is included in the -+ Python library, you can do so by providing module setup files for each platform. -+ There are three default module configuration files: -+ -+ - ``Modules/Setup.iOS-aarch64`` for ARM64 iOS builds -+ - ``Modules/Setup.iOS-arm`` for ARMv7 iOS builds -+ - ``Modules/Setup.iOS-x86_64`` for x86_64 iOS simulator builds -+ -+ If you copy these files to a ``.local`` version (e.g., -+ ``Modules/Setup.iOS-aarch64.local``), the local version will override the -+ default. You can then make modifications to the modules that will be included -+ in the iOS framework, and the flags passed to the compiler when compiling those -+ modules. -+ -+Adding Python to an iOS project -+=============================== -+ -+The iOS subdirectory contains a sample XCode 6.1 project to demonstrate how -+Python can be added to an iOS project. After building the Python iOS framework, -+copy it into the ``iOS/XCode-sample`` directory. You should end up with a directory -+structure that looks like this:: -+ -+ XCode-sample/ -+ Python.framework/ - Manually copied into the project -+ app/ -+ sample/ -+ __init__.py -+ main.py - The Python script to be executed -+ app_packages/ - A directory that will be added to the `PYTHONPATH` at runtime -+ sample -+ Images.xcassets -+ en.lproj -+ main.c - The main() definition for the iOS application -+ sample-Info.plist -+ sample-Prefix.pch -+ sample.xcodeproj - The XCode project file -+ -+If you open the project file is project and run it, you should get output -+similar to the following:: -+ -+ 2015-03-14 22:15:19.595 sample[84454:22100187] PythonHome is: /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app -+ 2015-03-14 22:15:19.597 sample[84454:22100187] Initializing Python runtime -+ 2015-03-14 22:15:19.758 sample[84454:22100187] Running /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app/app/sample/main.py -+ Hello, World. -+ 2015-03-14 22:15:19.792 sample[84454:22100187] Leaving -+ -+You can now modify the provide Python source code, import and use -+code from the Python standard library, and add third-party modules to -+app_packages. -+ -+The sample app is a console-only app, so it isn't of any real practical use. -+Python can be embedded into any Objective-C project using the normal Python -+APIs for embedding; but if you want to write a full iOS app in Python, or -+you want to access iOS services from within embedded code, you'll need to -+bridge between the Objective-C environment and the Python environment. -+This binding isn't something that Python does out of the box; you'll need -+to use a third-party library like `Rubicon ObjC`_, `Pyobjus`_ or `PyObjC`_. -+ -+.. _Rubicon ObjC: http://pybee.org/rubicon -+.. _Pyobjus: http://pyobjus.readthedocs.org/ -+.. _PyObjC: https://pythonhosted.org/pyobjc/ ---- /dev/null -+++ b/iOS/XCode-sample/app/sample/main.py -@@ -0,0 +1,3 @@ -+ -+if __name__ == '__main__': -+ print("Hello, World.") ---- /dev/null -+++ b/iOS/XCode-sample/app_packages/README -@@ -0,0 +1 @@ -+This directory exists so that 3rd party packages can be installed here. -\ No newline at end of file ---- /dev/null -+++ b/iOS/XCode-sample/sample.xcodeproj/project.pbxproj -@@ -0,0 +1,353 @@ -+// !$*UTF8*$! -+{ -+ archiveVersion = 1; -+ classes = { -+ }; -+ objectVersion = 46; -+ objects = { -+ -+/* Begin PBXBuildFile section */ -+ 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE519190F4100A9926B /* Foundation.framework */; }; -+ 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE719190F4100A9926B /* CoreGraphics.framework */; }; -+ 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE919190F4100A9926B /* UIKit.framework */; }; -+ 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60796EEE19190F4100A9926B /* InfoPlist.strings */; }; -+ 60796EF219190F4100A9926B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 60796EF119190F4100A9926B /* main.m */; }; -+ 60796EF819190F4100A9926B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60796EF719190F4100A9926B /* Images.xcassets */; }; -+ 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1819190FBB00A9926B /* libz.dylib */; }; -+ 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1F1919174D00A9926B /* libsqlite3.dylib */; }; -+ 60796F2C1919C70800A9926B /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F2B1919C70800A9926B /* Python.framework */; }; -+ 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F38191CDBBA00A9926B /* CoreFoundation.framework */; }; -+/* End PBXBuildFile section */ -+ -+/* Begin PBXFileReference section */ -+ 60796EE219190F4100A9926B /* sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 60796EE519190F4100A9926B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; -+ 60796EE719190F4100A9926B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; -+ 60796EE919190F4100A9926B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; -+ 60796EED19190F4100A9926B /* sample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "sample-Info.plist"; sourceTree = ""; }; -+ 60796EEF19190F4100A9926B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; -+ 60796EF119190F4100A9926B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; -+ 60796EF319190F4100A9926B /* sample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "sample-Prefix.pch"; sourceTree = ""; }; -+ 60796EF719190F4100A9926B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; -+ 60796F1819190FBB00A9926B /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; -+ 60796F1F1919174D00A9926B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; -+ 60796F2B1919C70800A9926B /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; -+ 60796F38191CDBBA00A9926B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; -+ 60F0BABD191FC83F006EC268 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = SOURCE_ROOT; }; -+ 60F0BABF191FC868006EC268 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = SOURCE_ROOT; }; -+/* End PBXFileReference section */ -+ -+/* Begin PBXFrameworksBuildPhase section */ -+ 60796EDF19190F4100A9926B /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */, -+ 60796F2C1919C70800A9926B /* Python.framework in Frameworks */, -+ 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */, -+ 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */, -+ 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */, -+ 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */, -+ 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXFrameworksBuildPhase section */ -+ -+/* Begin PBXGroup section */ -+ 60796ED919190F4100A9926B = { -+ isa = PBXGroup; -+ children = ( -+ 60796EEB19190F4100A9926B /* sample */, -+ 60796EE419190F4100A9926B /* Frameworks */, -+ 60796EE319190F4100A9926B /* Products */, -+ ); -+ sourceTree = ""; -+ }; -+ 60796EE319190F4100A9926B /* Products */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796EE219190F4100A9926B /* sample.app */, -+ ); -+ name = Products; -+ sourceTree = ""; -+ }; -+ 60796EE419190F4100A9926B /* Frameworks */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796F1F1919174D00A9926B /* libsqlite3.dylib */, -+ 60796F1819190FBB00A9926B /* libz.dylib */, -+ 60796F38191CDBBA00A9926B /* CoreFoundation.framework */, -+ 60796EE719190F4100A9926B /* CoreGraphics.framework */, -+ 60796EE519190F4100A9926B /* Foundation.framework */, -+ 60796F2B1919C70800A9926B /* Python.framework */, -+ 60796EE919190F4100A9926B /* UIKit.framework */, -+ ); -+ name = Frameworks; -+ sourceTree = ""; -+ }; -+ 60796EEB19190F4100A9926B /* sample */ = { -+ isa = PBXGroup; -+ children = ( -+ 60F0BABD191FC83F006EC268 /* app */, -+ 60F0BABF191FC868006EC268 /* app_packages */, -+ 60796EF719190F4100A9926B /* Images.xcassets */, -+ 60796EEC19190F4100A9926B /* Supporting Files */, -+ ); -+ path = sample; -+ sourceTree = ""; -+ }; -+ 60796EEC19190F4100A9926B /* Supporting Files */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796EED19190F4100A9926B /* sample-Info.plist */, -+ 60796EEE19190F4100A9926B /* InfoPlist.strings */, -+ 60796EF119190F4100A9926B /* main.m */, -+ 60796EF319190F4100A9926B /* sample-Prefix.pch */, -+ ); -+ name = "Supporting Files"; -+ sourceTree = ""; -+ }; -+/* End PBXGroup section */ -+ -+/* Begin PBXNativeTarget section */ -+ 60796EE119190F4100A9926B /* sample */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */; -+ buildPhases = ( -+ 60796F2F1919C7E700A9926B /* Refresh Python source */, -+ 60796EDE19190F4100A9926B /* Sources */, -+ 60796EDF19190F4100A9926B /* Frameworks */, -+ 60796EE019190F4100A9926B /* Resources */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ ); -+ name = sample; -+ productName = sample; -+ productReference = 60796EE219190F4100A9926B /* sample.app */; -+ productType = "com.apple.product-type.application"; -+ }; -+/* End PBXNativeTarget section */ -+ -+/* Begin PBXProject section */ -+ 60796EDA19190F4100A9926B /* Project object */ = { -+ isa = PBXProject; -+ attributes = { -+ CLASSPREFIX = Py; -+ LastUpgradeCheck = 0630; -+ ORGANIZATIONNAME = "Example Corp"; -+ }; -+ buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */; -+ compatibilityVersion = "Xcode 3.2"; -+ developmentRegion = English; -+ hasScannedForEncodings = 0; -+ knownRegions = ( -+ en, -+ ); -+ mainGroup = 60796ED919190F4100A9926B; -+ productRefGroup = 60796EE319190F4100A9926B /* Products */; -+ projectDirPath = ""; -+ projectRoot = ""; -+ targets = ( -+ 60796EE119190F4100A9926B /* sample */, -+ ); -+ }; -+/* End PBXProject section */ -+ -+/* Begin PBXResourcesBuildPhase section */ -+ 60796EE019190F4100A9926B /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */, -+ 60796EF819190F4100A9926B /* Images.xcassets in Resources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXResourcesBuildPhase section */ -+ -+/* Begin PBXShellScriptBuildPhase section */ -+ 60796F2F1919C7E700A9926B /* Refresh Python source */ = { -+ isa = PBXShellScriptBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Refresh Python source"; -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nmkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/lib $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/include $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app_packages/ $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\n"; -+ }; -+/* End PBXShellScriptBuildPhase section */ -+ -+/* Begin PBXSourcesBuildPhase section */ -+ 60796EDE19190F4100A9926B /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796EF219190F4100A9926B /* main.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXSourcesBuildPhase section */ -+ -+/* Begin PBXVariantGroup section */ -+ 60796EEE19190F4100A9926B /* InfoPlist.strings */ = { -+ isa = PBXVariantGroup; -+ children = ( -+ 60796EEF19190F4100A9926B /* en */, -+ ); -+ name = InfoPlist.strings; -+ sourceTree = ""; -+ }; -+/* End PBXVariantGroup section */ -+ -+/* Begin XCBuildConfiguration section */ -+ 60796F0C19190F4100A9926B /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ COPY_PHASE_STRIP = NO; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ GCC_DYNAMIC_NO_PIC = NO; -+ GCC_OPTIMIZATION_LEVEL = 0; -+ GCC_PREPROCESSOR_DEFINITIONS = ( -+ "DEBUG=1", -+ "$(inherited)", -+ ); -+ GCC_SYMBOLS_PRIVATE_EXTERN = NO; -+ 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 = 7.1; -+ ONLY_ACTIVE_ARCH = YES; -+ SDKROOT = iphoneos; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ }; -+ name = Debug; -+ }; -+ 60796F0D19190F4100A9926B /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ COPY_PHASE_STRIP = YES; -+ ENABLE_NS_ASSERTIONS = NO; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ 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 = 7.1; -+ SDKROOT = iphoneos; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ VALIDATE_PRODUCT = YES; -+ }; -+ name = Release; -+ }; -+ 60796F0F19190F4100A9926B /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ GCC_PRECOMPILE_PREFIX_HEADER = YES; -+ GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; -+ HEADER_SEARCH_PATHS = ( -+ "$(inherited)", -+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, -+ "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", -+ ); -+ INFOPLIST_FILE = "sample/sample-Info.plist"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ USER_HEADER_SEARCH_PATHS = include/python2.7; -+ WRAPPER_EXTENSION = app; -+ }; -+ name = Debug; -+ }; -+ 60796F1019190F4100A9926B /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ GCC_PRECOMPILE_PREFIX_HEADER = YES; -+ GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; -+ HEADER_SEARCH_PATHS = ( -+ "$(inherited)", -+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, -+ "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", -+ ); -+ INFOPLIST_FILE = "sample/sample-Info.plist"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ USER_HEADER_SEARCH_PATHS = include/python2.7; -+ WRAPPER_EXTENSION = app; -+ }; -+ name = Release; -+ }; -+/* End XCBuildConfiguration section */ -+ -+/* Begin XCConfigurationList section */ -+ 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 60796F0C19190F4100A9926B /* Debug */, -+ 60796F0D19190F4100A9926B /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 60796F0F19190F4100A9926B /* Debug */, -+ 60796F1019190F4100A9926B /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+/* End XCConfigurationList section */ -+ }; -+ rootObject = 60796EDA19190F4100A9926B /* Project object */; -+} ---- /dev/null -+++ b/iOS/XCode-sample/sample/Images.xcassets/AppIcon.appiconset/Contents.json -@@ -0,0 +1,53 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "iphone", -+ "size" : "29x29", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "40x40", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "60x60", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "29x29", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "29x29", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "40x40", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "40x40", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "76x76", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "76x76", -+ "scale" : "2x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/iOS/XCode-sample/sample/Images.xcassets/LaunchImage.launchimage/Contents.json -@@ -0,0 +1,51 @@ -+{ -+ "images" : [ -+ { -+ "orientation" : "portrait", -+ "idiom" : "iphone", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "iphone", -+ "subtype" : "retina4", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "1x" -+ }, -+ { -+ "orientation" : "landscape", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "1x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "landscape", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/iOS/XCode-sample/sample/en.lproj/InfoPlist.strings -@@ -0,0 +1 @@ -+/* Localized versions of Info.plist keys */ ---- /dev/null -+++ b/iOS/XCode-sample/sample/main.m -@@ -0,0 +1,111 @@ -+// -+// main.m -+// A main module for starting Python projects under iOS. -+// -+ -+#import -+#import -+#include -+#include -+ -+int main(int argc, char *argv[]) { -+ int ret = 0; -+ unsigned int i; -+ NSString *tmp_path; -+ NSString *python_home; -+ wchar_t *wpython_home; -+ const char* main_script; -+ wchar_t** python_argv; -+ -+ @autoreleasepool { -+ -+ NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; -+ -+ // Special environment to avoid writing bytecode because -+ // the process will not have write attribute on the device. -+ putenv("PYTHONDONTWRITEBYTECODE=1"); -+ -+ python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; -+ NSLog(@"PythonHome is: %@", python_home); -+ wpython_home = _Py_char2wchar([python_home UTF8String], NULL); -+ Py_SetPythonHome(wpython_home); -+ -+ // iOS provides a specific directory for temp files. -+ tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; -+ putenv((char *)[tmp_path UTF8String]); -+ -+ NSLog(@"Initializing Python runtime"); -+ Py_Initialize(); -+ -+ // Set the name of the main script -+ main_script = [ -+ [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.sample/app/sample/main" -+ ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; -+ -+ if (main_script == NULL) { -+ NSLog(@"Unable to locate app/sample/main.py file"); -+ exit(-1); -+ } -+ -+ // Construct argv for the interpreter -+ python_argv = PyMem_RawMalloc(sizeof(wchar_t*) * argc); -+ -+ python_argv[0] = _Py_char2wchar(main_script, NULL); -+ for (i = 1; i < argc; i++) { -+ python_argv[i] = _Py_char2wchar(argv[i], NULL); -+ } -+ -+ PySys_SetArgv(argc, python_argv); -+ -+ // If other modules are using threads, we need to initialize them. -+ PyEval_InitThreads(); -+ -+ // Start the main.py script -+ NSLog(@"Running %s", main_script); -+ -+ @try { -+ FILE* fd = fopen(main_script, "r"); -+ if (fd == NULL) { -+ ret = 1; -+ NSLog(@"Unable to open main.py, abort."); -+ } else { -+ ret = PyRun_SimpleFileEx(fd, main_script, 1); -+ if (ret != 0) { -+ NSLog(@"Application quit abnormally!"); -+ } else { -+ // In a normal iOS application, the following line is what -+ // actually runs the application. It requires that the -+ // Objective-C runtime environment has a class named -+ // "PythonAppDelegate". This project doesn't define -+ // one, because Objective-C bridging isn't something -+ // Python does out of the box. You'll need to use -+ // a library like Rubicon-ObjC [1], Pyobjus [2] or -+ // PyObjC [3] if you want to run an *actual* iOS app. -+ // [1] http://pybee.org/rubicon -+ // [2] http://pyobjus.readthedocs.org/ -+ // [3] https://pythonhosted.org/pyobjc/ -+ -+ UIApplicationMain(argc, argv, nil, @"PythonAppDelegate"); -+ } -+ } -+ } -+ @catch (NSException *exception) { -+ NSLog(@"Python runtime error: %@", [exception reason]); -+ } -+ @finally { -+ Py_Finalize(); -+ } -+ -+ PyMem_RawFree(wpython_home); -+ if (python_argv) { -+ for (i = 0; i < argc; i++) { -+ PyMem_RawFree(python_argv[i]); -+ } -+ PyMem_RawFree(python_argv); -+ } -+ NSLog(@"Leaving"); -+ } -+ -+ exit(ret); -+ return ret; -+} -\ No newline at end of file ---- /dev/null -+++ b/iOS/XCode-sample/sample/sample-Info.plist -@@ -0,0 +1,45 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ en -+ CFBundleDisplayName -+ ${PRODUCT_NAME} -+ CFBundleExecutable -+ ${EXECUTABLE_NAME} -+ CFBundleIdentifier -+ com.example.${PRODUCT_NAME:rfc1034identifier} -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundleName -+ ${PRODUCT_NAME} -+ CFBundlePackageType -+ APPL -+ CFBundleShortVersionString -+ 1.0 -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ 1.0 -+ LSRequiresIPhoneOS -+ -+ UIRequiredDeviceCapabilities -+ -+ armv7 -+ -+ UISupportedInterfaceOrientations -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ UISupportedInterfaceOrientations~ipad -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationPortraitUpsideDown -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ -+ -\ No newline at end of file ---- /dev/null -+++ b/iOS/XCode-sample/sample/sample-Prefix.pch -@@ -0,0 +1,16 @@ -+// -+// Prefix header -+// -+// The contents of this file are implicitly included at the beginning of every source file. -+// -+ -+#import -+ -+#ifndef __IPHONE_3_0 -+#warning "This project uses features only available in iOS SDK 3.0 and later." -+#endif -+ -+#ifdef __OBJC__ -+ #import -+ #import -+#endif -\ No newline at end of file ---- /dev/null -+++ b/tvOS/Info.plist -@@ -0,0 +1,20 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ English -+ CFBundleExecutable -+ Python -+ CFBundleIdentifier -+ org.python -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundlePackageType -+ FMWK -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ xxxVERSIONxxx -+ -+ ---- /dev/null -+++ b/tvOS/README -@@ -0,0 +1,161 @@ -+===================== -+Python on tvOS README -+===================== -+ -+:Authors: -+ Russell Keith-Magee (2015) -+ -+:Version: 3.5.2 -+ -+This document provides a overview of eccentricities of building and using -+Python on tvOS devices (i.e., AppleTV). -+ -+Build instructions -+================== -+ -+The tvOS build must be run on an Mac with XCode installed. To build the tvOS -+framework, unpack the Python sources, move into the tvOS subdirectory, and -+run ``make``. There are no configuration options to this build process - -+it will use XCode utilities to identify the location of compilers, -+resource directories, and so on. -+ -+The build process will configure and build Python 3 times, producing: -+ -+ * A "host" version of Python -+ * A version of Python compiled for the x86-64 tvOS Simulator -+ * A version of Python compiled for ARM64 tvOS devices -+ -+Build products will be "installed" into tvOS/build. The built products will -+then be combined into a single "fat" ``Python.framework`` that can be added to -+an XCode project. The resulting framework will be located in the root -+directory of the Python source tree. -+ -+A ``make clean`` target also exists to clean out all build products; -+``make distclean`` will clean out all user-specific files from the test and -+sample projects. -+ -+Test instructions -+----------------- -+ -+The ``Tools`` directory contains an ``tvOS-Test`` project that enables you to -+run the Python regression test suite. When you run ``make`` in the tvOS -+directory, a copy of ``Python.framework`` will also be installed into this -+test project. -+ -+To run the test project, load the project into XCode, and run (either on a -+device or in the simulator). The test suite takes around 10 minutes to run on -+an gen 4 AppleTV. -+ -+.. note:: If you run the test project in debug mode, the XCode debugger will -+ stop whenever a signal is raised. The Python regression test suite checks -+ a number of signal handlers, and the test suite will stop mid-execution -+ when this occurs. -+ -+ To disable this signal handling, set a breakpoint at the start of -+ ``main.c``; when execution stops at the breakpoint, run the following -+ commands in the debugger (at the ``(lldb)`` prompt in the console log -+ window):: -+ -+ process handle SIGPIPE -n true -p true -s false -+ process handle SIGINT -n true -p true -s false -+ process handle SIGXFSZ -n true -p true -s false -+ process handle SIGUSR1 -n true -p true -s false -+ process handle SIGUSR2 -n true -p true -s false -+ -+ Unfortunately, this has to be done every time the test suite is executed. -+ -+tvOS-specific details -+==================== -+ -+* ``import sys; sys.platform`` will report as `'tvos'`, regardless of whether you -+ are on a simulator or a real platform. -+ -+* ``import platform; platform.machine()`` will return the device identifier. -+ For example, a Generation 4 Apple TV will return `'AppleTV5,3'` -+ -+* The following modules are not currently supported: -+ -+ - ``bsddb`` -+ - ``bz2`` -+ - ``curses`` -+ - ``dbm`` -+ - ``gdbm`` -+ - ``hotshot`` -+ - ``idlelib`` -+ - ``lzma`` -+ - ``nis`` -+ - ``ossaudiodev`` -+ - ``readline`` -+ - ``spwd`` -+ - ``sqlite3`` -+ - ``ssl`` -+ - ``tkinter`` -+ - ``turtledemo`` -+ - ``wsgiref`` -+ -+* Due to limitations in using dynamic loading on tvOS, binary Python modules must be -+ statically-linked into the executable. The framework package produced by the tvOS -+ ``make install`` statically links all the supported standard library modules. -+ If you have a third-party Python binary module, you'll need to incorporate the -+ source files for that module into the sources for your own app. -+ -+ If you want to add or remove a binary module from the set that is included in the -+ Python library, you can do so by providing module setup files for each platform. -+ There are two default module configuration files: -+ -+ - ``Modules/Setup.tvOS-aarch64`` for ARM64 tvOS builds -+ - ``Modules/Setup.tvOS-x86_64`` for x86_64 tvOS simulator builds -+ -+ If you copy these files to a ``.local`` version (e.g., -+ ``Modules/Setup.tvOS-aarch64.local``), the local version will override the -+ default. You can then make modifications to the modules that will be included -+ in the tvOS framework, and the flags passed to the compiler when compiling those -+ modules. -+ -+Adding Python to an tvOS project -+=============================== -+ -+The tvOS subdirectory contains a sample XCode 6.1 project to demonstrate how -+Python can be added to an tvOS project. After building the Python tvOS framework, -+copy it into the ``tvOS/XCode-sample`` directory. You should end up with a directory -+structure that looks like this:: -+ -+ XCode-sample/ -+ Python.framework/ - Manually copied into the project -+ app/ -+ sample/ -+ __init__.py -+ main.py - The Python script to be executed -+ app_packages/ - A directory that will be added to the `PYTHONPATH` at runtime -+ sample -+ Images.xcassets -+ en.lproj -+ main.c - The main() definition for the tvOS application -+ sample-Info.plist -+ sample-Prefix.pch -+ sample.xcodeproj - The XCode project file -+ -+If you open the project file is project and run it, you should get output -+similar to the following:: -+ -+ 2015-03-14 22:15:19.595 sample[84454:22100187] PythonHome is: /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app -+ 2015-03-14 22:15:19.597 sample[84454:22100187] Initializing Python runtime -+ 2015-03-14 22:15:19.758 sample[84454:22100187] Running /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app/app/sample/main.py -+ Hello, World. -+ 2015-03-14 22:15:19.792 sample[84454:22100187] Leaving -+ -+You can now modify the provide Python source code, import and use -+code from the Python standard library, and add third-party modules to -+app_packages. -+ -+The sample app is a console-only app, so it isn't of any real practical use. -+Python can be embedded into any Objective-C project using the normal Python -+APIs for embedding; but if you want to write a full tvOS app in Python, or -+you want to access tvOS services from within embedded code, you'll need to -+bridge between the Objective-C environment and the Python environment. -+This binding isn't something that Python does out of the box; you'll need -+to use a third-party library like `Rubicon ObjC`_, `Pyobjus`_ or `PyObjC`_. -+ -+.. _Rubicon ObjC: http://pybee.org/rubicon -+.. _Pyobjus: http://pyobjus.readthedocs.org/ -+.. _PyObjC: https://pythonhosted.org/pyobjc/ ---- /dev/null -+++ b/tvOS/XCode-sample/app/sample/main.py -@@ -0,0 +1,3 @@ -+ -+if __name__ == '__main__': -+ print("Hello, World.") ---- /dev/null -+++ b/tvOS/XCode-sample/app_packages/README -@@ -0,0 +1 @@ -+This directory exists so that 3rd party packages can be installed here. -\ No newline at end of file ---- /dev/null -+++ b/tvOS/XCode-sample/sample.xcodeproj/project.pbxproj -@@ -0,0 +1,353 @@ -+// !$*UTF8*$! -+{ -+ archiveVersion = 1; -+ classes = { -+ }; -+ objectVersion = 46; -+ objects = { -+ -+/* Begin PBXBuildFile section */ -+ 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE519190F4100A9926B /* Foundation.framework */; }; -+ 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE719190F4100A9926B /* CoreGraphics.framework */; }; -+ 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE919190F4100A9926B /* UIKit.framework */; }; -+ 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60796EEE19190F4100A9926B /* InfoPlist.strings */; }; -+ 60796EF219190F4100A9926B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 60796EF119190F4100A9926B /* main.m */; }; -+ 60796EF819190F4100A9926B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60796EF719190F4100A9926B /* Images.xcassets */; }; -+ 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1819190FBB00A9926B /* libz.dylib */; }; -+ 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1F1919174D00A9926B /* libsqlite3.dylib */; }; -+ 60796F2C1919C70800A9926B /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F2B1919C70800A9926B /* Python.framework */; }; -+ 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F38191CDBBA00A9926B /* CoreFoundation.framework */; }; -+/* End PBXBuildFile section */ -+ -+/* Begin PBXFileReference section */ -+ 60796EE219190F4100A9926B /* sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 60796EE519190F4100A9926B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; -+ 60796EE719190F4100A9926B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; -+ 60796EE919190F4100A9926B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; -+ 60796EED19190F4100A9926B /* sample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "sample-Info.plist"; sourceTree = ""; }; -+ 60796EEF19190F4100A9926B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; -+ 60796EF119190F4100A9926B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; -+ 60796EF319190F4100A9926B /* sample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "sample-Prefix.pch"; sourceTree = ""; }; -+ 60796EF719190F4100A9926B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; -+ 60796F1819190FBB00A9926B /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; -+ 60796F1F1919174D00A9926B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; -+ 60796F2B1919C70800A9926B /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; -+ 60796F38191CDBBA00A9926B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; -+ 60F0BABD191FC83F006EC268 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = SOURCE_ROOT; }; -+ 60F0BABF191FC868006EC268 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = SOURCE_ROOT; }; -+/* End PBXFileReference section */ -+ -+/* Begin PBXFrameworksBuildPhase section */ -+ 60796EDF19190F4100A9926B /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */, -+ 60796F2C1919C70800A9926B /* Python.framework in Frameworks */, -+ 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */, -+ 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */, -+ 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */, -+ 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */, -+ 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXFrameworksBuildPhase section */ -+ -+/* Begin PBXGroup section */ -+ 60796ED919190F4100A9926B = { -+ isa = PBXGroup; -+ children = ( -+ 60796EEB19190F4100A9926B /* sample */, -+ 60796EE419190F4100A9926B /* Frameworks */, -+ 60796EE319190F4100A9926B /* Products */, -+ ); -+ sourceTree = ""; -+ }; -+ 60796EE319190F4100A9926B /* Products */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796EE219190F4100A9926B /* sample.app */, -+ ); -+ name = Products; -+ sourceTree = ""; -+ }; -+ 60796EE419190F4100A9926B /* Frameworks */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796F1F1919174D00A9926B /* libsqlite3.dylib */, -+ 60796F1819190FBB00A9926B /* libz.dylib */, -+ 60796F38191CDBBA00A9926B /* CoreFoundation.framework */, -+ 60796EE719190F4100A9926B /* CoreGraphics.framework */, -+ 60796EE519190F4100A9926B /* Foundation.framework */, -+ 60796F2B1919C70800A9926B /* Python.framework */, -+ 60796EE919190F4100A9926B /* UIKit.framework */, -+ ); -+ name = Frameworks; -+ sourceTree = ""; -+ }; -+ 60796EEB19190F4100A9926B /* sample */ = { -+ isa = PBXGroup; -+ children = ( -+ 60F0BABD191FC83F006EC268 /* app */, -+ 60F0BABF191FC868006EC268 /* app_packages */, -+ 60796EF719190F4100A9926B /* Images.xcassets */, -+ 60796EEC19190F4100A9926B /* Supporting Files */, -+ ); -+ path = sample; -+ sourceTree = ""; -+ }; -+ 60796EEC19190F4100A9926B /* Supporting Files */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796EED19190F4100A9926B /* sample-Info.plist */, -+ 60796EEE19190F4100A9926B /* InfoPlist.strings */, -+ 60796EF119190F4100A9926B /* main.m */, -+ 60796EF319190F4100A9926B /* sample-Prefix.pch */, -+ ); -+ name = "Supporting Files"; -+ sourceTree = ""; -+ }; -+/* End PBXGroup section */ -+ -+/* Begin PBXNativeTarget section */ -+ 60796EE119190F4100A9926B /* sample */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */; -+ buildPhases = ( -+ 60796F2F1919C7E700A9926B /* Refresh Python source */, -+ 60796EDE19190F4100A9926B /* Sources */, -+ 60796EDF19190F4100A9926B /* Frameworks */, -+ 60796EE019190F4100A9926B /* Resources */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ ); -+ name = sample; -+ productName = sample; -+ productReference = 60796EE219190F4100A9926B /* sample.app */; -+ productType = "com.apple.product-type.application"; -+ }; -+/* End PBXNativeTarget section */ -+ -+/* Begin PBXProject section */ -+ 60796EDA19190F4100A9926B /* Project object */ = { -+ isa = PBXProject; -+ attributes = { -+ CLASSPREFIX = Py; -+ LastUpgradeCheck = 0630; -+ ORGANIZATIONNAME = "Example Corp"; -+ }; -+ buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */; -+ compatibilityVersion = "Xcode 3.2"; -+ developmentRegion = English; -+ hasScannedForEncodings = 0; -+ knownRegions = ( -+ en, -+ ); -+ mainGroup = 60796ED919190F4100A9926B; -+ productRefGroup = 60796EE319190F4100A9926B /* Products */; -+ projectDirPath = ""; -+ projectRoot = ""; -+ targets = ( -+ 60796EE119190F4100A9926B /* sample */, -+ ); -+ }; -+/* End PBXProject section */ -+ -+/* Begin PBXResourcesBuildPhase section */ -+ 60796EE019190F4100A9926B /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */, -+ 60796EF819190F4100A9926B /* Images.xcassets in Resources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXResourcesBuildPhase section */ -+ -+/* Begin PBXShellScriptBuildPhase section */ -+ 60796F2F1919C7E700A9926B /* Refresh Python source */ = { -+ isa = PBXShellScriptBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Refresh Python source"; -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nmkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/lib $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/include $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app_packages/ $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\n"; -+ }; -+/* End PBXShellScriptBuildPhase section */ -+ -+/* Begin PBXSourcesBuildPhase section */ -+ 60796EDE19190F4100A9926B /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796EF219190F4100A9926B /* main.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXSourcesBuildPhase section */ -+ -+/* Begin PBXVariantGroup section */ -+ 60796EEE19190F4100A9926B /* InfoPlist.strings */ = { -+ isa = PBXVariantGroup; -+ children = ( -+ 60796EEF19190F4100A9926B /* en */, -+ ); -+ name = InfoPlist.strings; -+ sourceTree = ""; -+ }; -+/* End PBXVariantGroup section */ -+ -+/* Begin XCBuildConfiguration section */ -+ 60796F0C19190F4100A9926B /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ COPY_PHASE_STRIP = NO; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ GCC_DYNAMIC_NO_PIC = NO; -+ GCC_OPTIMIZATION_LEVEL = 0; -+ GCC_PREPROCESSOR_DEFINITIONS = ( -+ "DEBUG=1", -+ "$(inherited)", -+ ); -+ GCC_SYMBOLS_PRIVATE_EXTERN = NO; -+ 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 = 7.1; -+ ONLY_ACTIVE_ARCH = YES; -+ SDKROOT = iphoneos; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ }; -+ name = Debug; -+ }; -+ 60796F0D19190F4100A9926B /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ COPY_PHASE_STRIP = YES; -+ ENABLE_NS_ASSERTIONS = NO; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ 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 = 7.1; -+ SDKROOT = iphoneos; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ VALIDATE_PRODUCT = YES; -+ }; -+ name = Release; -+ }; -+ 60796F0F19190F4100A9926B /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ GCC_PRECOMPILE_PREFIX_HEADER = YES; -+ GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; -+ HEADER_SEARCH_PATHS = ( -+ "$(inherited)", -+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, -+ "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", -+ ); -+ INFOPLIST_FILE = "sample/sample-Info.plist"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ USER_HEADER_SEARCH_PATHS = include/python2.7; -+ WRAPPER_EXTENSION = app; -+ }; -+ name = Debug; -+ }; -+ 60796F1019190F4100A9926B /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ GCC_PRECOMPILE_PREFIX_HEADER = YES; -+ GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; -+ HEADER_SEARCH_PATHS = ( -+ "$(inherited)", -+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, -+ "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", -+ ); -+ INFOPLIST_FILE = "sample/sample-Info.plist"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ USER_HEADER_SEARCH_PATHS = include/python2.7; -+ WRAPPER_EXTENSION = app; -+ }; -+ name = Release; -+ }; -+/* End XCBuildConfiguration section */ -+ -+/* Begin XCConfigurationList section */ -+ 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 60796F0C19190F4100A9926B /* Debug */, -+ 60796F0D19190F4100A9926B /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 60796F0F19190F4100A9926B /* Debug */, -+ 60796F1019190F4100A9926B /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+/* End XCConfigurationList section */ -+ }; -+ rootObject = 60796EDA19190F4100A9926B /* Project object */; -+} ---- /dev/null -+++ b/tvOS/XCode-sample/sample/Images.xcassets/AppIcon.appiconset/Contents.json -@@ -0,0 +1,53 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "iphone", -+ "size" : "29x29", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "40x40", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "60x60", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "29x29", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "29x29", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "40x40", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "40x40", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "76x76", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "76x76", -+ "scale" : "2x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/tvOS/XCode-sample/sample/Images.xcassets/LaunchImage.launchimage/Contents.json -@@ -0,0 +1,51 @@ -+{ -+ "images" : [ -+ { -+ "orientation" : "portrait", -+ "idiom" : "iphone", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "iphone", -+ "subtype" : "retina4", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "1x" -+ }, -+ { -+ "orientation" : "landscape", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "1x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "landscape", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/tvOS/XCode-sample/sample/en.lproj/InfoPlist.strings -@@ -0,0 +1 @@ -+/* Localized versions of Info.plist keys */ ---- /dev/null -+++ b/tvOS/XCode-sample/sample/main.m -@@ -0,0 +1,111 @@ -+// -+// main.m -+// A main module for starting Python projects under iOS. -+// -+ -+#import -+#import -+#include -+#include -+ -+int main(int argc, char *argv[]) { -+ int ret = 0; -+ unsigned int i; -+ NSString *tmp_path; -+ NSString *python_home; -+ wchar_t *wpython_home; -+ const char* main_script; -+ wchar_t** python_argv; -+ -+ @autoreleasepool { -+ -+ NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; -+ -+ // Special environment to avoid writing bytecode because -+ // the process will not have write attribute on the device. -+ putenv("PYTHONDONTWRITEBYTECODE=1"); -+ -+ python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; -+ NSLog(@"PythonHome is: %@", python_home); -+ wpython_home = _Py_char2wchar([python_home UTF8String], NULL); -+ Py_SetPythonHome(wpython_home); -+ -+ // iOS provides a specific directory for temp files. -+ tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; -+ putenv((char *)[tmp_path UTF8String]); -+ -+ NSLog(@"Initializing Python runtime"); -+ Py_Initialize(); -+ -+ // Set the name of the main script -+ main_script = [ -+ [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.sample/app/sample/main" -+ ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; -+ -+ if (main_script == NULL) { -+ NSLog(@"Unable to locate app/sample/main.py file"); -+ exit(-1); -+ } -+ -+ // Construct argv for the interpreter -+ python_argv = PyMem_RawMalloc(sizeof(wchar_t*) * argc); -+ -+ python_argv[0] = _Py_char2wchar(main_script, NULL); -+ for (i = 1; i < argc; i++) { -+ python_argv[i] = _Py_char2wchar(argv[i], NULL); -+ } -+ -+ PySys_SetArgv(argc, python_argv); -+ -+ // If other modules are using threads, we need to initialize them. -+ PyEval_InitThreads(); -+ -+ // Start the main.py script -+ NSLog(@"Running %s", main_script); -+ -+ @try { -+ FILE* fd = fopen(main_script, "r"); -+ if (fd == NULL) { -+ ret = 1; -+ NSLog(@"Unable to open main.py, abort."); -+ } else { -+ ret = PyRun_SimpleFileEx(fd, main_script, 1); -+ if (ret != 0) { -+ NSLog(@"Application quit abnormally!"); -+ } else { -+ // In a normal iOS application, the following line is what -+ // actually runs the application. It requires that the -+ // Objective-C runtime environment has a class named -+ // "PythonAppDelegate". This project doesn't define -+ // one, because Objective-C bridging isn't something -+ // Python does out of the box. You'll need to use -+ // a library like Rubicon-ObjC [1], Pyobjus [2] or -+ // PyObjC [3] if you want to run an *actual* iOS app. -+ // [1] http://pybee.org/rubicon -+ // [2] http://pyobjus.readthedocs.org/ -+ // [3] https://pythonhosted.org/pyobjc/ -+ -+ UIApplicationMain(argc, argv, nil, @"PythonAppDelegate"); -+ } -+ } -+ } -+ @catch (NSException *exception) { -+ NSLog(@"Python runtime error: %@", [exception reason]); -+ } -+ @finally { -+ Py_Finalize(); -+ } -+ -+ PyMem_RawFree(wpython_home); -+ if (python_argv) { -+ for (i = 0; i < argc; i++) { -+ PyMem_RawFree(python_argv[i]); -+ } -+ PyMem_RawFree(python_argv); -+ } -+ NSLog(@"Leaving"); -+ } -+ -+ exit(ret); -+ return ret; -+} -\ No newline at end of file ---- /dev/null -+++ b/tvOS/XCode-sample/sample/sample-Info.plist -@@ -0,0 +1,45 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ en -+ CFBundleDisplayName -+ ${PRODUCT_NAME} -+ CFBundleExecutable -+ ${EXECUTABLE_NAME} -+ CFBundleIdentifier -+ com.example.${PRODUCT_NAME:rfc1034identifier} -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundleName -+ ${PRODUCT_NAME} -+ CFBundlePackageType -+ APPL -+ CFBundleShortVersionString -+ 1.0 -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ 1.0 -+ LSRequiresIPhoneOS -+ -+ UIRequiredDeviceCapabilities -+ -+ armv7 -+ -+ UISupportedInterfaceOrientations -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ UISupportedInterfaceOrientations~ipad -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationPortraitUpsideDown -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ -+ -\ No newline at end of file ---- /dev/null -+++ b/tvOS/XCode-sample/sample/sample-Prefix.pch -@@ -0,0 +1,16 @@ -+// -+// Prefix header -+// -+// The contents of this file are implicitly included at the beginning of every source file. -+// -+ -+#import -+ -+#ifndef __IPHONE_3_0 -+#warning "This project uses features only available in iOS SDK 3.0 and later." -+#endif -+ -+#ifdef __OBJC__ -+ #import -+ #import -+#endif -\ No newline at end of file ---- /dev/null -+++ b/watchOS/Info.plist -@@ -0,0 +1,20 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ English -+ CFBundleExecutable -+ Python -+ CFBundleIdentifier -+ org.python -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundlePackageType -+ FMWK -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ xxxVERSIONxxx -+ -+ ---- /dev/null -+++ b/watchOS/README -@@ -0,0 +1,161 @@ -+======================== -+Python on watchOS README -+======================== -+ -+:Authors: -+ Russell Keith-Magee (2015) -+ -+:Version: 3.5.2 -+ -+This document provides a overview of eccentricities of building and using -+Python on watchOS devices (i.e., AppleTV). -+ -+Build instructions -+================== -+ -+The watchOS build must be run on an Mac with XCode installed. To build the watchOS -+framework, unpack the Python sources, move into the watchOS subdirectory, and -+run ``make``. There are no configuration options to this build process - -+it will use XCode utilities to identify the location of compilers, -+resource directories, and so on. -+ -+The build process will configure and build Python 3 times, producing: -+ -+ * A "host" version of Python -+ * A version of Python compiled for the i386 watchOS Simulator -+ * A version of Python compiled for ARMv7k watchOS devices -+ -+Build products will be "installed" into watchOS/build. The built products will -+then be combined into a single "fat" ``Python.framework`` that can be added to -+an XCode project. The resulting framework will be located in the root -+directory of the Python source tree. -+ -+A ``make clean`` target also exists to clean out all build products; -+``make distclean`` will clean out all user-specific files from the test and -+sample projects. -+ -+Test instructions -+----------------- -+ -+The ``Tools`` directory contains an ``watchOS-Test`` project that enables you to -+run the Python regression test suite. When you run ``make`` in the watchOS -+directory, a copy of ``Python.framework`` will also be installed into this -+test project. -+ -+To run the test project, load the project into XCode, and run (either on a -+device or in the simulator). The test suite takes around 10 minutes to run on -+an Apple Watch. -+ -+.. note:: If you run the test project in debug mode, the XCode debugger will -+ stop whenever a signal is raised. The Python regression test suite checks -+ a number of signal handlers, and the test suite will stop mid-execution -+ when this occurs. -+ -+ To disable this signal handling, set a breakpoint at the start of -+ ``main.c``; when execution stops at the breakpoint, run the following -+ commands in the debugger (at the ``(lldb)`` prompt in the console log -+ window):: -+ -+ process handle SIGPIPE -n true -p true -s false -+ process handle SIGINT -n true -p true -s false -+ process handle SIGXFSZ -n true -p true -s false -+ process handle SIGUSR1 -n true -p true -s false -+ process handle SIGUSR2 -n true -p true -s false -+ -+ Unfortunately, this has to be done every time the test suite is executed. -+ -+watchOS-specific details -+==================== -+ -+* ``import sys; sys.platform`` will report as `'watchos'`, regardless of whether you -+ are on a simulator or a real platform. -+ -+* ``import platform; platform.machine()`` will return the device identifier. -+ For example, an origianl Apple Watch will return `'Watch1,1'` -+ -+* The following modules are not currently supported: -+ -+ - ``bsddb`` -+ - ``bz2`` -+ - ``curses`` -+ - ``dbm`` -+ - ``gdbm`` -+ - ``hotshot`` -+ - ``idlelib`` -+ - ``lzma`` -+ - ``nis`` -+ - ``ossaudiodev`` -+ - ``readline`` -+ - ``spwd`` -+ - ``sqlite3`` -+ - ``ssl`` -+ - ``tkinter`` -+ - ``turtledemo`` -+ - ``wsgiref`` -+ -+* Due to limitations in using dynamic loading on watchOS, binary Python modules must be -+ statically-linked into the executable. The framework package produced by the watchOS -+ ``make install`` statically links all the supported standard library modules. -+ If you have a third-party Python binary module, you'll need to incorporate the -+ source files for that module into the sources for your own app. -+ -+ If you want to add or remove a binary module from the set that is included in the -+ Python library, you can do so by providing module setup files for each platform. -+ There are two default module configuration files: -+ -+ - ``Modules/Setup.watchOS-aarch64`` for ARM64 watchOS builds -+ - ``Modules/Setup.watchOS-x86_64`` for x86_64 watchOS simulator builds -+ -+ If you copy these files to a ``.local`` version (e.g., -+ ``Modules/Setup.watchOS-aarch64.local``), the local version will override the -+ default. You can then make modifications to the modules that will be included -+ in the watchOS framework, and the flags passed to the compiler when compiling those -+ modules. -+ -+Adding Python to an watchOS project -+=============================== -+ -+The watchOS subdirectory contains a sample XCode 6.1 project to demonstrate how -+Python can be added to an watchOS project. After building the Python watchOS framework, -+copy it into the ``watchOS/XCode-sample`` directory. You should end up with a directory -+structure that looks like this:: -+ -+ XCode-sample/ -+ Python.framework/ - Manually copied into the project -+ app/ -+ sample/ -+ __init__.py -+ main.py - The Python script to be executed -+ app_packages/ - A directory that will be added to the `PYTHONPATH` at runtime -+ sample -+ Images.xcassets -+ en.lproj -+ main.c - The main() definition for the watchOS application -+ sample-Info.plist -+ sample-Prefix.pch -+ sample.xcodeproj - The XCode project file -+ -+If you open the project file is project and run it, you should get output -+similar to the following:: -+ -+ 2015-03-14 22:15:19.595 sample[84454:22100187] PythonHome is: /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app -+ 2015-03-14 22:15:19.597 sample[84454:22100187] Initializing Python runtime -+ 2015-03-14 22:15:19.758 sample[84454:22100187] Running /Users/rkm/Library/Developer/CoreSimulator/Devices/19FE988F-E5C3-4A6C-8752-C12DE9BF079D/data/Containers/Bundle/Application/A949B323-FD20-4C76-B370-99AFF294E9D5/sample.app/app/sample/main.py -+ Hello, World. -+ 2015-03-14 22:15:19.792 sample[84454:22100187] Leaving -+ -+You can now modify the provide Python source code, import and use -+code from the Python standard library, and add third-party modules to -+app_packages. -+ -+The sample app is a console-only app, so it isn't of any real practical use. -+Python can be embedded into any Objective-C project using the normal Python -+APIs for embedding; but if you want to write a full watchOS app in Python, or -+you want to access watchOS services from within embedded code, you'll need to -+bridge between the Objective-C environment and the Python environment. -+This binding isn't something that Python does out of the box; you'll need -+to use a third-party library like `Rubicon ObjC`_, `Pyobjus`_ or `PyObjC`_. -+ -+.. _Rubicon ObjC: http://pybee.org/rubicon -+.. _Pyobjus: http://pyobjus.readthedocs.org/ -+.. _PyObjC: https://pythonhosted.org/pyobjc/ ---- /dev/null -+++ b/watchOS/XCode-sample/app/sample/main.py -@@ -0,0 +1,3 @@ -+ -+if __name__ == '__main__': -+ print("Hello, World.") ---- /dev/null -+++ b/watchOS/XCode-sample/app_packages/README -@@ -0,0 +1 @@ -+This directory exists so that 3rd party packages can be installed here. -\ No newline at end of file ---- /dev/null -+++ b/watchOS/XCode-sample/sample.xcodeproj/project.pbxproj -@@ -0,0 +1,353 @@ -+// !$*UTF8*$! -+{ -+ archiveVersion = 1; -+ classes = { -+ }; -+ objectVersion = 46; -+ objects = { -+ -+/* Begin PBXBuildFile section */ -+ 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE519190F4100A9926B /* Foundation.framework */; }; -+ 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE719190F4100A9926B /* CoreGraphics.framework */; }; -+ 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796EE919190F4100A9926B /* UIKit.framework */; }; -+ 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 60796EEE19190F4100A9926B /* InfoPlist.strings */; }; -+ 60796EF219190F4100A9926B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 60796EF119190F4100A9926B /* main.m */; }; -+ 60796EF819190F4100A9926B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 60796EF719190F4100A9926B /* Images.xcassets */; }; -+ 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1819190FBB00A9926B /* libz.dylib */; }; -+ 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F1F1919174D00A9926B /* libsqlite3.dylib */; }; -+ 60796F2C1919C70800A9926B /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F2B1919C70800A9926B /* Python.framework */; }; -+ 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60796F38191CDBBA00A9926B /* CoreFoundation.framework */; }; -+/* End PBXBuildFile section */ -+ -+/* Begin PBXFileReference section */ -+ 60796EE219190F4100A9926B /* sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sample.app; sourceTree = BUILT_PRODUCTS_DIR; }; -+ 60796EE519190F4100A9926B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; -+ 60796EE719190F4100A9926B /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; -+ 60796EE919190F4100A9926B /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; -+ 60796EED19190F4100A9926B /* sample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "sample-Info.plist"; sourceTree = ""; }; -+ 60796EEF19190F4100A9926B /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; -+ 60796EF119190F4100A9926B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; -+ 60796EF319190F4100A9926B /* sample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "sample-Prefix.pch"; sourceTree = ""; }; -+ 60796EF719190F4100A9926B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; -+ 60796F1819190FBB00A9926B /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; -+ 60796F1F1919174D00A9926B /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; -+ 60796F2B1919C70800A9926B /* Python.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Python.framework; sourceTree = ""; }; -+ 60796F38191CDBBA00A9926B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; -+ 60F0BABD191FC83F006EC268 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = SOURCE_ROOT; }; -+ 60F0BABF191FC868006EC268 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = SOURCE_ROOT; }; -+/* End PBXFileReference section */ -+ -+/* Begin PBXFrameworksBuildPhase section */ -+ 60796EDF19190F4100A9926B /* Frameworks */ = { -+ isa = PBXFrameworksBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796F39191CDBBA00A9926B /* CoreFoundation.framework in Frameworks */, -+ 60796F2C1919C70800A9926B /* Python.framework in Frameworks */, -+ 60796F201919174D00A9926B /* libsqlite3.dylib in Frameworks */, -+ 60796F1919190FBB00A9926B /* libz.dylib in Frameworks */, -+ 60796EE819190F4100A9926B /* CoreGraphics.framework in Frameworks */, -+ 60796EEA19190F4100A9926B /* UIKit.framework in Frameworks */, -+ 60796EE619190F4100A9926B /* Foundation.framework in Frameworks */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXFrameworksBuildPhase section */ -+ -+/* Begin PBXGroup section */ -+ 60796ED919190F4100A9926B = { -+ isa = PBXGroup; -+ children = ( -+ 60796EEB19190F4100A9926B /* sample */, -+ 60796EE419190F4100A9926B /* Frameworks */, -+ 60796EE319190F4100A9926B /* Products */, -+ ); -+ sourceTree = ""; -+ }; -+ 60796EE319190F4100A9926B /* Products */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796EE219190F4100A9926B /* sample.app */, -+ ); -+ name = Products; -+ sourceTree = ""; -+ }; -+ 60796EE419190F4100A9926B /* Frameworks */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796F1F1919174D00A9926B /* libsqlite3.dylib */, -+ 60796F1819190FBB00A9926B /* libz.dylib */, -+ 60796F38191CDBBA00A9926B /* CoreFoundation.framework */, -+ 60796EE719190F4100A9926B /* CoreGraphics.framework */, -+ 60796EE519190F4100A9926B /* Foundation.framework */, -+ 60796F2B1919C70800A9926B /* Python.framework */, -+ 60796EE919190F4100A9926B /* UIKit.framework */, -+ ); -+ name = Frameworks; -+ sourceTree = ""; -+ }; -+ 60796EEB19190F4100A9926B /* sample */ = { -+ isa = PBXGroup; -+ children = ( -+ 60F0BABD191FC83F006EC268 /* app */, -+ 60F0BABF191FC868006EC268 /* app_packages */, -+ 60796EF719190F4100A9926B /* Images.xcassets */, -+ 60796EEC19190F4100A9926B /* Supporting Files */, -+ ); -+ path = sample; -+ sourceTree = ""; -+ }; -+ 60796EEC19190F4100A9926B /* Supporting Files */ = { -+ isa = PBXGroup; -+ children = ( -+ 60796EED19190F4100A9926B /* sample-Info.plist */, -+ 60796EEE19190F4100A9926B /* InfoPlist.strings */, -+ 60796EF119190F4100A9926B /* main.m */, -+ 60796EF319190F4100A9926B /* sample-Prefix.pch */, -+ ); -+ name = "Supporting Files"; -+ sourceTree = ""; -+ }; -+/* End PBXGroup section */ -+ -+/* Begin PBXNativeTarget section */ -+ 60796EE119190F4100A9926B /* sample */ = { -+ isa = PBXNativeTarget; -+ buildConfigurationList = 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */; -+ buildPhases = ( -+ 60796F2F1919C7E700A9926B /* Refresh Python source */, -+ 60796EDE19190F4100A9926B /* Sources */, -+ 60796EDF19190F4100A9926B /* Frameworks */, -+ 60796EE019190F4100A9926B /* Resources */, -+ ); -+ buildRules = ( -+ ); -+ dependencies = ( -+ ); -+ name = sample; -+ productName = sample; -+ productReference = 60796EE219190F4100A9926B /* sample.app */; -+ productType = "com.apple.product-type.application"; -+ }; -+/* End PBXNativeTarget section */ -+ -+/* Begin PBXProject section */ -+ 60796EDA19190F4100A9926B /* Project object */ = { -+ isa = PBXProject; -+ attributes = { -+ CLASSPREFIX = Py; -+ LastUpgradeCheck = 0630; -+ ORGANIZATIONNAME = "Example Corp"; -+ }; -+ buildConfigurationList = 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */; -+ compatibilityVersion = "Xcode 3.2"; -+ developmentRegion = English; -+ hasScannedForEncodings = 0; -+ knownRegions = ( -+ en, -+ ); -+ mainGroup = 60796ED919190F4100A9926B; -+ productRefGroup = 60796EE319190F4100A9926B /* Products */; -+ projectDirPath = ""; -+ projectRoot = ""; -+ targets = ( -+ 60796EE119190F4100A9926B /* sample */, -+ ); -+ }; -+/* End PBXProject section */ -+ -+/* Begin PBXResourcesBuildPhase section */ -+ 60796EE019190F4100A9926B /* Resources */ = { -+ isa = PBXResourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796EF019190F4100A9926B /* InfoPlist.strings in Resources */, -+ 60796EF819190F4100A9926B /* Images.xcassets in Resources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXResourcesBuildPhase section */ -+ -+/* Begin PBXShellScriptBuildPhase section */ -+ 60796F2F1919C7E700A9926B /* Refresh Python source */ = { -+ isa = PBXShellScriptBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ ); -+ inputPaths = ( -+ ); -+ name = "Refresh Python source"; -+ outputPaths = ( -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ shellPath = /bin/sh; -+ shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nmkdir -p $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/lib $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/Python.framework/Resources/include $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Application\\ Support/org.python.$PROJECT_NAME\nrsync -pvtrL --exclude .hg --exclude .svn --exclude .git $PROJECT_DIR/app_packages/ $BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/Python.framework/Resources/lib/python`readlink $PROJECT_DIR/Python.framework/Versions/Current`/site-packages/\n"; -+ }; -+/* End PBXShellScriptBuildPhase section */ -+ -+/* Begin PBXSourcesBuildPhase section */ -+ 60796EDE19190F4100A9926B /* Sources */ = { -+ isa = PBXSourcesBuildPhase; -+ buildActionMask = 2147483647; -+ files = ( -+ 60796EF219190F4100A9926B /* main.m in Sources */, -+ ); -+ runOnlyForDeploymentPostprocessing = 0; -+ }; -+/* End PBXSourcesBuildPhase section */ -+ -+/* Begin PBXVariantGroup section */ -+ 60796EEE19190F4100A9926B /* InfoPlist.strings */ = { -+ isa = PBXVariantGroup; -+ children = ( -+ 60796EEF19190F4100A9926B /* en */, -+ ); -+ name = InfoPlist.strings; -+ sourceTree = ""; -+ }; -+/* End PBXVariantGroup section */ -+ -+/* Begin XCBuildConfiguration section */ -+ 60796F0C19190F4100A9926B /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ COPY_PHASE_STRIP = NO; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ GCC_DYNAMIC_NO_PIC = NO; -+ GCC_OPTIMIZATION_LEVEL = 0; -+ GCC_PREPROCESSOR_DEFINITIONS = ( -+ "DEBUG=1", -+ "$(inherited)", -+ ); -+ GCC_SYMBOLS_PRIVATE_EXTERN = NO; -+ 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 = 7.1; -+ ONLY_ACTIVE_ARCH = YES; -+ SDKROOT = iphoneos; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ }; -+ name = Debug; -+ }; -+ 60796F0D19190F4100A9926B /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ALWAYS_SEARCH_USER_PATHS = NO; -+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; -+ CLANG_CXX_LIBRARY = "libc++"; -+ CLANG_ENABLE_MODULES = YES; -+ CLANG_ENABLE_OBJC_ARC = YES; -+ CLANG_WARN_BOOL_CONVERSION = YES; -+ CLANG_WARN_CONSTANT_CONVERSION = YES; -+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; -+ CLANG_WARN_EMPTY_BODY = YES; -+ CLANG_WARN_ENUM_CONVERSION = YES; -+ CLANG_WARN_INT_CONVERSION = YES; -+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; -+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; -+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; -+ COPY_PHASE_STRIP = YES; -+ ENABLE_NS_ASSERTIONS = NO; -+ GCC_C_LANGUAGE_STANDARD = gnu99; -+ 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 = 7.1; -+ SDKROOT = iphoneos; -+ TARGETED_DEVICE_FAMILY = "1,2"; -+ VALIDATE_PRODUCT = YES; -+ }; -+ name = Release; -+ }; -+ 60796F0F19190F4100A9926B /* Debug */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ GCC_PRECOMPILE_PREFIX_HEADER = YES; -+ GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; -+ HEADER_SEARCH_PATHS = ( -+ "$(inherited)", -+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, -+ "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", -+ ); -+ INFOPLIST_FILE = "sample/sample-Info.plist"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ USER_HEADER_SEARCH_PATHS = include/python2.7; -+ WRAPPER_EXTENSION = app; -+ }; -+ name = Debug; -+ }; -+ 60796F1019190F4100A9926B /* Release */ = { -+ isa = XCBuildConfiguration; -+ buildSettings = { -+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; -+ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; -+ FRAMEWORK_SEARCH_PATHS = ( -+ "$(inherited)", -+ "$(PROJECT_DIR)", -+ ); -+ GCC_PRECOMPILE_PREFIX_HEADER = YES; -+ GCC_PREFIX_HEADER = "sample/sample-Prefix.pch"; -+ HEADER_SEARCH_PATHS = ( -+ "$(inherited)", -+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, -+ "\"$(PROJECT_DIR)/Python.framework/Resources/include/python2.7\"", -+ ); -+ INFOPLIST_FILE = "sample/sample-Info.plist"; -+ PRODUCT_NAME = "$(TARGET_NAME)"; -+ USER_HEADER_SEARCH_PATHS = include/python2.7; -+ WRAPPER_EXTENSION = app; -+ }; -+ name = Release; -+ }; -+/* End XCBuildConfiguration section */ -+ -+/* Begin XCConfigurationList section */ -+ 60796EDD19190F4100A9926B /* Build configuration list for PBXProject "sample" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 60796F0C19190F4100A9926B /* Debug */, -+ 60796F0D19190F4100A9926B /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+ 60796F0E19190F4100A9926B /* Build configuration list for PBXNativeTarget "sample" */ = { -+ isa = XCConfigurationList; -+ buildConfigurations = ( -+ 60796F0F19190F4100A9926B /* Debug */, -+ 60796F1019190F4100A9926B /* Release */, -+ ); -+ defaultConfigurationIsVisible = 0; -+ defaultConfigurationName = Release; -+ }; -+/* End XCConfigurationList section */ -+ }; -+ rootObject = 60796EDA19190F4100A9926B /* Project object */; -+} ---- /dev/null -+++ b/watchOS/XCode-sample/sample/Images.xcassets/AppIcon.appiconset/Contents.json -@@ -0,0 +1,53 @@ -+{ -+ "images" : [ -+ { -+ "idiom" : "iphone", -+ "size" : "29x29", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "40x40", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "iphone", -+ "size" : "60x60", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "29x29", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "29x29", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "40x40", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "40x40", -+ "scale" : "2x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "76x76", -+ "scale" : "1x" -+ }, -+ { -+ "idiom" : "ipad", -+ "size" : "76x76", -+ "scale" : "2x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/watchOS/XCode-sample/sample/Images.xcassets/LaunchImage.launchimage/Contents.json -@@ -0,0 +1,51 @@ -+{ -+ "images" : [ -+ { -+ "orientation" : "portrait", -+ "idiom" : "iphone", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "iphone", -+ "subtype" : "retina4", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "1x" -+ }, -+ { -+ "orientation" : "landscape", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "1x" -+ }, -+ { -+ "orientation" : "portrait", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ }, -+ { -+ "orientation" : "landscape", -+ "idiom" : "ipad", -+ "extent" : "full-screen", -+ "minimum-system-version" : "7.0", -+ "scale" : "2x" -+ } -+ ], -+ "info" : { -+ "version" : 1, -+ "author" : "xcode" -+ } -+} -\ No newline at end of file ---- /dev/null -+++ b/watchOS/XCode-sample/sample/en.lproj/InfoPlist.strings -@@ -0,0 +1 @@ -+/* Localized versions of Info.plist keys */ ---- /dev/null -+++ b/watchOS/XCode-sample/sample/main.m -@@ -0,0 +1,111 @@ -+// -+// main.m -+// A main module for starting Python projects under iOS. -+// -+ -+#import -+#import -+#include -+#include -+ -+int main(int argc, char *argv[]) { -+ int ret = 0; -+ unsigned int i; -+ NSString *tmp_path; -+ NSString *python_home; -+ char *wpython_home; -+ const char* main_script; -+ char** python_argv; -+ @autoreleasepool { -+ -+ NSString * resourcePath = [[NSBundle mainBundle] resourcePath]; -+ -+ // Special environment to avoid writing bytecode because -+ // the process will not have write attribute on the device. -+ putenv("PYTHONDONTWRITEBYTECODE=1"); -+ -+ python_home = [NSString stringWithFormat:@"%@/Library/Python.framework/Resources", resourcePath, nil]; -+ NSLog(@"PythonHome is: %@", python_home); -+ wpython_home = strdup([python_home UTF8String]); -+ Py_SetPythonHome(wpython_home); -+ -+ // iOS provides a specific directory for temp files. -+ tmp_path = [NSString stringWithFormat:@"TMP=%@/tmp", resourcePath, nil]; -+ putenv((char *)[tmp_path UTF8String]); -+ -+ NSLog(@"Initializing Python runtime"); -+ Py_Initialize(); -+ -+ // Set the name of the main script -+ main_script = [ -+ [[NSBundle mainBundle] pathForResource:@"Library/Application Support/org.python.sample/app/sample/main" -+ ofType:@"py"] cStringUsingEncoding:NSUTF8StringEncoding]; -+ -+ if (main_script == NULL) { -+ NSLog(@"Unable to locate app/sample/main.py file"); -+ exit(-1); -+ } -+ -+ // Construct argv for the interpreter -+ python_argv = PyMem_Malloc(sizeof(char *) * argc); -+ -+ -+ python_argv[0] = strdup(main_script); -+ for (i = 1; i < argc; i++) { -+ python_argv[i] = argv[i]; -+ } -+ -+ PySys_SetArgv(argc, python_argv); -+ -+ // If other modules are using threads, we need to initialize them. -+ PyEval_InitThreads(); -+ -+ // Start the main.py script -+ NSLog(@"Running %s", main_script); -+ -+ @try { -+ FILE* fd = fopen(main_script, "r"); -+ if (fd == NULL) { -+ ret = 1; -+ NSLog(@"Unable to open main.py, abort."); -+ } else { -+ ret = PyRun_SimpleFileEx(fd, main_script, 1); -+ if (ret != 0) { -+ NSLog(@"Application quit abnormally!"); -+ } else { -+ // In a normal iOS application, the following line is what -+ // actually runs the application. It requires that the -+ // Objective-C runtime environment has a class named -+ // "PythonAppDelegate". This project doesn't define -+ // one, because Objective-C bridging isn't something -+ // Python does out of the box. You'll need to use -+ // a library like Rubicon-ObjC [1], Pyobjus [2] or -+ // PyObjC [3] if you want to run an *actual* iOS app. -+ // [1] http://pybee.org/rubicon -+ // [2] http://pyobjus.readthedocs.org/ -+ // [3] https://pythonhosted.org/pyobjc/ -+ -+ UIApplicationMain(argc, argv, nil, @"PythonAppDelegate"); -+ } -+ } -+ } -+ @catch (NSException *exception) { -+ NSLog(@"Python runtime error: %@", [exception reason]); -+ } -+ @finally { -+ Py_Finalize(); -+ } -+ -+ PyMem_Free(wpython_home); -+ if (python_argv) { -+ for (i = 0; i < argc; i++) { -+ PyMem_Free(python_argv[i]); -+ } -+ PyMem_Free(python_argv); -+ } -+ NSLog(@"Leaving"); -+ } -+ -+ exit(ret); -+ return ret; -+} -\ No newline at end of file ---- /dev/null -+++ b/watchOS/XCode-sample/sample/sample-Info.plist -@@ -0,0 +1,45 @@ -+ -+ -+ -+ -+ CFBundleDevelopmentRegion -+ en -+ CFBundleDisplayName -+ ${PRODUCT_NAME} -+ CFBundleExecutable -+ ${EXECUTABLE_NAME} -+ CFBundleIdentifier -+ com.example.${PRODUCT_NAME:rfc1034identifier} -+ CFBundleInfoDictionaryVersion -+ 6.0 -+ CFBundleName -+ ${PRODUCT_NAME} -+ CFBundlePackageType -+ APPL -+ CFBundleShortVersionString -+ 1.0 -+ CFBundleSignature -+ ???? -+ CFBundleVersion -+ 1.0 -+ LSRequiresIPhoneOS -+ -+ UIRequiredDeviceCapabilities -+ -+ armv7 -+ -+ UISupportedInterfaceOrientations -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ UISupportedInterfaceOrientations~ipad -+ -+ UIInterfaceOrientationPortrait -+ UIInterfaceOrientationPortraitUpsideDown -+ UIInterfaceOrientationLandscapeLeft -+ UIInterfaceOrientationLandscapeRight -+ -+ -+ -\ No newline at end of file ---- /dev/null -+++ b/watchOS/XCode-sample/sample/sample-Prefix.pch -@@ -0,0 +1,16 @@ -+// -+// Prefix header -+// -+// The contents of this file are implicitly included at the beginning of every source file. -+// -+ -+#import -+ -+#ifndef __IPHONE_3_0 -+#warning "This project uses features only available in iOS SDK 3.0 and later." -+#endif -+ -+#ifdef __OBJC__ -+ #import -+ #import -+#endif -\ No newline at end of file + AC_SUBST(LIBFFI_INCLUDEDIR) ++AC_SUBST(LIBFFI_LIBDIR) ++AC_SUBST(LIBFFI_LIB) + + # Check for use of the system libmpdec library + AC_MSG_CHECKING(for --with-system-libmpdec) +diff --git a/setup.py b/setup.py +index 0bec170d3f..4e64c30d26 100644 +--- a/setup.py ++++ b/setup.py +@@ -63,6 +63,9 @@ + MS_WINDOWS = (HOST_PLATFORM == 'win32') + CYGWIN = (HOST_PLATFORM == 'cygwin') + MACOS = (HOST_PLATFORM == 'darwin') ++IOS = HOST_PLATFORM.startswith('ios-') ++TVOS = HOST_PLATFORM.startswith('tvos-') ++WATCHOS = HOST_PLATFORM.startswith('watchos-') + AIX = (HOST_PLATFORM.startswith('aix')) + VXWORKS = ('vxworks' in HOST_PLATFORM) + CC = os.environ.get("CC") +@@ -2122,6 +2125,11 @@ + extra_compile_args.append('-DMACOSX') + include_dirs.append('_ctypes/darwin') + ++ if IOS or TVOS or WATCHOS: ++ sources.append('_ctypes/malloc_closure.c') ++ extra_compile_args.append('-DUSING_MALLOC_CLOSURE_DOT_C=1') ++ include_dirs.append('_ctypes/darwin') ++ + elif HOST_PLATFORM == 'sunos5': + # XXX This shouldn't be necessary; it appears that some + # of the assembler code is non-PIC (i.e. it has relocations +@@ -2151,7 +2159,8 @@ + libraries=['m'])) + + ffi_inc = sysconfig.get_config_var("LIBFFI_INCLUDEDIR") +- ffi_lib = None ++ ffi_lib_dir = sysconfig.get_config_var("LIBFFI_LIBDIR") ++ ffi_lib = sysconfig.get_config_var("LIBFFI_LIB") + + ffi_inc_dirs = self.inc_dirs.copy() + if MACOS: +@@ -2180,6 +2189,7 @@ + for lib_name in ('ffi', 'ffi_pic'): + if (self.compiler.find_library_file(self.lib_dirs, lib_name)): + ffi_lib = lib_name ++ self.use_system_libffi = True + break + + if ffi_inc and ffi_lib: +@@ -2193,7 +2203,8 @@ + + ext.include_dirs.append(ffi_inc) + ext.libraries.append(ffi_lib) +- self.use_system_libffi = True ++ if ffi_lib_dir: ++ ext.library_dirs.append(ffi_lib_dir) + + if sysconfig.get_config_var('HAVE_LIBDL'): + # for dlopen, see bpo-32647 diff --git a/patch/Python/Setup.embedded b/patch/Python/Setup.embedded deleted file mode 100644 index 64fefb00..00000000 --- a/patch/Python/Setup.embedded +++ /dev/null @@ -1,147 +0,0 @@ -##################################################################### -# Static compilation instructions for all binary modules. -##################################################################### - -*static* - -_asyncio _asynciomodule.c -_bisect _bisectmodule.c -_blake2 _blake2/blake2module.c _blake2/blake2b_impl.c _blake2/blake2s_impl.c -_bz2 _bz2module.c -I$(srcdir)/../Support/BZip2.xcframework/{{slice}}/Headers -L$(srcdir)/../Support/BZip2.xcframework/{{slice}} -lbzip2 -_codecs_cn cjkcodecs/_codecs_cn.c -_codecs_hk cjkcodecs/_codecs_hk.c -_codecs_iso2022 cjkcodecs/_codecs_iso2022.c -_codecs_jp cjkcodecs/_codecs_jp.c -_codecs_kr cjkcodecs/_codecs_kr.c -_codecs_tw cjkcodecs/_codecs_tw.c -_contextvars _contextvarsmodule.c -_csv _csv.c -_dbm _dbmmodule.c -DHAVE_NDBM_H -_datetime _datetimemodule.c -_elementtree _elementtree.c \ - -I$(srcdir)/Modules/expat - -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI -_hashlib _hashopenssl.c -I$(srcdir)/../Support/OpenSSL.xcframework/{{slice}}/Headers -L$(srcdir)/../Support/OpenSSL.xcframework/{{slice}} -lOpenSSL -DUSE_SSL -_heapq _heapqmodule.c -_json -I$(srcdir)/Include/internal -DPy_BUILD_CORE_BUILTIN _json.c -_lsprof _lsprof.c rotatingtree.c -_lzma _lzmamodule.c -I$(srcdir)/../Support/XZ.xcframework/{{slice}}/Headers -L$(srcdir)/../Support/XZ.xcframework/{{slice}} -lxz -_md5 md5module.c -_multibytecodec cjkcodecs/multibytecodec.c -_multiprocessing -I$(srcdir)/Modules/_multiprocessing _multiprocessing/multiprocessing.c _multiprocessing/semaphore.c -_opcode _opcode.c -_pickle _pickle.c -DPy_BUILD_CORE_MODULE -_posixsubprocess _posixsubprocess.c -_queue _queuemodule.c -_random _randommodule.c -DPy_BUILD_CORE_MODULE -_sha1 sha1module.c -_sha3 _sha3/sha3module.c -_sha256 sha256module.c -DPy_BUILD_CORE_MODULE -_sha512 sha512module.c -DPy_BUILD_CORE_MODULE -_socket socketmodule.c -_sqlite3 -I$(srcdir)/Modules/_sqlite -DMODULE_NAME='\"sqlite3\"' -DSQLITE_OMIT_LOAD_EXTENSION -lsqlite3 \ - _sqlite/cache.c \ - _sqlite/connection.c \ - _sqlite/cursor.c \ - _sqlite/microprotocols.c \ - _sqlite/module.c \ - _sqlite/prepare_protocol.c \ - _sqlite/row.c \ - _sqlite/statement.c \ - _sqlite/util.c -_ssl _ssl.c -I$(srcdir)/../Support/OpenSSL.xcframework/{{slice}}/Headers -L$(srcdir)/../Support/OpenSSL.xcframework/{{slice}} -lOpenSSL -DUSE_SSL -_statistics _statisticsmodule.c -_struct _struct.c -_uuid _uuidmodule.c -_zoneinfo _zoneinfo.c -DPy_BUILD_CORE_MODULE -array arraymodule.c -DPy_BUILD_CORE_MODULE -binascii binascii.c -cmath cmathmodule.c _math.c -fcntl fcntlmodule.c -grp grpmodule.c -math mathmodule.c -DPy_BUILD_CORE_MODULE -mmap mmapmodule.c -parser parsermodule.c -posix -DPy_BUILD_CORE_BUILTIN -I$(srcdir)/Include/internal posixmodule.c -pwd pwdmodule.c -pyexpat expat/xmlparse.c \ - expat/xmlrole.c \ - expat/xmltok.c \ - pyexpat.c \ - -I$(srcdir)/Modules/expat \ - -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI -DXML_DEV_URANDOM -resource resource.c -select selectmodule.c -syslog syslogmodule.c -termios termios.c -unicodedata unicodedata.c -zlib zlibmodule.c -I$(prefix)/include -lz - -##################################################################### -# Modules that will be added by the bootstrap -##################################################################### - -# _abc -# _codecs -# _collections -# _functools -# _io -# _locale -# _operator -# _signal -# _sre -# _stat -# _symtable -# _thread -# _tracemalloc -# _weakref -# atexit -# errno -# faulthandler -# itertools -# posix -# pwd -# time - -##################################################################### -# DISABLED Testing modules -##################################################################### - -*disabled* - -_ctypes_test -_testbuffer -_testcapi -_testimportmultiple -_testinternalcapi -_testmultiphase -_xxsubinterpreters -_xxtestfuzz -xxlimited -xxlimited_35 - -##################################################################### -# DISABLED Modules that require additional frameworks -##################################################################### - -*disabled* - -_gdbm -_tkinter -readline - -##################################################################### -# Modules that exist, but are deprecated by PEP594 and will be -# removed in Python 3.13 -##################################################################### - -*static* - -_crypt _cryptmodule.c -audioop audioop.c - -*disabled* - -nis -ossaudiodev -spwd diff --git a/patch/Python/Setup.iOS b/patch/Python/Setup.iOS deleted file mode 100644 index 5633c2c5..00000000 --- a/patch/Python/Setup.iOS +++ /dev/null @@ -1,49 +0,0 @@ -##################################################################### -# iOS: Platform specific configuration -##################################################################### - -*static* - -_ctypes _ctypes/_ctypes.c \ - _ctypes/callbacks.c \ - _ctypes/callproc.c \ - _ctypes/stgdict.c \ - _ctypes/cfield.c \ - _ctypes/malloc_closure.c \ - -I$(srcdir)/Modules/_ctypes/darwin \ - -I$(srcdir)/../Support/libFFI.xcframework/{{slice}}/Headers \ - -DPy_BUILD_CORE_MODULE \ - -DHAVE_FFI_CLOSURE_ALLOC \ - -DHAVE_FFI_PREP_CIF_VAR \ - -DHAVE_FFI_PREP_CLOSURE_LOC \ - -DUSING_MALLOC_CLOSURE_DOT_C \ - -L$(srcdir)/../Support/libFFI.xcframework/{{slice}} \ - -lFFI - -_decimal _decimal/_decimal.c \ - _decimal/libmpdec/basearith.c \ - _decimal/libmpdec/constants.c \ - _decimal/libmpdec/context.c \ - _decimal/libmpdec/convolute.c \ - _decimal/libmpdec/crt.c \ - _decimal/libmpdec/difradix2.c \ - _decimal/libmpdec/fnt.c \ - _decimal/libmpdec/fourstep.c \ - _decimal/libmpdec/io.c \ - _decimal/libmpdec/mpalloc.c \ - _decimal/libmpdec/mpdecimal.c \ - _decimal/libmpdec/numbertheory.c \ - _decimal/libmpdec/sixstep.c \ - _decimal/libmpdec/transpose.c \ - -I$(srcdir)/Modules/_decimal/libmpdec \ - -DCONFIG_64 -DANSI -DHAVE_UINT128_T - -##################################################################### -# DISABLED Modules that require additional frameworks -##################################################################### - -*disabled* - -_curses -_curses_panel -_posixshmem diff --git a/patch/Python/Setup.macOS b/patch/Python/Setup.macOS deleted file mode 100644 index 293fffe5..00000000 --- a/patch/Python/Setup.macOS +++ /dev/null @@ -1,48 +0,0 @@ -##################################################################### -# macOS: Platform specific configuration -##################################################################### - -*static* - -_ctypes _ctypes/_ctypes.c \ - _ctypes/callbacks.c \ - _ctypes/callproc.c \ - _ctypes/stgdict.c \ - _ctypes/cfield.c \ - _ctypes/malloc_closure.c \ - -I$(srcdir)/Modules/_ctypes/darwin \ - -I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/ffi \ - -DPy_BUILD_CORE_MODULE \ - -DHAVE_FFI_CLOSURE_ALLOC \ - -DHAVE_FFI_PREP_CIF_VAR \ - -DHAVE_FFI_PREP_CLOSURE_LOC \ - -DMACOSX \ - -DUSING_APPLE_OS_LIBFFI \ - -DUSING_MALLOC_CLOSURE_DOT_C \ - -lffi - -_decimal _decimal/_decimal.c \ - _decimal/libmpdec/basearith.c \ - _decimal/libmpdec/constants.c \ - _decimal/libmpdec/context.c \ - _decimal/libmpdec/convolute.c \ - _decimal/libmpdec/crt.c \ - _decimal/libmpdec/difradix2.c \ - _decimal/libmpdec/fnt.c \ - _decimal/libmpdec/fourstep.c \ - _decimal/libmpdec/io.c \ - _decimal/libmpdec/mpalloc.c \ - _decimal/libmpdec/mpdecimal.c \ - _decimal/libmpdec/numbertheory.c \ - _decimal/libmpdec/sixstep.c \ - _decimal/libmpdec/transpose.c \ - -I$(srcdir)/Modules/_decimal/libmpdec \ - -DCONFIG_64 -DANSI -DHAVE_UINT128_T - -_posixshmem -I$(srcdir)/Modules/_multiprocessing _multiprocessing/posixshmem.c - -_scproxy _scproxy.c -framework SystemConfiguration -framework CoreFoundation - -_curses _cursesmodule.c -lcurses -ltermcap - -_curses_panel _curses_panel.c -lpanel -lncurses diff --git a/patch/Python/Setup.tvOS b/patch/Python/Setup.tvOS deleted file mode 100644 index b9c2a7a0..00000000 --- a/patch/Python/Setup.tvOS +++ /dev/null @@ -1,49 +0,0 @@ -##################################################################### -# tvOS: Platform specific configuration -##################################################################### - -*static* - -_ctypes _ctypes/_ctypes.c \ - _ctypes/callbacks.c \ - _ctypes/callproc.c \ - _ctypes/stgdict.c \ - _ctypes/cfield.c \ - _ctypes/malloc_closure.c \ - -I$(srcdir)/Modules/_ctypes/darwin \ - -I$(srcdir)/../Support/libFFI.xcframework/{{slice}}/Headers \ - -DPy_BUILD_CORE_MODULE \ - -DHAVE_FFI_CLOSURE_ALLOC \ - -DHAVE_FFI_PREP_CIF_VAR \ - -DHAVE_FFI_PREP_CLOSURE_LOC \ - -DUSING_MALLOC_CLOSURE_DOT_C \ - -L$(srcdir)/../Support/libFFI.xcframework/{{slice}} \ - -lFFI - -_decimal _decimal/_decimal.c \ - _decimal/libmpdec/basearith.c \ - _decimal/libmpdec/constants.c \ - _decimal/libmpdec/context.c \ - _decimal/libmpdec/convolute.c \ - _decimal/libmpdec/crt.c \ - _decimal/libmpdec/difradix2.c \ - _decimal/libmpdec/fnt.c \ - _decimal/libmpdec/fourstep.c \ - _decimal/libmpdec/io.c \ - _decimal/libmpdec/mpalloc.c \ - _decimal/libmpdec/mpdecimal.c \ - _decimal/libmpdec/numbertheory.c \ - _decimal/libmpdec/sixstep.c \ - _decimal/libmpdec/transpose.c \ - -I$(srcdir)/Modules/_decimal/libmpdec \ - -DCONFIG_64 -DANSI -DHAVE_UINT128_T - -##################################################################### -# DISABLED Modules that require additional frameworks -##################################################################### - -*disabled* - -_curses -_curses_panel -_posixshmem diff --git a/patch/Python/Setup.watchOS b/patch/Python/Setup.watchOS deleted file mode 100644 index 369dae09..00000000 --- a/patch/Python/Setup.watchOS +++ /dev/null @@ -1,31 +0,0 @@ -##################################################################### -# watchOS: Platform specific configuration -##################################################################### - -*static* - -_ctypes _ctypes/_ctypes.c \ - _ctypes/callbacks.c \ - _ctypes/callproc.c \ - _ctypes/stgdict.c \ - _ctypes/cfield.c \ - _ctypes/malloc_closure.c \ - -I$(srcdir)/Modules/_ctypes/darwin \ - -I$(srcdir)/../Support/libFFI.xcframework/{{slice}}/Headers \ - -DPy_BUILD_CORE_MODULE \ - -DHAVE_FFI_CLOSURE_ALLOC \ - -DHAVE_FFI_PREP_CIF_VAR \ - -DHAVE_FFI_PREP_CLOSURE_LOC \ - -DUSING_MALLOC_CLOSURE_DOT_C \ - -L$(srcdir)/../Support/libFFI.xcframework/{{slice}} \ - -lFFI - -##################################################################### -# DISABLED Modules that require additional frameworks -##################################################################### - -*disabled* - -_curses -_curses_panel -_posixshmem diff --git a/patch/Python/Setup.watchos.arm64_32 b/patch/Python/Setup.watchos.arm64_32 deleted file mode 100644 index a693c508..00000000 --- a/patch/Python/Setup.watchos.arm64_32 +++ /dev/null @@ -1,23 +0,0 @@ -##################################################################### -# watchOS ARM64_32: Target specific configuration -##################################################################### - -*static* - -_decimal _decimal/_decimal.c \ - _decimal/libmpdec/basearith.c \ - _decimal/libmpdec/constants.c \ - _decimal/libmpdec/context.c \ - _decimal/libmpdec/convolute.c \ - _decimal/libmpdec/crt.c \ - _decimal/libmpdec/difradix2.c \ - _decimal/libmpdec/fnt.c \ - _decimal/libmpdec/fourstep.c \ - _decimal/libmpdec/io.c \ - _decimal/libmpdec/mpalloc.c \ - _decimal/libmpdec/mpdecimal.c \ - _decimal/libmpdec/numbertheory.c \ - _decimal/libmpdec/sixstep.c \ - _decimal/libmpdec/transpose.c \ - -I$(srcdir)/Modules/_decimal/libmpdec \ - -DCONFIG_32 -DANSI diff --git a/patch/Python/Setup.watchsimulator.arm64 b/patch/Python/Setup.watchsimulator.arm64 deleted file mode 100644 index 2f55b527..00000000 --- a/patch/Python/Setup.watchsimulator.arm64 +++ /dev/null @@ -1,23 +0,0 @@ -##################################################################### -# watchOS Simulator ARM64: Target specific configuration -##################################################################### - -*static* - -_decimal _decimal/_decimal.c \ - _decimal/libmpdec/basearith.c \ - _decimal/libmpdec/constants.c \ - _decimal/libmpdec/context.c \ - _decimal/libmpdec/convolute.c \ - _decimal/libmpdec/crt.c \ - _decimal/libmpdec/difradix2.c \ - _decimal/libmpdec/fnt.c \ - _decimal/libmpdec/fourstep.c \ - _decimal/libmpdec/io.c \ - _decimal/libmpdec/mpalloc.c \ - _decimal/libmpdec/mpdecimal.c \ - _decimal/libmpdec/numbertheory.c \ - _decimal/libmpdec/sixstep.c \ - _decimal/libmpdec/transpose.c \ - -I$(srcdir)/Modules/_decimal/libmpdec \ - -DCONFIG_64 -DANSI -DHAVE_UINT128_T diff --git a/patch/Python/Setup.watchsimulator.x86_64 b/patch/Python/Setup.watchsimulator.x86_64 deleted file mode 100644 index f43c2000..00000000 --- a/patch/Python/Setup.watchsimulator.x86_64 +++ /dev/null @@ -1,23 +0,0 @@ -##################################################################### -# watchOS simulator x86_64: Target specific configuration -##################################################################### - -*static* - -_decimal _decimal/_decimal.c \ - _decimal/libmpdec/basearith.c \ - _decimal/libmpdec/constants.c \ - _decimal/libmpdec/context.c \ - _decimal/libmpdec/convolute.c \ - _decimal/libmpdec/crt.c \ - _decimal/libmpdec/difradix2.c \ - _decimal/libmpdec/fnt.c \ - _decimal/libmpdec/fourstep.c \ - _decimal/libmpdec/io.c \ - _decimal/libmpdec/mpalloc.c \ - _decimal/libmpdec/mpdecimal.c \ - _decimal/libmpdec/numbertheory.c \ - _decimal/libmpdec/sixstep.c \ - _decimal/libmpdec/transpose.c \ - -I$(srcdir)/Modules/_decimal/libmpdec \ - -DCONFIG_64 -DANSI -DHAVE_UINT128_T diff --git a/patch/Python/_sysconfigdata__ios_iphoneos.py b/patch/Python/_sysconfigdata__ios_iphoneos.py new file mode 100644 index 00000000..780bf883 --- /dev/null +++ b/patch/Python/_sysconfigdata__ios_iphoneos.py @@ -0,0 +1,2 @@ +# There's only one supported architecture for iOS hardware +from _sysconfigdata__ios_iphoneos_arm64 import * diff --git a/patch/Python/_sysconfigdata__ios_iphonesimulator.py b/patch/Python/_sysconfigdata__ios_iphonesimulator.py new file mode 100644 index 00000000..1bede110 --- /dev/null +++ b/patch/Python/_sysconfigdata__ios_iphonesimulator.py @@ -0,0 +1,11 @@ +import os + + +# os.uname().machine is the host CPU architecture on the simulator +arch = os.uname().machine +if arch == 'x86_64': + from _sysconfigdata__ios_iphonesimulator_x86_64 import * +elif arch == 'arm64': + from _sysconfigdata__ios_iphonesimulator_arm64 import * +else: + raise RuntimeError("Unknown iOS simulator architecture.") diff --git a/patch/Python/_sysconfigdata__tvos_appletvos.py b/patch/Python/_sysconfigdata__tvos_appletvos.py new file mode 100644 index 00000000..eb7ac9cc --- /dev/null +++ b/patch/Python/_sysconfigdata__tvos_appletvos.py @@ -0,0 +1,2 @@ +# There's only one supported architecture for tvOS hardware +from _sysconfigdata__tvos_appletvos_arm64 import * diff --git a/patch/Python/_sysconfigdata__tvos_appletvsimulator.py b/patch/Python/_sysconfigdata__tvos_appletvsimulator.py new file mode 100644 index 00000000..29f8a67b --- /dev/null +++ b/patch/Python/_sysconfigdata__tvos_appletvsimulator.py @@ -0,0 +1,11 @@ +import os + + +# os.uname().machine is the host CPU architecture on the simulator +arch = os.uname().machine +if arch == 'x86_64': + from _sysconfigdata__tvos_appletvsimulator_x86_64 import * +elif arch == 'arm64': + from _sysconfigdata__tvos_appletvsimulator_arm64 import * +else: + raise RuntimeError("Unknown tvOS simulator architecture.") diff --git a/patch/Python/_sysconfigdata__watchos_watchos.py b/patch/Python/_sysconfigdata__watchos_watchos.py new file mode 100644 index 00000000..c1872dfc --- /dev/null +++ b/patch/Python/_sysconfigdata__watchos_watchos.py @@ -0,0 +1,2 @@ +# There's only one supported architecture for watchOS hardware +from _sysconfigdata__watchos_watchos_arm64_32 import * diff --git a/patch/Python/_sysconfigdata__watchos_watchsimulator.py b/patch/Python/_sysconfigdata__watchos_watchsimulator.py new file mode 100644 index 00000000..c34bd97b --- /dev/null +++ b/patch/Python/_sysconfigdata__watchos_watchsimulator.py @@ -0,0 +1,11 @@ +import os + + +# os.uname().machine is the host CPU architecture on the simulator +arch = os.uname().machine +if arch == 'x86_64': + from _sysconfigdata__watchos_watchsimulator_x86_64 import * +elif arch == 'arm64': + from _sysconfigdata__watchos_watchsimulator_arm64 import * +else: + raise RuntimeError("Unknown watchOS simulator architecture.") diff --git a/patch/Python/pyconfig-watchOS.h b/patch/Python/pyconfig-watchOS.h index 6801a6a9..ae4563f1 100644 --- a/patch/Python/pyconfig-watchOS.h +++ b/patch/Python/pyconfig-watchOS.h @@ -3,7 +3,11 @@ #endif #ifdef __arm64__ +# ifdef __LP64__ #include "pyconfig-arm64.h" +# else +#include "pyconfig-arm64_32.h" +# endif #endif #ifdef __x86_64__ diff --git a/patch/Python/release.common.exclude b/patch/Python/release.common.exclude index a4ac3703..8f11eac5 100644 --- a/patch/Python/release.common.exclude +++ b/patch/Python/release.common.exclude @@ -1,40 +1,30 @@ # 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 binaries; not needed for embedded builds -Python/Resources/bin -# Remove includes; use the version packaged in Headers -Python/Resources/include -# Remove the Resources version of libpython; -# we use the version packaged at the root level -Python/Resources/lib/libpython3.*.a -# Remove lib/pkgconfig files. These are used for compiling C extension modules. -Python/Resources/lib/pkgconfig # Remove standard library test suites. -Python/Resources/lib/python*/ctypes/test -Python/Resources/lib/python*/distutils/tests -Python/Resources/lib/python*/lib2to3/tests -Python/Resources/lib/python*/sqlite3/test -Python/Resources/lib/python*/test -# Remove compiled test and example modules. -Python/Resources/lib/python*/lib-dynload/*.so +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/Resources/lib/python*/config-* +python-stdlib/config-* # Remove ensurepip. If user code needs pip, it can add it to -Python/Resources/lib/python*/ensurepip +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/Resources/lib/python*/idlelib -Python/Resources/lib/python*/tkinter -Python/Resources/lib/python*/turtle.py -Python/Resources/lib/python*/turtledemo -Python/Resources/lib/python*/lib-dynload/_tkinter*.so +python-stdlib/tkinter +python-stdlib/turtle.py +python-stdlib/turtledemo +# Remove the testing binary modules +python-stdlib/lib-dynload/_test*.so +python-stdlib/lib-dynload/_xx*.so +python-stdlib/lib-dynload/xx*.so # Remove site-packages directory. The template unpacks user code and # dependencies to a different path. -Python/Resources/lib/python*/site-packages -# Remove share/ directory, which contains user documentation (man pages). -Python/Resources/share +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. -Python/Resources/*/*.pyc \ No newline at end of file +*/__pycache__ \ No newline at end of file diff --git a/patch/Python/release.iOS.exclude b/patch/Python/release.iOS.exclude index 59de6bf2..471b1907 100644 --- a/patch/Python/release.iOS.exclude +++ b/patch/Python/release.iOS.exclude @@ -3,4 +3,4 @@ # It is used by `tar -X` during the Makefile build. # # Remove command-line curses toolkit. -Python/Resources/lib/python*/curses +python-stdlib/curses diff --git a/patch/Python/sitecustomize.py b/patch/Python/sitecustomize.py new file mode 100644 index 00000000..d7d86e36 --- /dev/null +++ b/patch/Python/sitecustomize.py @@ -0,0 +1,99 @@ +# A site customization that can be used to trick pip into installing +# packages cross-platform. If the folder containing this file is on +# your PYTHONPATH when you invoke pip, pip will behave as if it were +# running on {{os}}. +import distutils.ccompiler +import distutils.unixccompiler +import os +import platform +import sys +import sysconfig +import types + +# Make platform.system() return "{{os}}" +def custom_system(): + return "{{os}}" + +platform.system = custom_system + +# Make sysconfig.get_platform() return "{{tag}}" +def custom_get_platform(): + return "{{tag}}" + +sysconfig.get_platform = custom_get_platform + +# Make distutils raise errors if you try to use it to build modules. +DISABLED_COMPILER_ERROR = "Cannot compile native modules" + +distutils.ccompiler.get_default_compiler = lambda *args, **kwargs: "disabled" +distutils.ccompiler.compiler_class["disabled"] = ( + "disabledcompiler", + "DisabledCompiler", + "Compiler disabled ({})".format(DISABLED_COMPILER_ERROR), +) + + +def disabled_compiler(prefix): + # No need to give any more advice here: that will come from the higher-level code in pip. + from distutils.errors import DistutilsPlatformError + + raise DistutilsPlatformError("{}: {}".format(prefix, DISABLED_COMPILER_ERROR)) + + +class DisabledCompiler(distutils.ccompiler.CCompiler): + compiler_type = "disabled" + + def preprocess(*args, **kwargs): + disabled_compiler("CCompiler.preprocess") + + def compile(*args, **kwargs): + disabled_compiler("CCompiler.compile") + + def create_static_lib(*args, **kwargs): + disabled_compiler("CCompiler.create_static_lib") + + def link(*args, **kwargs): + disabled_compiler("CCompiler.link") + + +# To maximize the chance of the build getting as far as actually calling compile(), make +# sure the class has all of the expected attributes. +for name in [ + "src_extensions", + "obj_extension", + "static_lib_extension", + "shared_lib_extension", + "static_lib_format", + "shared_lib_format", + "exe_extension", +]: + setattr( + DisabledCompiler, name, getattr(distutils.unixccompiler.UnixCCompiler, name) + ) + +DisabledCompiler.executables = { + name: [DISABLED_COMPILER_ERROR.replace(" ", "_")] + for name in distutils.unixccompiler.UnixCCompiler.executables +} + +disabled_mod = types.ModuleType("distutils.disabledcompiler") +disabled_mod.DisabledCompiler = DisabledCompiler +sys.modules["distutils.disabledcompiler"] = disabled_mod + + +# Try to disable native builds for packages which don't use the distutils native build +# system at all (e.g. uwsgi), or only use it to wrap an external build script (e.g. pynacl). +for tool in ["ar", "as", "cc", "cxx", "ld"]: + os.environ[tool.upper()] = DISABLED_COMPILER_ERROR.replace(" ", "_") + + +# Call the next sitecustomize script if there is one +# (https://nedbatchelder.com/blog/201001/running_code_at_python_startup.html). +del sys.modules["sitecustomize"] +this_dir = os.path.dirname(__file__) +path_index = sys.path.index(this_dir) +del sys.path[path_index] +try: + import sitecustomize # noqa: F401 +finally: + sys.path.insert(path_index, this_dir) diff --git a/patch/Python/test.exclude b/patch/Python/test.exclude index 664b3273..add994a7 100644 --- a/patch/Python/test.exclude +++ b/patch/Python/test.exclude @@ -2,25 +2,6 @@ # we exclude from the embedded device Python-Apple-support test tarballs. # It is used by `tar -X` during the Makefile build. # -# Remove binaries -Python/Resources/bin -# Remove include/ directory, only useful for compiling C extension modules. -Python/Resources/include -# Remove the Resources version of libpython; -# we use the version packaged at the root level -Python/Resources/lib/libpython3.*.a -# Remove lib/pkgconfig files. These are used for compiling C extension modules. -Python/Resources/lib/pkgconfig -# Remove compiled test and example modules. -Python/Resources/lib/python*/lib-dynload/_test*.so -Python/Resources/lib/python*/lib-dynload/_ctypes_test*.so -Python/Resources/lib/python*/lib-dynload/xxlimited*.so -Python/Resources/lib/python*/lib-dynload/_xxtestfuzz.so -# Remove site-packages directory. The template unpacks user code and -# dependencies to a different path. -Python/Resources/lib/python*/site-packages -# Remove share/ directory, which contains user documentation (man pages). -Python/Resources/share # Remove pyc files. These take up space, but since most stdlib modules are # never imported by user code, they mostly have no value. -Python/Resources/*/*.pyc \ No newline at end of file +*/__pycache__ \ No newline at end of file diff --git a/patch/libffi.patch b/patch/libffi-3.4.2.patch similarity index 100% rename from patch/libffi.patch rename to patch/libffi-3.4.2.patch diff --git a/patch/xz-5.2.6.patch b/patch/xz-5.2.6.patch new file mode 100644 index 00000000..6876e0d5 --- /dev/null +++ b/patch/xz-5.2.6.patch @@ -0,0 +1,35 @@ +diff -ru xz-5.2.6-orig/build-aux/config.sub xz-5.2.6/build-aux/config.sub +--- xz-5.2.6-orig/build-aux/config.sub 2022-08-12 18:56:06.000000000 +0800 ++++ xz-5.2.6/build-aux/config.sub 2022-09-01 14:36:08.000000000 +0800 +@@ -1121,10 +1121,9 @@ + xscale-* | xscalee[bl]-*) + cpu=`echo "$cpu" | sed 's/^xscale/arm/'` + ;; +- arm64-*) ++ arm64-* | arm64_32-*) + cpu=aarch64 + ;; +- + # Recognize the canonical CPU Types that limit and/or modify the + # company names they are paired with. + cr16-*) +@@ -1723,7 +1722,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 +1785,8 @@ + ;; + *-eabi* | *-gnueabi*) + ;; ++ ios*-simulator | tvos*-simulator | watchos*-simulator) ++ ;; + -*) + # Blank kernel with real OS is always fine. + ;; +Only in xz-5.2.6/build-aux: config.sub.orig +Only in xz-5.2.6/build-aux: config.sub.rej diff --git a/tests/testbed/README.rst b/tests/testbed/README.rst deleted file mode 100644 index 077b3dc6..00000000 --- a/tests/testbed/README.rst +++ /dev/null @@ -1,13 +0,0 @@ -Python Apple Support Testbed -============================ - -This is a testbed application that can be used to do basic verification checks -of the Python Apple Support builds. - -The app can be deployed with Briefcase. When executed, (using `briefcase run -macOS Xcode` or `briefcase run iOS`) the app will generate output on the console -log that is similar to a unit test suite. If it returns 0 test failures, you can -have some confidence that the support build is functioning as expected. - -The default configuration assumes that you have already run `make` in the root -directory of this repository. diff --git a/tests/testbed/pyproject.toml b/tests/testbed/pyproject.toml deleted file mode 100644 index 636810a8..00000000 --- a/tests/testbed/pyproject.toml +++ /dev/null @@ -1,40 +0,0 @@ -[tool.briefcase] -project_name = "Testbed" -bundle = "org.beeware" -version = "0.0.1" -url = "https://beeware.org" -license = "BSD license" -author = 'Russell Keith-Magee' -author_email = "russell@beeware.org" - -[tool.briefcase.app.testbed] -formal_name = "Testbed" -description = "A testbed for the Apple Support packages." -icon = "src/testbed/resources/testbed" -sources = ['src/testbed'] -requires = [ -] - -[tool.briefcase.app.testbed.macOS] -requires = [ - "rubicon-objc", - "std-nslog", -] -support_package = "../../dist/Python-3.9-macOS-support.custom.tar.gz" - -[tool.briefcase.app.testbed.linux] -supported = false - -[tool.briefcase.app.testbed.windows] -supported = false - -# Mobile deployments -[tool.briefcase.app.testbed.iOS] -requires = [ - "rubicon-objc", - "std-nslog", -] -support_package = "../../dist/Python-3.9-iOS-support.custom.tar.gz" - -[tool.briefcase.app.testbed.android] -supported = false diff --git a/tests/testbed/src/testbed/__init__.py b/tests/testbed/src/testbed/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/testbed/src/testbed/__main__.py b/tests/testbed/src/testbed/__main__.py deleted file mode 100644 index 00c3da21..00000000 --- a/tests/testbed/src/testbed/__main__.py +++ /dev/null @@ -1,4 +0,0 @@ -from testbed.app import main - -if __name__ == "__main__": - main() diff --git a/tests/testbed/src/testbed/app.py b/tests/testbed/src/testbed/app.py deleted file mode 100644 index 0f641091..00000000 --- a/tests/testbed/src/testbed/app.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -A testbed for the Apple Support packages. -""" -import importlib -import platform -import sys -import traceback - -from . import common - - -def discover_tests(module): - "Discover all the test methods in the given module" - return [ - (getattr(module, "__name__").split(".")[-1], getattr(module, name)) - for name in dir(module) - if name.startswith("test_") - ] - - -def main(): - # This should start and launch your app! - print("=" * 80) - print(f"Python {platform.python_version()} Apple Support verification suite") - print(f"Running on {platform.platform()}") - print("=" * 80) - # Discover the common test suite - suite = discover_tests(common) - - # Discover the platform-specific tests - try: - module = importlib.import_module(f".{sys.platform}", "testbed") - suite.extend(discover_tests(module)) - except ModuleNotFoundError: - print(f"No platform-specific tests for {sys.platform}") - - # Run the suite - failures = 0 - tests = 0 - for sys_platform, test in suite: - try: - tests += 1 - # If the test has a docstring, use that text; - # otherwise, use the test name - if test.__doc__: - print(f"{sys_platform}: {test.__doc__}", end="...") - else: - print(f"{sys_platform}: {test.__name__}", end="...") - test() - print(" ok") - except Exception: - failures += 1 - print(" FAILED!") - print("-" * 80) - traceback.print_exc() - print("-" * 80) - - print("=" * 80) - print(f"Tests complete; {tests} tests, {failures} failures.") - sys.exit(failures) diff --git a/tests/testbed/src/testbed/common.py b/tests/testbed/src/testbed/common.py deleted file mode 100644 index 339f59ad..00000000 --- a/tests/testbed/src/testbed/common.py +++ /dev/null @@ -1,339 +0,0 @@ -########################################################################### -# Common tests -########################################################################### -import importlib -import os - -from .utils import assert_ - - -def test_bootstrap_modules(): - "All the bootstrap modules are importable" - missing = [] - - # The list of bootstrap modules that don't have explicit tests. - for module in [ - '_abc', - '_codecs', - '_collections', - '_functools', - '_io', - '_locale', - '_operator', - '_signal', - '_sre', - '_stat', - '_symtable', - '_thread', - '_tracemalloc', - '_weakref', - 'atexit', - 'errno', - 'faulthandler', - 'itertools', - 'posix', - 'pwd', - 'time', - ]: - try: - importlib.import_module(module) - except ModuleNotFoundError: - missing.append(module) - - assert_(len(missing) == 0, msg=f"Missing bootstrap modules: {', '.join(str(m) for m in missing)}") - - -def test_stdlib_modules(): - "All the stdlib modules exist" - missing = [] - for module in [ - "_asyncio", - "_bisect", - "_codecs_cn", - "_codecs_hk", - "_codecs_iso2022", - "_codecs_jp", - "_codecs_kr", - "_codecs_tw", - "_contextvars", - "_csv", - "_datetime", - "_heapq", - "_json", - "_lsprof", - "_multibytecodec", - "_multiprocessing", - "_opcode", - "_pickle", - "_posixsubprocess", - "_queue", - "_random", - "_socket", - "_statistics", - "_struct", - "_uuid", - "array", - "binascii", - "cmath", - "fcntl", - "grp", - "math", - "mmap", - "resource", - "select", - "syslog", - "termios", - "unicodedata", - "zlib", - # Scheduled for deprecation - "_crypt", - "audioop", - ]: - try: - importlib.import_module(module) - except ModuleNotFoundError: - missing.append(module) - - assert_(len(missing) == 0, msg=f"Missing stdlib modules: {', '.join(str(m) for m in missing)}") - - -def test_bzip2(): - "BZip2 compression with the bz2 module works" - import bz2 - - data = bz2.compress(b"Hello world") - assert_( - data == b"BZh91AY&SY\x059\x88u\x00\x00\x00\x95\x80@\x00\x00@\x06\x04" - b'\x90\x80 \x00"\x06\x9bHC\x02\x1a|\n\xa1<]\xc9\x14\xe1B@\x14\xe6!\xd4' - ) - - -def test_ctypes(): - "The FFI module has been compiled, and ctypes works on ObjC objects" - from rubicon.objc import ObjCClass - - NSURL = ObjCClass("NSURL") - - base = NSURL.URLWithString("https://beeware.org/") - full = NSURL.URLWithString("contributing", relativeToURL=base) - absolute = full.absoluteURL - assert_(absolute.description == "https://beeware.org/contributing") - -def test_dbm(): - "The DBM module is accessible" - import dbm - - cache_name = f'{os.path.dirname(__file__)}/dbm' - try: - with dbm.open(cache_name, 'c') as db: - db['hello'] = 'world' - - assert_(db['hello'] == b'world') - finally: - os.remove(f'{cache_name}.db') - - -def test_dbm_dumb(): - "The dumb DBM module has been compiled and works" - from dbm import dumb as ddbm - - cache_name = f'{os.path.dirname(__file__)}/ddbm' - try: - with ddbm.open(cache_name, 'c') as db: - db['hello'] = 'world' - - assert_(db['hello'] == b'world') - finally: - os.remove(f'{cache_name}.bak') - os.remove(f'{cache_name}.dat') - os.remove(f'{cache_name}.dir') - - -def test_dbm_ndbm(): - "The ndbm DBM module has been compiled and works" - from dbm import ndbm - - cache_name = f'{os.path.dirname(__file__)}/ndbm' - try: - with ndbm.open(cache_name, 'c') as db: - db['hello'] = 'world' - - assert_(db['hello'] == b'world') - finally: - os.remove(f'{cache_name}.db') - - -def test_decimal(): - "The decimal module works" - from decimal import Decimal, getcontext - - getcontext().prec = 28 - assert str(Decimal(1) / Decimal(7)) == "0.1428571428571428571428571429" - - -def test_hashlib(): - "Hashlib can compute hashes" - import hashlib - - algorithms = { - "md5": "3e25960a79dbc69b674cd4ec67a72c62", - "sha1": "7b502c3a1f48c8609ae212cdfb639dee39673f5e", - "sha224": "ac230f15fcae7f77d8f76e99adf45864a1c6f800655da78dea956112", - "sha256": ("64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c"), - "sha384": ( - "9203b0c4439fd1e6ae5878866337b7c532acd6d9260150c80318e8ab8c27ce33" - "0189f8df94fb890df1d298ff360627e1" - ), - "sha512": ( - "b7f783baed8297f0db917462184ff4f08e69c2d5e5f79a942600f9725f58ce1f" - "29c18139bf80b06c0fff2bdd34738452ecf40c488c22a7e3d80cdf6f9c1c0d47" - ), - "blake2b": ( - "6ff843ba685842aa82031d3f53c48b66326df7639a63d128974c5c14f31a0f33" - "343a8c65551134ed1ae0f2b0dd2bb495dc81039e3eeb0aa1bb0388bbeac29183" - ), - "blake2s": "619a15b0f4dd21ef4bd626a9146af64561caf1325b21bccf755e4d7fbc31a65f", - "sha3_224": "3b8570ec1335c461747d016460ff91cb41fad08051911c50dd8e1995", - "sha3_256": ( - "369183d3786773cef4e56c7b849e7ef5f742867510b676d6b38f8e38a222d8a2" - ), - "sha3_384": ( - "ff3917192427ea1aa7f3ad47ac10152d179af30126c52835ee8dc7e6ea12aed9" - "1ad91b316e15c3b250469ef17a03e529" - ), - "sha3_512": ( - "e2e1c9e522efb2495a178434c8bb8f11000ca23f1fd679058b7d7e141f0cf343" - "3f94fc427ec0b9bebb12f327a3240021053db6091196576d5e6d9bd8fac71c0c" - ), - "shake_128": ( - 40, - "c1301df86b1dc67ce3b5a067dc9b47affca8caa08f41d1efa614cea56f526897" - "d61ded8ab01421f1", - ), - "shake_256": ( - 40, - "20740b4c7a7997765e9cc254b44a1589e60849be0fe70b68a6fb732415edaa13" - "3bb6eb7825ffa531", - ), - } - for algorithm, details in algorithms.items(): - try: - length, expected = details - digest_args = {"length": length} - except ValueError: - expected = details - digest_args = {} - msg = getattr(hashlib, algorithm)() - msg.update(b"Hello world") - assert_( - msg.hexdigest(**digest_args) == expected, - msg=f"{algorithm} digest was {msg.hexdigest(**digest_args)}", - ) - - -def test_sqlite3(): - "The sqlite3 module works" - import sqlite3 - - conn = sqlite3.connect(":memory:") - try: - cursor = conn.cursor() - - cursor.execute( - "CREATE TABLE stonks (date text, symbol text, qty real, price real)" - ) - cursor.execute("INSERT INTO stonks VALUES ('2022-05-04', 'JEDI', 10, 2.50)") - cursor.execute("INSERT INTO stonks VALUES ('2022-05-04', 'SITH', 2, 6.66)") - conn.commit() - - assert_( - list(cursor.execute("SELECT * FROM stonks ORDER BY symbol DESC")) - == [("2022-05-04", "SITH", 2.0, 6.66), ("2022-05-04", "JEDI", 10.0, 2.5)] - ) - finally: - conn.close() - - -def test_ssl(): - "The SSL modules has been compiled" - import ssl - - # Result doesn't really matter; we just need to be able to invoke - # a method whose implementation is in the C module - ssl.get_default_verify_paths() - - -def test_tempfile(): - "A tempfile can be written" - import tempfile - - msg = b"I've watched C-beams glitter in the dark near the Tannhauser Gate." - with tempfile.TemporaryFile() as f: - # Write content to the temp file - f.write(msg) - - # Reset the file pointer to 0 and read back the content - f.seek(0) - assert_(f.read() == msg) - - -XML_DOCUMENT = """ - - - iOS - phone - - - macOS - laptop - - -""" - - -def test_xml_elementtree(): - "The elementtree XML parser works" - import xml.etree.ElementTree as ET - - root = ET.fromstring(XML_DOCUMENT) - assert_( - [(child.tag, child.attrib["name"]) for child in root] - == [("device", "iPhone"), ("device", "macBook")] - ) - - -def test_xml_expat(): - "The expat XML parser works" - from xml.parsers.expat import ParserCreate - - starts = [] - - def start_element(name, attrs): - starts.append(name) - - parser = ParserCreate() - parser.StartElementHandler = start_element - parser.Parse(XML_DOCUMENT) - - assert_(starts == ["data", "device", "os", "type", "device", "os", "type"]) - - -def test_xz(): - "XZ compression with the lzma module works" - import lzma - - data = lzma.compress(b"Hello world") - assert_( - data == b"\xfd7zXZ\x00\x00\x04\xe6\xd6\xb4F\x02\x00!\x01\x16\x00\x00\x00t/" - b"\xe5\xa3\x01\x00\nHello world\x00\x00\xbfVw\xd4\xb9\xf2\xa5\xf4\x00" - b"\x01#\x0b\xc2\x1b\xfd\t\x1f\xb6\xf3}\x01\x00\x00\x00\x00\x04YZ" - ) - - -def test_zoneinfo(): - "Zoneinfo database is available" - from zoneinfo import ZoneInfo - from datetime import datetime - - dt = datetime(2022, 5, 4, 13, 40, 42, tzinfo=ZoneInfo("Australia/Perth")) - assert_(str(dt) == "2022-05-04 13:40:42+08:00") diff --git a/tests/testbed/src/testbed/darwin.py b/tests/testbed/src/testbed/darwin.py deleted file mode 100644 index a557e65e..00000000 --- a/tests/testbed/src/testbed/darwin.py +++ /dev/null @@ -1,68 +0,0 @@ -########################################################################### -# macOS specific tests -########################################################################### -import importlib - -from .utils import assert_ - - -def test_scproxy(): - "The _scproxy module has been compiled" - import _scproxy - - _scproxy._get_proxy_settings() - - -def test_curses(): - "The curses module has been compiled" - import curses - - try: - curses.can_change_color() - except curses.error: - # We can't invoke curses methods without raising a curses error; - # but if we get the error, the module works. - pass - - -def test_posix_shmem(): - "POSIX shared memory works" - from multiprocessing import shared_memory - - # FIXME: For now, we can't actually test multiprocessing - # because it involves invoking a subprocess, and the macOS app - # shim doesn't support process duplication. The import is - # enough to test that the _posixshmem C module exists. - # try: - # obj = shared_memory.ShareableList( - # ["howdy", b"HoWdY", -273.154, 100, None, True, 42] - # ) - # - # assert obj[3] == 100 - # finally: - # obj.shm.close() - # obj.shm.unlink() - # del obj - - -def test_posix_subprocess(): - "Subprocesses can be invoked" - import subprocess - - result = subprocess.run(["uname", "-s"], capture_output=True) - assert_(result.stdout == b"Darwin\n") - - -def test_stdlib_modules(): - "All the macOS-specific stdlib modules exist" - missing = [] - for module in [ - "_posixshmem", - "_scproxy", - ]: - try: - importlib.import_module(module) - except ModuleNotFoundError: - missing.append(module) - - assert_(len(missing) == 0, msg=f"Missing stdlib modules: {', '.join(str(m) for m in missing)}") diff --git a/tests/testbed/src/testbed/ios.py b/tests/testbed/src/testbed/ios.py deleted file mode 100644 index f6bfa515..00000000 --- a/tests/testbed/src/testbed/ios.py +++ /dev/null @@ -1,21 +0,0 @@ -from rubicon.objc import ObjCClass - -from .utils import assert_ - - -UIResponder = ObjCClass('UIResponder') - -# iOS apps need an AppDelegate or they crash -class PythonAppDelegate(UIResponder): - pass - - -def test_subprocess(): - "Subprocesses should raise exceptions" - import subprocess - - try: - subprocess.call(['uname', '-a']) - raise AssertionError('Subprocesses should not be possible') - except RuntimeError as e: - assert_(str(e) == "Subprocesses are not supported on ios") \ No newline at end of file diff --git a/tests/testbed/src/testbed/resources/__init__.py b/tests/testbed/src/testbed/resources/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/testbed/src/testbed/resources/testbed-1024.png b/tests/testbed/src/testbed/resources/testbed-1024.png deleted file mode 100644 index 3672c84b..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-1024.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-120.png b/tests/testbed/src/testbed/resources/testbed-120.png deleted file mode 100644 index 39233f2d..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-120.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-128.png b/tests/testbed/src/testbed/resources/testbed-128.png deleted file mode 100644 index b8d131fc..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-128.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-152.png b/tests/testbed/src/testbed/resources/testbed-152.png deleted file mode 100644 index 205e8193..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-152.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-16.png b/tests/testbed/src/testbed/resources/testbed-16.png deleted file mode 100644 index ac5d46f9..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-16.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-167.png b/tests/testbed/src/testbed/resources/testbed-167.png deleted file mode 100644 index bf1f9ac4..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-167.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-180.png b/tests/testbed/src/testbed/resources/testbed-180.png deleted file mode 100644 index 2be0bb8a..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-180.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-20.png b/tests/testbed/src/testbed/resources/testbed-20.png deleted file mode 100644 index 80c1614c..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-20.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-256.png b/tests/testbed/src/testbed/resources/testbed-256.png deleted file mode 100644 index c2c8c72b..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-256.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-29.png b/tests/testbed/src/testbed/resources/testbed-29.png deleted file mode 100644 index 016229c3..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-29.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-32.png b/tests/testbed/src/testbed/resources/testbed-32.png deleted file mode 100644 index 0e43db82..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-32.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-40.png b/tests/testbed/src/testbed/resources/testbed-40.png deleted file mode 100644 index a8ea704e..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-40.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-512.png b/tests/testbed/src/testbed/resources/testbed-512.png deleted file mode 100644 index 7b15c675..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-512.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-58.png b/tests/testbed/src/testbed/resources/testbed-58.png deleted file mode 100644 index 0ecb9f1c..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-58.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-60.png b/tests/testbed/src/testbed/resources/testbed-60.png deleted file mode 100644 index 47c1b6ea..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-60.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-64.png b/tests/testbed/src/testbed/resources/testbed-64.png deleted file mode 100644 index a3cd3614..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-64.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-76.png b/tests/testbed/src/testbed/resources/testbed-76.png deleted file mode 100644 index 70aca2ec..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-76.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-80.png b/tests/testbed/src/testbed/resources/testbed-80.png deleted file mode 100644 index b0a3f1a9..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-80.png and /dev/null differ diff --git a/tests/testbed/src/testbed/resources/testbed-87.png b/tests/testbed/src/testbed/resources/testbed-87.png deleted file mode 100644 index cfe22b2d..00000000 Binary files a/tests/testbed/src/testbed/resources/testbed-87.png and /dev/null differ diff --git a/tests/testbed/src/testbed/utils.py b/tests/testbed/src/testbed/utils.py deleted file mode 100644 index 7777c707..00000000 --- a/tests/testbed/src/testbed/utils.py +++ /dev/null @@ -1,8 +0,0 @@ -########################################################################### -# Testing utilities -########################################################################### - - -def assert_(condition, msg=None): - if not condition: - raise AssertionError(msg if msg else "Test assertion failed")