diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..c35bb42d
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,9 @@
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ # Check for updates on the first Sunday of every month, 8PM UTC
+ interval: "cron"
+ cronjob: "0 20 * * sun#1"
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
new file mode 100644
index 00000000..34b7ed74
--- /dev/null
+++ b/.github/workflows/ci.yaml
@@ -0,0 +1,313 @@
+name: CI
+on:
+ pull_request:
+ workflow_call:
+ inputs:
+ build-number:
+ description: "The build number to add to the built package"
+ default: "custom"
+ type: "string"
+ outputs:
+ PYTHON_VER:
+ description: "The Python major.minor version."
+ value: ${{ jobs.config.outputs.PYTHON_VER }}
+ PYTHON_VERSION:
+ description: "The full Python version."
+ value: ${{ jobs.config.outputs.PYTHON_VERSION }}
+ BZIP2_VERSION:
+ description: "The BZip2 version used for the build."
+ value: ${{ jobs.config.outputs.BZIP2_VERSION }}
+ LIBFFI_VERSION:
+ description: "The libFFI version used for the build."
+ value: ${{ jobs.config.outputs.LIBFFI_VERSION }}
+ MPDECIMAL_VERSION:
+ description: "The mpdecimal version used for the build."
+ value: ${{ jobs.config.outputs.MPDECIMAL_VERSION }}
+ OPENSSL_VERSION:
+ description: "The OpenSSL version used for the build."
+ value: ${{ jobs.config.outputs.OPENSSL_VERSION }}
+ XZ_VERSION:
+ description: "The XZ version used for the build."
+ value: ${{ jobs.config.outputs.XZ_VERSION }}
+ ZSTD_VERSION:
+ description: "The Zstandard version used for the build."
+ value: ${{ jobs.config.outputs.ZSTD_VERSION }}
+
+env:
+ FORCE_COLOR: "1"
+
+defaults:
+ run:
+ shell: bash
+
+# Cancel active CI runs for a PR before starting another run
+concurrency:
+ group: ${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ config:
+ runs-on: macOS-latest
+ outputs:
+ PYTHON_VER: ${{ steps.extract.outputs.PYTHON_VER }}
+ PYTHON_VERSION: ${{ steps.extract.outputs.PYTHON_VERSION }}
+ BUILD_NUMBER: ${{ steps.extract.outputs.BUILD_NUMBER }}
+ BZIP2_VERSION: ${{ steps.extract.outputs.BZIP2_VERSION }}
+ LIBFFI_VERSION: ${{ steps.extract.outputs.LIBFFI_VERSION }}
+ MPDECIMAL_VERSION: ${{ steps.extract.outputs.MPDECIMAL_VERSION }}
+ OPENSSL_VERSION: ${{ steps.extract.outputs.OPENSSL_VERSION }}
+ XZ_VERSION: ${{ steps.extract.outputs.XZ_VERSION }}
+ ZSTD_VERSION: ${{ steps.extract.outputs.ZSTD_VERSION }}
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Extract config variables
+ id: extract
+ run: |
+ PYTHON_VER=$(make config | grep "PYTHON_VER=" | cut -d "=" -f 2)
+ PYTHON_VERSION=$(make config | grep "PYTHON_VERSION=" | cut -d "=" -f 2)
+ BZIP2_VERSION=$(make config | grep "BZIP2_VERSION=" | cut -d "=" -f 2)
+ LIBFFI_VERSION=$(make config | grep "LIBFFI_VERSION=" | cut -d "=" -f 2)
+ MPDECIMAL_VERSION=$(make config | grep "MPDECIMAL_VERSION=" | cut -d "=" -f 2)
+ OPENSSL_VERSION=$(make config | grep "OPENSSL_VERSION=" | cut -d "=" -f 2)
+ XZ_VERSION=$(make config | grep "XZ_VERSION=" | cut -d "=" -f 2)
+ ZSTD_VERSION=$(make config | grep "ZSTD_VERSION=" | cut -d "=" -f 2)
+ if [ -z "${{ inputs.build-number }}" ]; then
+ BUILD_NUMBER=custom
+ else
+ BUILD_NUMBER=${{ inputs.build-number }}
+ fi
+
+ echo "PYTHON_VER=${PYTHON_VER}" | tee -a ${GITHUB_OUTPUT}
+ echo "PYTHON_VERSION=${PYTHON_VERSION}" | tee -a ${GITHUB_OUTPUT}
+ echo "BUILD_NUMBER=${BUILD_NUMBER}" | tee -a ${GITHUB_OUTPUT}
+ echo "BZIP2_VERSION=${BZIP2_VERSION}" | tee -a ${GITHUB_OUTPUT}
+ echo "LIBFFI_VERSION=${LIBFFI_VERSION}" | tee -a ${GITHUB_OUTPUT}
+ echo "MPDECIMAL_VERSION=${MPDECIMAL_VERSION}" | tee -a ${GITHUB_OUTPUT}
+ echo "OPENSSL_VERSION=${OPENSSL_VERSION}" | tee -a ${GITHUB_OUTPUT}
+ echo "XZ_VERSION=${XZ_VERSION}" | tee -a ${GITHUB_OUTPUT}
+ echo "ZSTD_VERSION=${ZSTD_VERSION}" | tee -a ${GITHUB_OUTPUT}
+
+ build:
+ runs-on: macOS-15
+ needs: [ config ]
+ strategy:
+ fail-fast: false
+ matrix:
+ platform: ['macOS', 'iOS', 'tvOS', 'watchOS', 'visionOS']
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Set up Xcode
+ # GitHub recommends explicitly selecting the desired Xcode version:
+ # https://github.com/actions/runner-images/issues/12541#issuecomment-3083850140
+ # This became a necessity as a result of
+ # https://github.com/actions/runner-images/issues/12541 and
+ # https://github.com/actions/runner-images/issues/12751.
+ run: |
+ sudo xcode-select --switch /Applications/Xcode_16.4.app
+
+ - name: Set up Python
+ uses: actions/setup-python@v6.2.0
+ with:
+ # Appending -dev ensures that we can always build the dev release.
+ # It's a no-op for versions that have been published.
+ python-version: ${{ needs.config.outputs.PYTHON_VER }}-dev
+ # Ensure that we *always* use the latest build, not a cached version.
+ # It's an edge case, but when a new alpha is released, we need to use it ASAP.
+ check-latest: true
+
+ - name: Build ${{ matrix.platform }}
+ run: |
+ # Do the build for the requested platform.
+ make ${{ matrix.platform }} BUILD_NUMBER=${{ needs.config.outputs.BUILD_NUMBER }}
+
+ - name: Upload build artefacts
+ uses: actions/upload-artifact@v7.0.0
+ with:
+ name: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
+ path: dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
+
+ briefcase-testbed:
+ name: Briefcase testbed (${{ matrix.platform }})
+ runs-on: macOS-15
+ needs: [ config, build ]
+ strategy:
+ fail-fast: false
+ matrix:
+ platform: ["macOS", "iOS"]
+ include:
+ - briefcase-run-args:
+
+ - platform: iOS
+ briefcase-run-args: ' -d "iPhone 16e::iOS 18.5"'
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Set up Xcode
+ # GitHub recommends explicitly selecting the desired Xcode version:
+ # https://github.com/actions/runner-images/issues/12541#issuecomment-3083850140
+ # This became a necessity as a result of
+ # https://github.com/actions/runner-images/issues/12541 and
+ # https://github.com/actions/runner-images/issues/12751.
+ run: |
+ sudo xcode-select --switch /Applications/Xcode_16.4.app
+
+ - name: Get build artifact
+ uses: actions/download-artifact@v8.0.1
+ with:
+ pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
+ path: dist
+ merge-multiple: true
+
+ - name: Set up Python
+ uses: actions/setup-python@v6.2.0
+ with:
+ # Appending -dev ensures that we can always build the dev release.
+ # It's a no-op for versions that have been published.
+ python-version: ${{ needs.config.outputs.PYTHON_VER }}-dev
+ # Ensure that we *always* use the latest build, not a cached version.
+ # It's an edge case, but when a new alpha is released, we need to use it ASAP.
+ check-latest: true
+
+ - uses: actions/checkout@v6
+ with:
+ repository: beeware/Python-support-testbed
+ path: Python-support-testbed
+
+ - name: Install dependencies
+ run: |
+ # Use the development version of Briefcase
+ python -m pip install git+https://github.com/beeware/briefcase.git
+
+ - name: Run support testbed check
+ timeout-minutes: 15
+ working-directory: Python-support-testbed
+ run: briefcase run ${{ matrix.platform }} Xcode --test ${{ matrix.briefcase-run-args }} -C support_package=\'../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz\'
+
+ cpython-testbed:
+ name: CPython testbed (${{ matrix.platform }})
+ runs-on: macOS-15
+ needs: [ config, build ]
+ strategy:
+ fail-fast: false
+ matrix:
+ platform: ["iOS", "tvOS", "visionOS"]
+ include:
+ - platform: "iOS"
+ testbed-args: '--simulator "iPhone 16e,arch=arm64,OS=18.5"'
+ - platform: "visionOS"
+ testbed-args: '--simulator "Apple Vision Pro,arch=arm64,OS=2.5"'
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Get build artifact
+ uses: actions/download-artifact@v8.0.1
+ with:
+ pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
+ path: dist
+ merge-multiple: true
+
+ - name: Set up Xcode
+ # GitHub recommends explicitly selecting the desired Xcode version:
+ # https://github.com/actions/runner-images/issues/12541#issuecomment-3083850140
+ # This became a necessity as a result of
+ # https://github.com/actions/runner-images/issues/12541 and
+ # https://github.com/actions/runner-images/issues/12751.
+ run: |
+ sudo xcode-select --switch /Applications/Xcode_16.4.app
+
+ - name: Set up Python
+ uses: actions/setup-python@v6.2.0
+ with:
+ # Appending -dev ensures that we can always build the dev release.
+ # It's a no-op for versions that have been published.
+ python-version: ${{ needs.config.outputs.PYTHON_VER }}-dev
+ # Ensure that we *always* use the latest build, not a cached version.
+ # It's an edge case, but when a new alpha is released, we need to use it ASAP.
+ check-latest: true
+
+ - name: Unpack support package
+ run: |
+ mkdir -p support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
+ cd support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
+ tar zxvf ../../../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
+
+ - name: Run CPython testbed
+ timeout-minutes: 15
+ working-directory: support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
+ run: |
+ # Run a representative subset of CPython core tests:
+ # - test_builtin as a test of core language tools
+ # - test_grammar as a test of core language features
+ # - test_os as a test of system library calls
+ # - test_bz2 as a simple test of third party libraries
+ # - test_ctypes as a test of FFI
+ python -m testbed run --verbose ${{ matrix.testbed-args }} -- test --single-process --rerun -W test_builtin test_grammar test_os test_bz2 test_ctypes
+
+ crossenv-test:
+ name: Cross-platform env test (${{ matrix.multiarch }})
+ runs-on: macOS-latest
+ needs: [ config, build ]
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - platform: iOS
+ slice: ios-arm64_x86_64-simulator
+ multiarch: arm64-iphonesimulator
+ - platform: iOS
+ slice: ios-arm64_x86_64-simulator
+ multiarch: x86_64-iphonesimulator
+ - platform: iOS
+ slice: ios-arm64
+ multiarch: arm64-iphoneos
+
+ steps:
+ - uses: actions/checkout@v6
+
+ - name: Get build artifact
+ uses: actions/download-artifact@v8.0.1
+ with:
+ pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
+ path: dist
+ merge-multiple: true
+
+ - name: Set up Python
+ uses: actions/setup-python@v6.2.0
+ with:
+ # Appending -dev ensures that we can always build the dev release.
+ # It's a no-op for versions that have been published.
+ python-version: ${{ needs.config.outputs.PYTHON_VER }}-dev
+ # Ensure that we *always* use the latest build, not a cached version.
+ # It's an edge case, but when a new alpha is released, we need to use it ASAP.
+ check-latest: true
+
+ - name: Unpack support package
+ run: |
+ mkdir -p support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
+ cd support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
+ tar zxvf ../../../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
+
+ - name: Run cross-platform environment test
+ env:
+ PYTHON_CROSS_PLATFORM: ${{ matrix.platform }}
+ PYTHON_CROSS_SLICE: ${{ matrix.slice }}
+ PYTHON_CROSS_MULTIARCH: ${{ matrix.multiarch }}
+ run: |
+ # Create and activate a native virtual environment
+ python${{ needs.config.outputs.PYTHON_VER }} -m venv cross-venv
+ source cross-venv/bin/activate
+
+ # Install pytest
+ python -m pip install pytest
+
+ # Convert venv into cross-venv
+ python support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}/Python.xcframework/${{ matrix.slice }}/platform-config/${{ matrix.multiarch }}/make_cross_venv.py cross-venv
+
+ # Run the test suite
+ python -m pytest tests
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index fd2c9623..1ba719c4 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -8,24 +8,26 @@ jobs:
publish:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v6
+
- name: Set up Python environment
- uses: actions/setup-python@v1
+ uses: actions/setup-python@v6.2.0
with:
python-version: "3.X"
+
- name: Set build variables
+ id: build-vars
env:
TAG_NAME: ${{ github.ref }}
run: |
- export TAG=$(basename $TAG_NAME)
- echo "TAG=${TAG}"
- export TAG_VERSION="${TAG%-*}"
- export TAG_BUILD="${TAG#*-}"
- echo "PY_VERSION=${TAG_VERSION}"
- echo "BUILD_NUMBER=${TAG_BUILD}"
- echo "TAG=${TAG}" >> $GITHUB_ENV
- echo "PY_VERSION=${TAG_VERSION}" >> $GITHUB_ENV
- echo "BUILD_NUMBER=${TAG_BUILD}" >> $GITHUB_ENV
+ TAG=$(basename $TAG_NAME)
+ PYTHON_VER="${TAG%-*}"
+ BUILD_NUMBER="${TAG#*-}"
+
+ echo "TAG=${TAG}" | tee -a ${GITHUB_OUTPUT}
+ echo "PYTHON_VER=${PYTHON_VER}" | tee -a ${GITHUB_OUTPUT}
+ echo "BUILD_NUMBER=${BUILD_NUMBER}" | tee -a ${GITHUB_OUTPUT}
+
- name: Update Release Asset to S3
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
@@ -35,14 +37,17 @@ jobs:
python -m pip install -U setuptools
python -m pip install awscli
# macOS build
- curl -o macOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ env.TAG }}/Python-${{ env.PY_VERSION }}-macOS-support.${{ env.BUILD_NUMBER }}.tar.gz
- aws s3 cp macOS-artefact.tar.gz s3://briefcase-support/python/${{ env.PY_VERSION }}/macOS/Python-${{ env.PY_VERSION }}-macOS-support.${{ env.BUILD_NUMBER }}.tar.gz
+ curl -o macOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ steps.build-vars.outputs.TAG }}/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-macOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
+ aws s3 cp macOS-artefact.tar.gz s3://briefcase-support/python/${{ steps.build-vars.outputs.PYTHON_VER }}/macOS/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-macOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
# iOS build
- curl -o iOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ env.TAG }}/Python-${{ env.PY_VERSION }}-iOS-support.${{ env.BUILD_NUMBER }}.tar.gz
- aws s3 cp iOS-artefact.tar.gz s3://briefcase-support/python/${{ env.PY_VERSION }}/iOS/Python-${{ env.PY_VERSION }}-iOS-support.${{ env.BUILD_NUMBER }}.tar.gz
+ curl -o iOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ steps.build-vars.outputs.TAG }}/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-iOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
+ aws s3 cp iOS-artefact.tar.gz s3://briefcase-support/python/${{ steps.build-vars.outputs.PYTHON_VER }}/iOS/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-iOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
# tvOS build
- curl -o tvOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ env.TAG }}/Python-${{ env.PY_VERSION }}-tvOS-support.${{ env.BUILD_NUMBER }}.tar.gz
- aws s3 cp tvOS-artefact.tar.gz s3://briefcase-support/python/${{ env.PY_VERSION }}/tvOS/Python-${{ env.PY_VERSION }}-tvOS-support.${{ env.BUILD_NUMBER }}.tar.gz
+ curl -o tvOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ steps.build-vars.outputs.TAG }}/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-tvOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
+ aws s3 cp tvOS-artefact.tar.gz s3://briefcase-support/python/${{ steps.build-vars.outputs.PYTHON_VER }}/tvOS/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-tvOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
# watchOS build
- curl -o watchOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ env.TAG }}/Python-${{ env.PY_VERSION }}-watchOS-support.${{ env.BUILD_NUMBER }}.tar.gz
- aws s3 cp watchOS-artefact.tar.gz s3://briefcase-support/python/${{ env.PY_VERSION }}/watchOS/Python-${{ env.PY_VERSION }}-watchOS-support.${{ env.BUILD_NUMBER }}.tar.gz
+ curl -o watchOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ steps.build-vars.outputs.TAG }}/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-watchOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
+ aws s3 cp watchOS-artefact.tar.gz s3://briefcase-support/python/${{ steps.build-vars.outputs.PYTHON_VER }}/watchOS/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-watchOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
+ # visionOS build
+ curl -o visionOS-artefact.tar.gz -L https://github.com/beeware/Python-Apple-support/releases/download/${{ steps.build-vars.outputs.TAG }}/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-visionOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
+ aws s3 cp visionOS-artefact.tar.gz s3://briefcase-support/python/${{ steps.build-vars.outputs.PYTHON_VER }}/visionOS/Python-${{ steps.build-vars.outputs.PYTHON_VER }}-visionOS-support.${{ steps.build-vars.outputs.BUILD_NUMBER }}.tar.gz
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 9d4b1fdf..02e514c9 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -8,89 +8,59 @@ on:
- '*-b*'
jobs:
- make-release:
- runs-on: ubuntu-latest
+ config:
+ name: Build vars
+ runs-on: macOS-latest
+ outputs:
+ TAG: ${{ steps.build-vars.outputs.TAG }}
+ BUILD_NUMBER: ${{ steps.build-vars.outputs.BUILD_NUMBER }}
+
steps:
- - name: Set build variables
+ - name: Set Build Variables
+ id: build-vars
env:
TAG_NAME: ${{ github.ref }}
run: |
export TAG=$(basename $TAG_NAME)
- echo "TAG=${TAG}"
- export TAG_VERSION="${TAG%-*}"
- export TAG_BUILD="${TAG#*-}"
- echo "PY_VERSION=${TAG_VERSION}"
- echo "BUILD_NUMBER=${TAG_BUILD}"
- echo "TAG=${TAG}" >> $GITHUB_ENV
- echo "PY_VERSION=${TAG_VERSION}" >> $GITHUB_ENV
- echo "BUILD_NUMBER=${TAG_BUILD}" >> $GITHUB_ENV
- - name: Create Release
- id: create_release
- uses: actions/create-release@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- tag_name: ${{ github.ref }}
- release_name: ${{ github.ref }}
- draft: true
- prerelease: false
- body: |
- Build ${{ env.BUILD_NUMBER }} of the BeeWare support package for Python ${{ env.PY_VERSION }}.
+ export BUILD_NUMBER="${TAG#*-}"
- Includes:
- * Python ${{ env.PY_VERSION }}.?
- * OpenSSL 3.0.5
- * BZip2 1.0.8
- * XZ 5.2.6
- * LibFFI 3.4.2
- outputs:
- upload_url: ${{ steps.create_release.outputs.upload_url }}
+ echo "TAG=${TAG}" | tee -a ${GITHUB_OUTPUT}
+ echo "BUILD_NUMBER=${BUILD_NUMBER}" | tee -a ${GITHUB_OUTPUT}
+
+ ci:
+ name: CI
+ needs: [ config ]
+ uses: ./.github/workflows/ci.yaml
+ with:
+ build-number: ${{ needs.config.outputs.BUILD_NUMBER }}
- build:
- runs-on: macOS-12
- needs: make-release
- strategy:
- max-parallel: 4
- matrix:
- target: ['macOS', 'iOS', 'tvOS', 'watchOS']
+ make-release:
+ name: Make Release
+ runs-on: ubuntu-latest
+ needs: [ config, ci ]
steps:
- - uses: actions/checkout@v2
- - name: Set build variables
- env:
- TAG_NAME: ${{ github.ref }}
- run: |
- export TAG=$(basename $TAG_NAME)
- echo "TAG=${TAG}"
- export TAG_VERSION="${TAG%-*}"
- export TAG_BUILD="${TAG#*-}"
- echo "PY_VERSION=${TAG_VERSION}"
- echo "BUILD_NUMBER=${TAG_BUILD}"
- echo "TAG=${TAG}" >> $GITHUB_ENV
- echo "PY_VERSION=${TAG_VERSION}" >> $GITHUB_ENV
- echo "BUILD_NUMBER=${TAG_BUILD}" >> $GITHUB_ENV
- - name: Set up Python
- uses: actions/setup-python@v3.1.2
+ - name: Get build artifacts
+ uses: actions/download-artifact@v8.0.1
with:
- python-version: ${{ env.TAG_VERSION }}
- - name: Build ${{ matrix.target }}
- env:
- BUILD_NUMBER: ${{ env.BUILD_NUMBER }}
- run: |
- # 2020-06-24: The Homebrew copy of gettext leaks into the macOS build
- # if it is present. Uninstall gettext to make sure that doesn't happen.
- # 2021-01-02: Uninstall curl as well. We need curl to download the
- # source bundles, but Homebrew's curl has a runtime dependency on
- # gettext. However macOS provides a version of curl that works fine.
- brew uninstall --ignore-dependencies gettext curl
+ pattern: Python-*
+ path: dist
+ merge-multiple: true
- # Do the build for the requested target.
- make -e ${{ matrix.target }}
- - name: Upload ${{ matrix.target }} release asset
- uses: actions/upload-release-asset@v1
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Create Release
+ uses: ncipollo/release-action@v1.21.0
with:
- upload_url: ${{ needs.make-release.outputs.upload_url }}
- asset_path: ./dist/Python-${{ env.PY_VERSION }}-${{ matrix.target }}-support.${{ env.BUILD_NUMBER }}.tar.gz
- asset_name: Python-${{ env.PY_VERSION }}-${{ matrix.target }}-support.${{ env.BUILD_NUMBER }}.tar.gz
- asset_content_type: application/gzip
+ name: ${{ needs.ci.outputs.PYTHON_VER }}-${{ needs.config.outputs.BUILD_NUMBER }}
+ tag: ${{ needs.ci.outputs.PYTHON_VER }}-${{ needs.config.outputs.BUILD_NUMBER }}
+ draft: true
+ body: |
+ Build ${{ needs.config.outputs.BUILD_NUMBER }} of the BeeWare support package for Python ${{ needs.ci.outputs.PYTHON_VER }}.
+
+ Includes:
+ * Python ${{ needs.ci.outputs.PYTHON_VERSION }}
+ * BZip2 ${{ needs.ci.outputs.BZIP2_VERSION }}
+ * libFFI ${{ needs.ci.outputs.LIBFFI_VERSION }}
+ * mpdecimal ${{ needs.ci.outputs.MPDECIMAL_VERSION }}
+ * OpenSSL ${{ needs.ci.outputs.OPENSSL_VERSION }}
+ * XZ ${{ needs.ci.outputs.XZ_VERSION }}
+ * Zstandard ${{ needs.ci.outputs.ZSTD_VERSION }}
+ artifacts: "dist/*"
diff --git a/.gitignore b/.gitignore
index 0fb0445a..a87e3e2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,18 +2,18 @@
*.swp
.envrc
.vscode/
-archive/*
-build/*
-diff/*
-dist/*
-downloads/*
-install/*
-local/*
-merge/*
-src/*
-support/*
-wheels/*
+build
+dist
+downloads
+install
+local
+support
*.dist-info
__pycache__
tests/testbed/macOS
tests/testbed/iOS
+*.log
+*.gz
+*.DS_Store
+cross-venv/
+temp
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..c4d88e81
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,162 @@
+
+
+
+# BeeWare Community Code of Conduct
+
+## Our pledge
+
+We pledge to make our community welcoming, safe, and equitable for all.
+
+We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant.
+
+The guidelines within and enforcement of the BeeWare Community Code of Conduct apply equally to everyone participating in the BeeWare community, including members of the Code of Conduct Response Team.
+
+## Encouraged behaviors
+
+While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language.
+
+With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including:
+
+1. Respecting the **purpose of our community**, our activities, and our ways of gathering.
+2. Engaging **kindly and honestly** with others.
+3. Respecting **different viewpoints** and experiences.
+4. **Taking responsibility** for our actions and contributions.
+5. Gracefully giving and accepting **constructive feedback**.
+6. Committing to **repairing harm** when it occurs.
+7. Behaving in other ways that promote and sustain the **well-being of our community**.
+
+## Restricted behaviors
+
+We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct.
+
+1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop.
+2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people.
+3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of a personal identity or trait.
+4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community.
+5. **Violating confidentiality.** Sharing or acting on someone's personal or private information without their permission.
+6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group.
+7. Behaving in other ways that **threaten the well-being** of our community.
+
+### Other restrictions
+
+1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions.
+2. **Misrepresenting project affiliation.** Speaking or acting in a way that implies an official affiliation with the BeeWare project, where one does not exist.
+3. **Failing to credit sources.** Not properly crediting the sources of content you contribute.
+4. **Promotional materials.** Sharing marketing or other commercial content in a way that is outside the norms of the community.
+5. **Excessive communication.** Disrespecting the time and space of others by engaging in an unacceptable volume of communication.
+6. **Unhelpful communication.** Offering opinions without relevant experience in the topic being discussed, entering into an ongoing discussion without first gaining familiarity with the history of the topic, or making contributions that are off-topic or otherwise distracting.
+7. **Irresponsible messaging.** Presenting content which includes, links, or describes other restricted behaviors without a relevant reason and appropriate prior warnings for consumers of that content.
+8. Other conduct that could reasonably be considered **unprofessional or inappropriate**.
+
+## Reporting an issue
+
+Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm. Reporting even minor issues is important, as they can be helpful in identifying patterns of behavior that may not be concerning in isolation, but when viewed collectively may be more significant.
+
+When an incident does occur, it is important to report it promptly to the BeeWare Code of Conduct Response Team.
+
+**If you believe you or anyone else is in physical danger, please notify appropriate law enforcement first.**
+
+To report a possible violation, email the Team at [conduct@beeware.org](mailto:conduct@beeware.org). If necessary, you can reach out to individual team members. On the BeeWare Discord server, you can also direct message anyone on the Response Team, or, if appropriate, mention `@moderators` in a public channel. Team members can be reached by the following usernames on Discord or GitHub, or the provided email addresses:
+
+* Russell Keith-Magee (@freakboy3742; [russell@beeware.org](mailto:russell@beeware.org))
+* Kattni (@kattni; [kattni@beeware.org](mailto:kattni@beeware.org))
+* Katie McLaughlin (@glasnt; [katie@beeware.org](mailto:katie@beeware.org))
+* Philip James (@phildini; [philip@beeware.org](mailto:philip@beeware.org))
+* Charles Whittington (@HalfWhitt; [charles@beeware.org](mailto:charles@beeware.org))
+
+The Response Team takes reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. The Team will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution. If we determine that a public statement needs to be made, the identities of all victims and reporters will remain confidential unless those individuals instruct us otherwise.
+
+In your report, please include:
+
+* **Your contact info** so we can get in touch with you if we need to follow up.
+* **Names (real, nicknames, or pseudonyms) of any individuals involved.** If there were other witnesses besides you, please try to include them as well.
+* **When and where the incident occurred.** Please be as specific as possible.
+* **Your account of what occurred.** If there is a publicly available record (e.g. a Discord or GitHub message) please include a link.
+* **Any extra context** you believe existed for the incident.
+* **If you believe this incident is ongoing.**
+* **If you believe any member of the Response Team has a conflict of interest** in adjudicating the incident.
+* **What, if any, corrective response** you believe would be appropriate.
+* **Any other information** you believe we should have.
+
+Code of Conduct Response Team members are obligated to maintain confidentiality with regard to the reporter and details of an incident.
+
+## The Response Team's report followup
+
+You will receive a response acknowledging receipt of your report. We promise to acknowledge receipt within 24 hours (and will aim for much quicker than that).
+
+The Response Team will immediately meet to review the incident and determine:
+
+* What happened.
+* Whether this event constitutes a code of conduct violation.
+* Who the reported person is.
+* Whether this is an ongoing situation, or if there is a threat to anyone's physical safety.
+* If this is determined to be an ongoing incident or a threat to physical safety, the Response Team's immediate priority will be to protect everyone involved. This means we may delay an official response until we believe that the situation has concluded and that everyone is physically safe.
+* If a member of the Response Team is one of the named parties, they will not be included in any discussions, and will not be provided with any confidential details from the reporter.
+
+If anyone on the Response Team believes they have a conflict of interest in adjudicating on a reported issue, they will inform the other Response Team members, and recuse themselves from any discussion about the issue. Following this declaration, they will not be provided with any confidential details from the reporter.
+
+We'll respond within one week to the person who filed the report with either a resolution or an explanation of why the situation is not yet resolved.
+
+Once we've determined our final action, we'll contact the original reporter to let them know what action (if any) we'll be taking. We'll take into account feedback from the reporter on the appropriateness of our response, but we don't guarantee we'll act on it.
+
+Finally, to maintain transparency in the reporting and enforcement process, whenever possible, the Response Team will make a public report of the incident on [The Buzz](https://beeware.org/news/buzz), the BeeWare blog. A public report may not be made if the specifics of the incident do not allow us to preserve anonymity, or if there is potential for ongoing harm.
+
+## Enforcement: addressing and repairing harm
+
+If an investigation by the Response Team finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped.
+
+1. Warning
+ * Event: A violation involving a single incident or series of incidents.
+ * Consequence: A private, written warning from the Response Team.
+ * Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations.
+
+2. Temporarily Limited Activities
+ * Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation.
+ * Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members.
+ * Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over.
+
+3. Temporary Suspension
+ * Event: A pattern of repeated violation which the Response Team has tried to address with warnings, or a single serious violation.
+ * Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions. Suspensions will be based on where the violation occurs, and may be limited to the space in which the violation occurs. In the event of a more serious violation, the suspension may apply to all spaces.
+ * Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted.
+
+4. Permanent Ban
+ * Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Response Team determines there is no way to keep the community safe with this person as a member.
+ * Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior.
+ * Repair: There is no possible repair in cases of this severity.
+
+This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, including GitHub, the BeeWare Discord server, and in-person events, such as conferences, meetups, and sprints. It also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
+
+Behavior outside of official BeeWare spaces may also be considered as supporting evidence for a report if that behavior establishes a pattern, or represents a potential risk to the BeeWare community.
+
+This Code of Conduct operates in parallel to any Code of Conduct that is in effect in a given context (e.g., the Code of Conduct for a conference). If an incident occurs, we encourage reporting that incident to all relevant conduct groups. Known violations of other Codes of Conduct may be considered as supporting evidence for a report under this Code of Conduct. The BeeWare Code of Conduct Response Team will cooperate with other Code of Conduct teams, but will not disclose any identifying details without the prior consent of the reporting party.
+
+## Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/).
+
+Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
+
+For answers to common questions about Contributor Covenant, see the [FAQ](https://www.contributor-covenant.org/faq). [Translations](https://www.contributor-covenant.org/translations) are provided. There are [additional enforcement and community guideline resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion).
+
+## Changes
+
+Major substantive changes are listed here; for a complete list of changes see the GitHub commit history.
+
+* **December 15, 2025:** Updated to adapt the Contributor Covenant, version 3.0, with some modifications for BeeWare-specific guidelines and procedures.
+
+* **July 4, 2016:** Added instructions and guidelines for reporting incidents.
+
+* **December 5, 2015:** Initial Code of Conduct adopted.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d6aad904..dfed555e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,7 +2,44 @@
BeeWare <3's contributions!
-Please be aware, BeeWare operates under a Code of Conduct.
+Please be aware that BeeWare operates under a [Code of
+Conduct](https://beeware.org/community/behavior/code-of-conduct/).
-See [CONTRIBUTING to BeeWare](https://beeware.org/contributing) for details.
+See [CONTRIBUTING to BeeWare](https://beeware.org/contributing) for general
+project contribution guidelines.
+Unless a fix is version specific, PRs should genereally be made against the
+`main` branch of this repo, targeting the current development version of Python.
+Project maintainers will manage the process of backporting changes to older
+Python versions.
+
+## Changes to `Python.patch`
+
+Additional handling is required if you need to make modifications to the patch
+applied to Python sources (`patch/Python/Python.patch`).
+
+Any iOS or macOS-specific changes should be submitted to the [upstream CPython
+repository](https://github.com/python/cpython). macOS and iOS are both
+officially supported Python platforms, and the code distributed by this project
+for those platforms is unmodified from the official repository.
+
+Changes to to support other platforms can be included in a PR for this repo, but
+they must also be submitted as a pull request against the `MAJOR.MINOR-patched`
+branch on [the `freakboy3742` fork of the CPython
+repo](https://github.com/freakboy3742/cpython). This is required to ensure that
+any contributed changes can be easily reproduced in future patches as more
+changes are made.
+
+Note that the `MAJOR.MINOR-patched` branch of that fork is maintained in the format
+of a *patch tree*, which is a branch that consists of an entirely linear sequence of
+commits applied on top of another branch (in the case of the fork, `MAJOR.MINOR`),
+each of which adds a significant new feature. Therefore, a bug fix for an existing commit
+in the patch tree *will* be merged when appropriate, but its changes will get combined
+with that existing commit that adds the feature. A feature addition PR will be squashed
+into a single, new commit, and then put on top of the patch tree.
+
+This also means that if another contributor gets a pull request merged into
+`MAJOR.MINOR-patched`, you must *rebase* your changes on top of the updated
+`MAJOR.MINOR-patched` branch, as opposed to *merging* `MAJOR.MINOR-patched` into your
+branch, since the "history" of a patch tree is likely to change in a way that is
+incompatible with merge commits.
diff --git a/Makefile b/Makefile
index 702ce082..dcbb49b3 100644
--- a/Makefile
+++ b/Makefile
@@ -5,91 +5,72 @@
# - iOS - build everything for iOS
# - tvOS - build everything for tvOS
# - watchOS - build everything for watchOS
-# - BZip2 - build BZip2 for all platforms
-# - BZip2-macOS - build BZip2 for macOS
-# - BZip2-iOS - build BZip2 for iOS
-# - BZip2-tvOS - build BZip2 for tvOS
-# - BZip2-watchOS - build BZip2 for watchOS
-# - XZ - build XZ for all platforms
-# - XZ-macOS - build XZ for macOS
-# - XZ-iOS - build XZ for iOS
-# - XZ-tvOS - build XZ for tvOS
-# - XZ-watchOS - build XZ for watchOS
-# - OpenSSL - build OpenSSL for all platforms
-# - OpenSSL-macOS - build OpenSSL for macOS
-# - OpenSSL-iOS - build OpenSSL for iOS
-# - OpenSSL-tvOS - build OpenSSL for tvOS
-# - OpenSSL-watchOS - build OpenSSL for watchOS
-# - libFFI - build libFFI for all platforms (except macOS)
-# - libFFI-iOS - build libFFI for iOS
-# - libFFI-tvOS - build libFFI for tvOS
-# - libFFI-watchOS - build libFFI for watchOS
-# - Python - build Python for all platforms
-# - Python-macOS - build Python for macOS
-# - Python-iOS - build Python for iOS
-# - Python-tvOS - build Python for tvOS
-# - Python-watchOS - build Python for watchOS
-
-# Current director
+# - visionOS - build everything for visionOS
+
+# Current directory
PROJECT_DIR=$(shell pwd)
BUILD_NUMBER=custom
# Version of packages that will be compiled by this meta-package
# PYTHON_VERSION is the full version number (e.g., 3.10.0b3)
+# PYTHON_PKG_VERSION is the version number with binary package releases to use
+# for macOS binaries. This will be less than PYTHON_VERSION towards the end
+# of a release cycle, as official binaries won't be published.
# 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.11.0
+PYTHON_VERSION=3.14.2
+PYTHON_PKG_VERSION=$(PYTHON_VERSION)
PYTHON_MICRO_VERSION=$(shell echo $(PYTHON_VERSION) | grep -Eo "\d+\.\d+\.\d+")
+PYTHON_PKG_MICRO_VERSION=$(shell echo $(PYTHON_PKG_VERSION) | grep -Eo "\d+\.\d+\.\d+")
PYTHON_VER=$(basename $(PYTHON_VERSION))
-BZIP2_VERSION=1.0.8
-
-XZ_VERSION=5.2.6
-
-# 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)
+# The binary releases of dependencies, published at:
+# https://github.com/beeware/cpython-apple-source-deps/releases
+BZIP2_VERSION=1.0.8-2
+LIBFFI_VERSION=3.4.7-2
+MPDECIMAL_VERSION=4.0.0-2
+OPENSSL_VERSION=3.0.18-1
+XZ_VERSION=5.6.4-2
+ZSTD_VERSION=1.5.7-1
-LIBFFI_VERSION=3.4.2
+# Supported OS
+OS_LIST=macOS iOS tvOS watchOS visionOS
-# Supported OS and dependencies
-DEPENDENCIES=BZip2 XZ OpenSSL libFFI
-OS_LIST=macOS iOS tvOS watchOS
-
-CURL_FLAGS=--fail --location --create-dirs --progress-bar
+CURL_FLAGS=--disable --fail --location --create-dirs --progress-bar
# macOS targets
TARGETS-macOS=macosx.x86_64 macosx.arm64
-VERSION_MIN-macOS=10.15
-CFLAGS-macOS=-mmacosx-version-min=$(VERSION_MIN-macOS)
+TRIPLE_OS-macOS=macos
+PLATFORM_NAME-macOS=macOS
+VERSION_MIN-macOS=11.0
# iOS targets
TARGETS-iOS=iphonesimulator.x86_64 iphonesimulator.arm64 iphoneos.arm64
-VERSION_MIN-iOS=12.0
-CFLAGS-iOS=-mios-version-min=$(VERSION_MIN-iOS)
+TRIPLE_OS-iOS=ios
+PLATFORM_NAME-iOS=iOS
+VERSION_MIN-iOS=13.0
# tvOS targets
TARGETS-tvOS=appletvsimulator.x86_64 appletvsimulator.arm64 appletvos.arm64
-VERSION_MIN-tvOS=9.0
-CFLAGS-tvOS=-mtvos-version-min=$(VERSION_MIN-tvOS)
-PYTHON_CONFIGURE-tvOS=ac_cv_func_sigaltstack=no
+TRIPLE_OS-tvOS=tvos
+PLATFORM_NAME-tvOS=tvOS
+VERSION_MIN-tvOS=12.0
# watchOS targets
TARGETS-watchOS=watchsimulator.x86_64 watchsimulator.arm64 watchos.arm64_32
+TRIPLE_OS-watchOS=watchos
+PLATFORM_NAME-watchOS=watchOS
VERSION_MIN-watchOS=4.0
-CFLAGS-watchOS=-mwatchos-version-min=$(VERSION_MIN-watchOS)
-PYTHON_CONFIGURE-watchOS=ac_cv_func_sigaltstack=no
+
+TARGETS-visionOS=xrsimulator.arm64 xros.arm64
+TRIPLE_OS-visionOS=xros
+PLATFORM_NAME-visionOS=xrOS
+VERSION_MIN-visionOS=2.0
# 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
+HOST_PYTHON=$(shell which python$(PYTHON_VER))
# 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
@@ -100,95 +81,46 @@ PATH=/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin
all: $(OS_LIST)
.PHONY: \
- 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 install merge dist support
+ all clean distclean update-patch vars config \
+ $(foreach os,$(OS_LIST),$(os) clean-$(os) dev-clean-$(os) vars-$(os)) \
+ $(foreach os,$(OS_LIST),$(foreach sdk,$$(sort $$(basename $$(TARGETS-$(os)))),$(sdk) vars-$(sdk)))
+ $(foreach os,$(OS_LIST),$(foreach target,$$(TARGETS-$(os)),$(target) vars-$(target)))
# Full clean - includes all downloaded products
distclean: clean
- rm -rf downloads
-
-downloads: \
- 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
+ rm -rf downloads build dist install support
update-patch:
# 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
+ # The patch archived in this repository 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) \
+ git diff --no-renames -D v$(PYTHON_VERSION) $(PYTHON_VER)-patched \
| PATH="/usr/local/bin:/opt/homebrew/bin:$(PATH)" filterdiff \
-X $(PROJECT_DIR)/patch/Python/diff.exclude -p 1 --clean \
> $(PROJECT_DIR)/patch/Python/Python.patch
-###########################################################################
-# Setup: BZip2
-###########################################################################
-
-# Download original BZip2 source code archive.
-downloads/bzip2-$(BZIP2_VERSION).tar.gz:
- @echo ">>> Download BZip2 sources"
- curl $(CURL_FLAGS) -o $@ \
- https://sourceware.org/pub/bzip2/$(notdir $@)
-
-###########################################################################
-# Setup: XZ (LZMA)
-###########################################################################
-
-# Download original XZ source code archive.
-downloads/xz-$(XZ_VERSION).tar.gz:
- @echo ">>> Download XZ sources"
- curl $(CURL_FLAGS) -o $@ \
- https://tukaani.org/xz/$(notdir $@)
-
-###########################################################################
-# Setup: OpenSSL
-# These build instructions adapted from the scripts developed by
-# Felix Shchulze (@x2on) https://github.com/x2on/OpenSSL-for-iPhone
-###########################################################################
-
-# Download original OpenSSL source code archive.
-downloads/openssl-$(OPENSSL_VERSION).tar.gz:
- @echo ">>> Download OpenSSL sources"
- 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 libFFI source code archive.
-downloads/libffi-$(LIBFFI_VERSION).tar.gz:
- @echo ">>> Download libFFI sources"
- 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).tar.gz:
@echo ">>> Download Python sources"
+ mkdir -p downloads
+ curl $(CURL_FLAGS) -o $@ \
+ https://www.python.org/ftp/python/$(PYTHON_MICRO_VERSION)/Python-$(PYTHON_VERSION).tgz
+
+downloads/python-$(PYTHON_PKG_VERSION)-macos11.pkg:
+ @echo ">>> Download macOS Python package"
+ mkdir -p downloads
curl $(CURL_FLAGS) -o $@ \
- https://www.python.org/ftp/python/$(PYTHON_MICRO_VERSION)/$(basename $(basename $(notdir $@))).tgz
+ https://www.python.org/ftp/python/$(PYTHON_PKG_MICRO_VERSION)/python-$(PYTHON_PKG_VERSION)-macos11.pkg
###########################################################################
# Build for specified target (from $(TARGETS-*))
@@ -204,262 +136,122 @@ 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)))
-ifeq ($(os),macOS)
-TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-darwin
-else
+ifneq ($(os),macOS)
ifeq ($$(findstring simulator,$$(SDK-$(target))),)
-TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))
+TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(TRIPLE_OS-$(os))$$(VERSION_MIN-$(os))
+IS_SIMULATOR-$(target)=False
else
-TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(OS_LOWER-$(target))-simulator
+TARGET_TRIPLE-$(target)=$$(ARCH-$(target))-apple-$$(TRIPLE_OS-$(os))$$(VERSION_MIN-$(os))-simulator
+IS_SIMULATOR-$(target)=True
endif
endif
SDK_ROOT-$(target)=$$(shell xcrun --sdk $$(SDK-$(target)) --show-sdk-path)
-CC-$(target)=xcrun --sdk $$(SDK-$(target)) clang -target $$(TARGET_TRIPLE-$(target))
-CPP-$(target)=xcrun --sdk $$(SDK-$(target)) clang -target $$(TARGET_TRIPLE-$(target)) -E
-CXX-$(target)=xcrun --sdk $$(SDK-$(target)) clang -target $$(TARGET_TRIPLE-$(target))
-AR-$(target)=xcrun --sdk $$(SDK-$(target)) ar
-CFLAGS-$(target)=$$(CFLAGS-$(os))
-LDFLAGS-$(target)=$$(CFLAGS-$(os))
###########################################################################
# Target: BZip2
###########################################################################
-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_SRCDIR-$(target))/Makefile: downloads/bzip2-$(BZIP2_VERSION).tar.gz
- @echo ">>> Unpack BZip2 sources for $(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_SRCDIR-$(target))/Makefile
-
-$$(BZIP2_LIB-$(target)): $$(BZIP2_SRCDIR-$(target))/Makefile
- @echo ">>> Build BZip2 for $(target)"
- cd $$(BZIP2_SRCDIR-$(target)) && \
- make install \
- PREFIX="$$(BZIP2_INSTALL-$(target))" \
- CC="$$(CC-$(target))" \
- 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
+
+downloads/bzip2-$(BZIP2_VERSION)-$(target).tar.gz:
+ @echo ">>> Download BZip2 for $(target)"
+ mkdir -p downloads
+ curl $(CURL_FLAGS) -o $$@ \
+ https://github.com/beeware/cpython-apple-source-deps/releases/download/BZip2-$(BZIP2_VERSION)/bzip2-$(BZIP2_VERSION)-$(target).tar.gz
+
+$$(BZIP2_LIB-$(target)): downloads/bzip2-$(BZIP2_VERSION)-$(target).tar.gz
+ @echo ">>> Install BZip2 for $(target)"
+ mkdir -p $$(BZIP2_INSTALL-$(target))
+ cd $$(BZIP2_INSTALL-$(target)) && tar zxvf $(PROJECT_DIR)/downloads/bzip2-$(BZIP2_VERSION)-$(target).tar.gz --exclude="*.dylib"
+ # Ensure the target is marked as clean.
+ touch $$(BZIP2_LIB-$(target))
###########################################################################
# Target: XZ (LZMA)
###########################################################################
-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_SRCDIR-$(target))/Makefile: downloads/xz-$(XZ_VERSION).tar.gz
- @echo ">>> Unpack XZ sources for $(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_SRCDIR-$(target)) && \
- ./configure \
- CC="$$(CC-$(target))" \
- CFLAGS="$$(CFLAGS-$(target))" \
- LDFLAGS="$$(LDFLAGS-$(target))" \
- --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_SRCDIR-$(target))/Makefile
- @echo ">>> Build and install XZ for $(target)"
- cd $$(XZ_SRCDIR-$(target)) && \
- make install \
- 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
+
+downloads/xz-$(XZ_VERSION)-$(target).tar.gz:
+ @echo ">>> Download XZ for $(target)"
+ mkdir -p downloads
+ curl $(CURL_FLAGS) -o $$@ \
+ https://github.com/beeware/cpython-apple-source-deps/releases/download/XZ-$(XZ_VERSION)/xz-$(XZ_VERSION)-$(target).tar.gz
+
+$$(XZ_LIB-$(target)): downloads/xz-$(XZ_VERSION)-$(target).tar.gz
+ @echo ">>> Install XZ for $(target)"
+ mkdir -p $$(XZ_INSTALL-$(target))
+ cd $$(XZ_INSTALL-$(target)) && tar zxvf $(PROJECT_DIR)/downloads/xz-$(XZ_VERSION)-$(target).tar.gz --exclude="*.dylib"
+ # Ensure the target is marked as clean.
+ touch $$(XZ_LIB-$(target))
+
+###########################################################################
+# Target: zstd (ZStandard)
+###########################################################################
+
+ZSTD_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/zstd-$(ZSTD_VERSION)
+ZSTD_LIB-$(target)=$$(ZSTD_INSTALL-$(target))/lib/libzstd.a
+
+downloads/zstd-$(ZSTD_VERSION)-$(target).tar.gz:
+ @echo ">>> Download zstd for $(target)"
+ mkdir -p downloads
+ curl $(CURL_FLAGS) -o $$@ \
+ https://github.com/beeware/cpython-apple-source-deps/releases/download/zstd-$(ZSTD_VERSION)/zstd-$(ZSTD_VERSION)-$(target).tar.gz
+
+$$(ZSTD_LIB-$(target)): downloads/zstd-$(ZSTD_VERSION)-$(target).tar.gz
+ @echo ">>> Install zstd for $(target)"
+ mkdir -p $$(ZSTD_INSTALL-$(target))
+ cd $$(ZSTD_INSTALL-$(target)) && tar zxvf $(PROJECT_DIR)/downloads/zstd-$(ZSTD_VERSION)-$(target).tar.gz --exclude="*.dylib"
+ # Ensure the target is marked as clean.
+ touch $$(ZSTD_LIB-$(target))
+
+###########################################################################
+# Target: mpdecimal
+###########################################################################
+
+MPDECIMAL_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/mpdecimal-$(MPDECIMAL_VERSION)
+MPDECIMAL_LIB-$(target)=$$(MPDECIMAL_INSTALL-$(target))/lib/libmpdec.a
+
+downloads/mpdecimal-$(MPDECIMAL_VERSION)-$(target).tar.gz:
+ @echo ">>> Download mpdecimal for $(target)"
+ mkdir -p downloads
+ curl $(CURL_FLAGS) -o $$@ \
+ https://github.com/beeware/cpython-apple-source-deps/releases/download/mpdecimal-$(MPDECIMAL_VERSION)/mpdecimal-$(MPDECIMAL_VERSION)-$(target).tar.gz
+
+$$(MPDECIMAL_LIB-$(target)): downloads/mpdecimal-$(MPDECIMAL_VERSION)-$(target).tar.gz
+ @echo ">>> Install mpdecimal for $(target)"
+ mkdir -p $$(MPDECIMAL_INSTALL-$(target))
+ cd $$(MPDECIMAL_INSTALL-$(target)) && tar zxvf $(PROJECT_DIR)/downloads/mpdecimal-$(MPDECIMAL_VERSION)-$(target).tar.gz --exclude="*.dylib"
+ # Ensure the target is marked as clean.
+ touch $$(MPDECIMAL_LIB-$(target))
###########################################################################
# Target: OpenSSL
###########################################################################
-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_SRCDIR-$(target))/is_configured: downloads/openssl-$(OPENSSL_VERSION).tar.gz
- @echo ">>> Unpack and configure OpenSSL sources for $(target)"
- mkdir -p $$(OPENSSL_SRCDIR-$(target))
- tar zxf $$< --strip-components 1 -C $$(OPENSSL_SRCDIR-$(target))
-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
-endif
+downloads/openssl-$(OPENSSL_VERSION)-$(target).tar.gz:
+ @echo ">>> Download OpenSSL for $(target)"
+ mkdir -p downloads
+ curl $(CURL_FLAGS) -o $$@ \
+ https://github.com/beeware/cpython-apple-source-deps/releases/download/OpenSSL-$(OPENSSL_VERSION)/openssl-$(OPENSSL_VERSION)-$(target).tar.gz
- # Configure the OpenSSL build
-ifeq ($(os),macOS)
- cd $$(OPENSSL_SRCDIR-$(target)) && \
- CC="$$(CC-$(target)) $$(CFLAGS-$(target))" \
- ./Configure darwin64-$$(ARCH-$(target))-cc no-tests \
- --prefix="$$(OPENSSL_INSTALL-$(target))" \
- --openssldir=/etc/ssl \
- 2>&1 | tee -a ../openssl-$(OPENSSL_VERSION).config.log
-else
- 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="$$(OPENSSL_INSTALL-$(target))" \
- --openssldir=/etc/ssl \
- 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_SRCDIR-$(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_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-$(OPENSSL_VERSION).build.log
-
-$$(OPENSSL_SSL_LIB-$(target)): $$(OPENSSL_SRCDIR-$(target))/libssl.a
+$$(OPENSSL_SSL_LIB-$(target)): downloads/openssl-$(OPENSSL_VERSION)-$(target).tar.gz
@echo ">>> Install OpenSSL for $(target)"
- # Install just the software (not the docs)
- 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-$(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
+ mkdir -p $$(OPENSSL_INSTALL-$(target))
+ cd $$(OPENSSL_INSTALL-$(target)) && tar zxvf $(PROJECT_DIR)/downloads/openssl-$(OPENSSL_VERSION)-$(target).tar.gz --exclude="*.dylib"
+ # Ensure the target is marked as clean.
+ touch $$(OPENSSL_SSL_LIB-$(target))
###########################################################################
# Target: libFFI
@@ -470,50 +262,21 @@ $$(OPENSSL_WHEEL-$(target)): $$(OPENSSL_LIB-$(target)) $$(BDIST_WHEEL)
# The configure step is performed as part of the OS-level build.
ifneq ($(os),macOS)
-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_SRCDIR-$(os))/darwin_common/include/ffi.h
- @echo ">>> Build libFFI for $(target)"
- cd $$(LIBFFI_SRCDIR-$(target)) && \
- make \
- 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
+LIBFFI_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/libffi-$(LIBFFI_VERSION)
+LIBFFI_LIB-$(target)=$$(LIBFFI_INSTALL-$(target))/lib/libffi.a
+
+downloads/libffi-$(LIBFFI_VERSION)-$(target).tar.gz:
+ @echo ">>> Download libFFI for $(target)"
+ mkdir -p downloads
+ curl $(CURL_FLAGS) -o $$@ \
+ https://github.com/beeware/cpython-apple-source-deps/releases/download/libFFI-$(LIBFFI_VERSION)/libffi-$(LIBFFI_VERSION)-$(target).tar.gz
+
+$$(LIBFFI_LIB-$(target)): downloads/libffi-$(LIBFFI_VERSION)-$(target).tar.gz
+ @echo ">>> Install libFFI for $(target)"
+ mkdir -p $$(LIBFFI_INSTALL-$(target))
+ cd $$(LIBFFI_INSTALL-$(target)) && tar zxvf $(PROJECT_DIR)/downloads/libffi-$(LIBFFI_VERSION)-$(target).tar.gz --exclude="*.dylib"
+ # Ensure the target is marked as clean.
+ touch $$(LIBFFI_LIB-$(target))
endif
@@ -523,67 +286,110 @@ endif
# 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.
+# `build-target` macro. However, the site-customize scripts generated here, per target.
ifneq ($(os),macOS)
PYTHON_SRCDIR-$(target)=build/$(os)/$(target)/python-$(PYTHON_VERSION)
PYTHON_INSTALL-$(target)=$(PROJECT_DIR)/install/$(os)/$(target)/python-$(PYTHON_VERSION)
-PYTHON_LIB-$(target)=$$(PYTHON_INSTALL-$(target))/lib/libpython$(PYTHON_VER).a
+PYTHON_FRAMEWORK-$(target)=$$(PYTHON_INSTALL-$(target))/Python.framework
+PYTHON_LIB-$(target)=$$(PYTHON_FRAMEWORK-$(target))/Python
+PYTHON_BIN-$(target)=$$(PYTHON_INSTALL-$(target))/bin
+PYTHON_INCLUDE-$(target)=$$(PYTHON_FRAMEWORK-$(target))/Headers
+PYTHON_STDLIB-$(target)=$$(PYTHON_INSTALL-$(target))/lib/python$(PYTHON_VER)
+PYTHON_PLATFORM_CONFIG-$(target)=$$(PYTHON_INSTALL-$(target))/platform-config/$$(ARCH-$(target))-$$(SDK-$(target))
+PYTHON_PLATFORM_SITECUSTOMIZE-$(target)=$$(PYTHON_PLATFORM_CONFIG-$(target))/sitecustomize.py
-$$(PYTHON_SRCDIR-$(target))/Makefile: \
+
+$$(PYTHON_SRCDIR-$(target))/configure: \
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)
+ $$(BZIP2_LIB-$(target)) \
+ $$(LIBFFI_LIB-$(target)) \
+ $$(MPDECIMAL_LIB-$(target)) \
+ $$(OPENSSL_SSL_LIB-$(target)) \
+ $$(XZ_LIB-$(target)) \
+ $$(ZSTD_LIB-$(target))
@echo ">>> Unpack and configure Python for $(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_SRCDIR-$(target)) && patch -p1 < $(PROJECT_DIR)/patch/Python/Python.patch
+ # Make sure the binary scripts are executable
+ chmod 755 $$(PYTHON_SRCDIR-$(target))/Apple/$(os)/Resources/bin/*
+ # Touch the configure script to ensure that Make identifies it as up to date.
+ touch $$(PYTHON_SRCDIR-$(target))/configure
+
+$$(PYTHON_SRCDIR-$(target))/Makefile: \
+ $$(PYTHON_SRCDIR-$(target))/configure
# Configure target Python
cd $$(PYTHON_SRCDIR-$(target)) && \
+ PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/Apple/$(os)/Resources/bin:$(PATH)" \
./configure \
- AR="$$(AR-$(target))" \
- CC="$$(CC-$(target))" \
- CPP="$$(CPP-$(target))" \
- CXX="$$(CXX-$(target))" \
- CFLAGS="$$(CFLAGS-$(target))" \
- LDFLAGS="$$(LDFLAGS-$(target))" \
- LIBLZMA_CFLAGS="-I$$(XZ_MERGE-$$(SDK-$(target)))/include" \
- LIBLZMA_LIBS="-L$$(XZ_MERGE-$$(SDK-$(target)))/lib -llzma" \
- BZIP2_CFLAGS="-I$$(BZIP2_MERGE-$$(SDK-$(target)))/include" \
- BZIP2_LIBS="-L$$(BZIP2_MERGE-$$(SDK-$(target)))/lib -lbz2" \
- LIBFFI_INCLUDEDIR="$$(LIBFFI_MERGE-$$(SDK-$(target)))/include" \
- LIBFFI_LIBDIR="$$(LIBFFI_MERGE-$$(SDK-$(target)))/lib" \
- LIBFFI_LIB="ffi" \
+ LIBLZMA_CFLAGS="-I$$(XZ_INSTALL-$(target))/include" \
+ LIBLZMA_LIBS="-L$$(XZ_INSTALL-$(target))/lib -llzma" \
+ BZIP2_CFLAGS="-I$$(BZIP2_INSTALL-$(target))/include" \
+ BZIP2_LIBS="-L$$(BZIP2_INSTALL-$(target))/lib -lbz2" \
+ LIBMPDEC_CFLAGS="-I$$(MPDECIMAL_INSTALL-$(target))/include" \
+ LIBMPDEC_LIBS="-L$$(MPDECIMAL_INSTALL-$(target))/lib -lmpdec" \
+ LIBFFI_CFLAGS="-I$$(LIBFFI_INSTALL-$(target))/include" \
+ LIBFFI_LIBS="-L$$(LIBFFI_INSTALL-$(target))/lib -lffi" \
+ LIBZSTD_CFLAGS="-I$$(ZSTD_INSTALL-$(target))/include" \
+ LIBZSTD_LIBS="-L$$(ZSTD_INSTALL-$(target))/lib -lzstd" \
--host=$$(TARGET_TRIPLE-$(target)) \
--build=$(HOST_ARCH)-apple-darwin \
- --with-build-python=$$(PYTHON_INSTALL-macosx)/bin/python$(PYTHON_VER) \
- --prefix="$$(PYTHON_INSTALL-$(target))" \
+ --with-build-python=$(HOST_PYTHON) \
--enable-ipv6 \
- --with-openssl="$$(OPENSSL_MERGE-$$(SDK-$(target)))" \
- --without-ensurepip \
- ac_cv_file__dev_ptmx=no \
- ac_cv_file__dev_ptc=no \
- $$(PYTHON_CONFIGURE-$(os)) \
+ --with-openssl="$$(OPENSSL_INSTALL-$(target))" \
+ --enable-framework="$$(PYTHON_INSTALL-$(target))" \
+ --with-system-libmpdec \
2>&1 | tee -a ../python-$(PYTHON_VERSION).config.log
$$(PYTHON_SRCDIR-$(target))/python.exe: $$(PYTHON_SRCDIR-$(target))/Makefile
@echo ">>> Build Python for $(target)"
cd $$(PYTHON_SRCDIR-$(target)) && \
- make all \
- 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log
+ PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/Apple/$(os)/Resources/bin:$(PATH)" \
+ make -j8 all \
+ 2>&1 | tee -a ../python-$(PYTHON_VERSION).build.log
$$(PYTHON_LIB-$(target)): $$(PYTHON_SRCDIR-$(target))/python.exe
@echo ">>> Install Python for $(target)"
cd $$(PYTHON_SRCDIR-$(target)) && \
- make install \
- 2>&1 | tee -a ../python-$(PYTHON_VERSION).install.log
+ PATH="$(PROJECT_DIR)/$$(PYTHON_SRCDIR-$(target))/Apple/$(os)/Resources/bin:$(PATH)" \
+ make install \
+ 2>&1 | tee -a ../python-$(PYTHON_VERSION).install.log
+
+ # Remove any .orig files produced by the compliance patching process
+ find $$(PYTHON_INSTALL-$(target)) -name "*.orig" -exec rm {} \;
+
+
+$$(PYTHON_PLATFORM_SITECUSTOMIZE-$(target)):
+ @echo ">>> Create cross-platform config for $(target)"
+ mkdir -p $$(PYTHON_PLATFORM_CONFIG-$(target))
+ # Create the cross-platform site definition
+ echo "import _cross_$$(ARCH-$(target))_$$(SDK-$(target)); import _cross_venv;" \
+ > $$(PYTHON_PLATFORM_CONFIG-$(target))/_cross_venv.pth
+ cp $(PROJECT_DIR)/patch/Python/make_cross_venv.py \
+ $$(PYTHON_PLATFORM_CONFIG-$(target))/make_cross_venv.py
+ cp $(PROJECT_DIR)/patch/Python/_cross_venv.py \
+ $$(PYTHON_PLATFORM_CONFIG-$(target))/_cross_venv.py
+ cp $$(PYTHON_STDLIB-$(target))/_sysconfig* \
+ $$(PYTHON_PLATFORM_CONFIG-$(target))
+ cat $(PROJECT_DIR)/patch/Python/_cross_target.py.tmpl \
+ | sed -e "s/{{os}}/$(os)/g" \
+ | sed -e "s/{{platform}}/$$(OS_LOWER-$(target))/g" \
+ | sed -e "s/{{arch}}/$$(ARCH-$(target))/g" \
+ | sed -e "s/{{sdk}}/$$(SDK-$(target))/g" \
+ | sed -e "s/{{version_min}}/$$(VERSION_MIN-$(os))/g" \
+ | sed -e "s/{{is_simulator}}/$$(IS_SIMULATOR-$(target))/g" \
+ > $$(PYTHON_PLATFORM_CONFIG-$(target))/_cross_$$(ARCH-$(target))_$$(SDK-$(target)).py
+ cat $(PROJECT_DIR)/patch/Python/sitecustomize.py.tmpl \
+ | sed -e "s/{{arch}}/$$(ARCH-$(target))/g" \
+ | sed -e "s/{{sdk}}/$$(SDK-$(target))/g" \
+ > $$(PYTHON_PLATFORM_SITECUSTOMIZE-$(target))
endif
+$(target): $$(PYTHON_PLATFORM_SITECUSTOMIZE-$(target)) $$(PYTHON_LIB-$(target))
+
###########################################################################
# Target: Debug
###########################################################################
@@ -594,33 +400,25 @@ vars-$(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 "CPP-$(target): $$(CPP-$(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 "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 "XZ_WHEEL-$(target): $$(XZ_WHEEL-$(target))"
- @echo "XZ_WHEEL_DISTINFO-$(target): $$(XZ_WHEEL_DISTINFO-$(target))"
- @echo "OPENSSL_SRCDIR-$(target): $$(OPENSSL_SRCDIR-$(target))"
+ @echo "LIBFFI_INSTALL-$(target): $$(LIBFFI_INSTALL-$(target))"
+ @echo "LIBFFI_LIB-$(target): $$(LIBFFI_LIB-$(target))"
+ @echo "MPDECIMAL_INSTALL-$(target): $$(MPDECIMAL_INSTALL-$(target))"
+ @echo "MPDECIMAL_LIB-$(target): $$(MPDECIMAL_LIB-$(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 "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 "LIBFFI_WHEEL-$(target): $$(LIBFFI_WHEEL-$(target))"
- @echo "LIBFFI_WHEEL_DISTINFO-$(target): $$(LIBFFI_WHEEL_DISTINFO-$(target))"
+ @echo "XZ_INSTALL-$(target): $$(XZ_INSTALL-$(target))"
+ @echo "XZ_LIB-$(target): $$(XZ_LIB-$(target))"
@echo "PYTHON_SRCDIR-$(target): $$(PYTHON_SRCDIR-$(target))"
@echo "PYTHON_INSTALL-$(target): $$(PYTHON_INSTALL-$(target))"
+ @echo "PYTHON_FRAMEWORK-$(target): $$(PYTHON_FRAMEWORK-$(target))"
@echo "PYTHON_LIB-$(target): $$(PYTHON_LIB-$(target))"
+ @echo "PYTHON_BIN-$(target): $$(PYTHON_BIN-$(target))"
+ @echo "PYTHON_INCLUDE-$(target): $$(PYTHON_INCLUDE-$(target))"
+ @echo "PYTHON_STDLIB-$(target): $$(PYTHON_STDLIB-$(target))"
+ @echo "PYTHON_PLATFORM_CONFIG-$(target): $$(PYTHON_PLATFORM_CONFIG-$(target))"
+ @echo "PYTHON_PLATFORM_SITECUSTOMIZE-$(target): $$(PYTHON_PLATFORM_SITECUSTOMIZE-$(target))"
@echo
endef # build-target
@@ -638,227 +436,118 @@ 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")
+SDK_SLICE-$(sdk)=$$(TRIPLE_OS-$(os))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g")
else
-SDK_SLICE-$(sdk)=$$(OS_LOWER-$(sdk))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g")-simulator
+SDK_SLICE-$(sdk)=$$(TRIPLE_OS-$(os))-$$(shell echo $$(SDK_ARCHES-$(sdk)) | sed "s/ /_/g")-simulator
endif
-CC-$(sdk)=xcrun --sdk $(sdk) clang
-CPP-$(sdk)=xcrun --sdk $(sdk) clang -E
-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)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(BZIP2_LIB-$$(target)))
- @echo ">>> Build BZip2 fat library for $(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)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(XZ_LIB-$$(target)))
- @echo ">>> Build XZ fat library for $(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_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)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(LIBFFI_LIB-$$(target)))
- @echo ">>> Build libFFI fat library for $(sdk)"
- 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
###########################################################################
-# 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)
+# macOS builds are extracted from the official installer package, then
+# reprocessed into an XCFramework.
-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))" \
- CPP="$$(CPP-$(sdk))" \
- CFLAGS="$$(CFLAGS-$(sdk))" \
- LDFLAGS="$$(LDFLAGS-$(sdk))" \
- LIBLZMA_CFLAGS="-I$$(XZ_MERGE-$(sdk))/include" \
- LIBLZMA_LIBS="-L$$(XZ_MERGE-$(sdk))/lib -llzma" \
- BZIP2_CFLAGS="-I$$(BZIP2_MERGE-$(sdk))/include" \
- BZIP2_LIBS="-L$$(BZIP2_MERGE-$(sdk))/lib -lbz2" \
- --prefix="$$(PYTHON_INSTALL-$(sdk))" \
- --enable-ipv6 \
- --enable-universalsdk \
- --with-openssl="$$(OPENSSL_MERGE-$(sdk))" \
- --with-universal-archs=universal2 \
- --without-ensurepip \
- 2>&1 | tee -a ../python-$(PYTHON_VERSION).config.log
-
-$$(PYTHON_SRCDIR-$(sdk))/python.exe: \
- $$(PYTHON_SRCDIR-$(sdk))/Makefile
- @echo ">>> Build Python for $(sdk)"
- cd $$(PYTHON_SRCDIR-$(sdk)) && \
- 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)"
- # 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))
+PYTHON_FRAMEWORK-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/Python.framework
+PYTHON_INSTALL_VERSION-$(sdk)=$$(PYTHON_FRAMEWORK-$(sdk))/Versions/$(PYTHON_VER)
+PYTHON_LIB-$(sdk)=$$(PYTHON_INSTALL_VERSION-$(sdk))/Python
+PYTHON_INCLUDE-$(sdk)=$$(PYTHON_INSTALL_VERSION-$(sdk))/include/python$(PYTHON_VER)
+PYTHON_MODULEMAP-$(sdk)=$$(PYTHON_INCLUDE-$(sdk))/module.modulemap
else
-
# Non-macOS builds need to be merged on a per-SDK basis. The merge covers:
-# * Merging a fat libPython.a
+# * Merging a fat libPython
# * Installing an architecture-sensitive pyconfig.h
# * Merging fat versions of the standard library lib-dynload folder
+# The non-macOS frameworks don't use the versioning structure.
-$$(PYTHON_FATLIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_LIB-$$(target)))
+PYTHON_INSTALL-$(sdk)=$(PROJECT_DIR)/install/$(os)/$(sdk)/python-$(PYTHON_VERSION)
+PYTHON_MODULEMAP-$(sdk)=$$(PYTHON_INCLUDE-$(sdk))/module.modulemap
+PYTHON_FRAMEWORK-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/Python.framework
+PYTHON_LIB-$(sdk)=$$(PYTHON_FRAMEWORK-$(sdk))/Python
+PYTHON_BIN-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/bin
+PYTHON_INCLUDE-$(sdk)=$$(PYTHON_FRAMEWORK-$(sdk))/Headers
+PYTHON_PLATFORM_CONFIG-$(sdk)=$$(PYTHON_INSTALL-$(sdk))/platform-config
+
+$$(PYTHON_LIB-$(sdk)): $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_LIB-$$(target)))
@echo ">>> Build Python fat library for the $(sdk) SDK"
- mkdir -p $$(dir $$(PYTHON_FATLIB-$(sdk)))
+ mkdir -p $$(dir $$(PYTHON_LIB-$(sdk)))
lipo -create -output $$@ $$^ \
- 2>&1 | tee -a merge/$(os)/$(sdk)/python-$(PYTHON_VERSION).lipo.log
+ 2>&1 | tee -a install/$(os)/$(sdk)/python-$(PYTHON_VERSION).lipo.log
+ # Disable dSYM production (for now)
+ # dsymutil $$@ -o $$(PYTHON_INSTALL-$(sdk))/Python.dSYM
-$$(PYTHON_FATINCLUDE-$(sdk)): $$(PYTHON_LIB-$(sdk))
+$$(PYTHON_FRAMEWORK-$(sdk))/Info.plist: $$(PYTHON_LIB-$(sdk))
+ @echo ">>> Install Info.plist for the $(sdk) SDK"
+ # Copy Info.plist as-is from the first target in the $(sdk) SDK
+ cp -r $$(PYTHON_FRAMEWORK-$$(firstword $$(SDK_TARGETS-$(sdk))))/Info.plist $$(PYTHON_FRAMEWORK-$(sdk))
+
+$$(PYTHON_INCLUDE-$(sdk))/pyconfig.h: $$(PYTHON_LIB-$(sdk))
@echo ">>> Build Python fat headers for the $(sdk) SDK"
+ # Copy binary helpers from the first target in the $(sdk) SDK
+ cp -r $$(PYTHON_BIN-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_BIN-$(sdk))
+
+ # Create a non-executable stub binary python3
+ echo "#!/bin/bash\necho Can\\'t run $(sdk) binary\nexit 1" > $$(PYTHON_BIN-$(sdk))/python$(PYTHON_VER)
+ chmod 755 $$(PYTHON_BIN-$(sdk))/python$(PYTHON_VER)
+
# Copy headers as-is from the first target in the $(sdk) SDK
- cp -r $$(PYTHON_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
+ cp -r $$(PYTHON_INCLUDE-$$(firstword $$(SDK_TARGETS-$(sdk)))) $$(PYTHON_INCLUDE-$(sdk))
+
+ # Create the modulemap file
+ cp -r patch/Python/module.modulemap.prefix $$(PYTHON_MODULEMAP-$(sdk))
+ echo "" >> $$(PYTHON_MODULEMAP-$(sdk))
+ cd $$(PYTHON_SRCDIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/Include && \
+ find cpython -name "*.h" | sort | sed -e 's/^/ exclude header "/' | sed 's/$$$$/"/' >> $$(PYTHON_MODULEMAP-$(sdk)) && \
+ echo "" >> $$(PYTHON_MODULEMAP-$(sdk)) && \
+ find internal -name "*.h" | sort | sed -e 's/^/ exclude header "/' | sed 's/$$$$/"/' >> $$(PYTHON_MODULEMAP-$(sdk))
+ echo "\n}" >> $$(PYTHON_MODULEMAP-$(sdk))
+
+ # Link the PYTHONHOME version of the headers
+ mkdir -p $$(PYTHON_INSTALL-$(sdk))/include
+ ln -si ../Python.framework/Headers $$(PYTHON_INSTALL-$(sdk))/include/python$(PYTHON_VER)
+
# Add the individual headers from each target in an arch-specific name
- $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_INSTALL-$$(target))/include/python$(PYTHON_VER)/pyconfig.h $$(PYTHON_FATINCLUDE-$(sdk))/pyconfig-$$(ARCH-$$(target)).h; )
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_INCLUDE-$$(target))/pyconfig.h $$(PYTHON_INCLUDE-$(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))
+ # Copy the cross-target header from the source folder of the first target in the $(sdk) SDK
+ cp $$(PYTHON_SRCDIR-$$(firstword $$(SDK_TARGETS-$(sdk))))/Apple/$(os)/Resources/pyconfig.h $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h
- # 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))
+$$(PYTHON_PLATFORM_CONFIG-$(sdk))/sitecustomize.py: $$(PYTHON_LIB-$(sdk)) $$(PYTHON_FRAMEWORK-$(sdk))/Info.plist $$(PYTHON_INCLUDE-$(sdk))/pyconfig.h $$(foreach target,$$(SDK_TARGETS-$(sdk)),$$(PYTHON_PLATFORM_SITECUSTOMIZE-$$(target)))
+ @echo ">>> Build Python stdlib for the $(sdk) SDK"
+ mkdir -p $$(PYTHON_INSTALL-$(sdk))/lib
- # 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; )
+ # Create arch-specific stdlib directories
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),mkdir -p $$(PYTHON_INSTALL-$(sdk))/lib-$$(ARCH-$$(target))/python$(PYTHON_VER); )
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_STDLIB-$$(target))/_sysconfigdata_* $$(PYTHON_INSTALL-$(sdk))/lib-$$(ARCH-$$(target))/python$(PYTHON_VER)/; )
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_STDLIB-$$(target))/_sysconfig_vars_* $$(PYTHON_INSTALL-$(sdk))/lib-$$(ARCH-$$(target))/python$(PYTHON_VER)/; )
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $$(PYTHON_STDLIB-$$(target))/build-details.json $$(PYTHON_INSTALL-$(sdk))/lib-$$(ARCH-$$(target))/python$(PYTHON_VER)/; )
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp -r $$(PYTHON_STDLIB-$$(target))/lib-dynload $$(PYTHON_INSTALL-$(sdk))/lib-$$(ARCH-$$(target))/python$(PYTHON_VER)/; )
- # 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); )
+ # Copy in known-required xcprivacy files.
+ # Libraries linking OpenSSL must provide a privacy manifest. The one in this repository
+ # has been sourced from https://github.com/openssl/openssl/blob/openssl-3.0/os-dep/Apple/PrivacyInfo.xcprivacy
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $(PROJECT_DIR)/patch/Python/OpenSSL.xcprivacy $$(PYTHON_STDLIB-$$(target))/lib-dynload/_hashlib.xcprivacy; )
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp $(PROJECT_DIR)/patch/Python/OpenSSL.xcprivacy $$(PYTHON_STDLIB-$$(target))/lib-dynload/_ssl.xcprivacy; )
- # 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))); )
+ # Copy the platform site folders for each architecture
+ mkdir -p $$(PYTHON_PLATFORM_CONFIG-$(sdk))
+ $$(foreach target,$$(SDK_TARGETS-$(sdk)),cp -r $$(PYTHON_PLATFORM_CONFIG-$$(target)) $$(PYTHON_PLATFORM_CONFIG-$(sdk)); )
endif
+$(sdk): $$(PYTHON_PLATFORM_CONFIG-$(sdk))/sitecustomize.py
###########################################################################
# SDK: Debug
@@ -869,27 +558,13 @@ vars-$(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 "CPP-$(sdk): $$(CPP-$(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_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_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_FRAMEWORK-$(sdk): $$(PYTHON_FRAMEWORK-$(sdk))"
@echo "PYTHON_LIB-$(sdk): $$(PYTHON_LIB-$(sdk))"
+ @echo "PYTHON_BIN-$(sdk): $$(PYTHON_BIN-$(sdk))"
+ @echo "PYTHON_INCLUDE-$(sdk): $$(PYTHON_INCLUDE-$(sdk))"
+ @echo "PYTHON_PLATFORM_CONFIG-$(sdk): $$(PYTHON_PLATFORM_CONFIG-$(sdk))"
@echo
endef # build-sdk
@@ -911,220 +586,172 @@ os=$1
SDKS-$(os)=$$(sort $$(basename $$(TARGETS-$(os))))
-# Predeclare the Python XCFramework files so they can be referenced in SDK targets
-PYTHON_XCFRAMEWORK-$(os)=support/$(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)
$$(foreach sdk,$$(SDKS-$(os)),$$(eval $$(call build-sdk,$$(sdk),$(os))))
###########################################################################
-# Build: BZip2
-###########################################################################
-
-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-$(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-$(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-$(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-$(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-$(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
+# Build: Python
###########################################################################
-# macOS uses the system-provided libFFI, so there's no need to package
-# a libFFI framework for macOS.
-ifneq ($(os),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_SRCDIR-$(os))
- tar zxf $$< --strip-components 1 -C $$(LIBFFI_SRCDIR-$(os))
- # Patch the build to add support for new platforms
- cd $$(LIBFFI_SRCDIR-$(os)) && patch -p1 < $(PROJECT_DIR)/patch/libffi-$(LIBFFI_VERSION).patch
- # Configure the build
- 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): $$(foreach sdk,$$(SDKS-$(os)),$$(LIBFFI_FATLIB-$$(sdk)))
-libFFI-wheels-$(os): $$(foreach target,$$(TARGETS-$(os)),$$(LIBFFI_WHEEL-$$(target)))
+PYTHON_XCFRAMEWORK-$(os)=support/$(PYTHON_VER)/$(os)/Python.xcframework
-clean-libFFI-$(os):
- @echo ">>> Clean libFFI build products on $(os)"
- 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
+ifeq ($(os),macOS)
-clean-libFFI-wheels-$(os):
- rm -rf \
- build/$(os)/libffi-$(LIBFFI_VERSION)/build_*/wheel \
- wheels/dist/libffi
+PYTHON_FRAMEWORK-$(os)=$$(PYTHON_INSTALL-$(sdk))/Python.framework
+
+$$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \
+ downloads/python-$(PYTHON_PKG_VERSION)-macos11.pkg
+ @echo ">>> Repackage macOS package as XCFramework"
+
+ # Unpack .pkg file. It turns out .pkg files are readable by tar... although
+ # their internal format is a bit of a mess. From tar's perspective, the .pkg
+ # is a tarball that contains additional tarballs; the inner tarball has the
+ # "payload" that is the framework.
+ mkdir -p build/macOS/macosx/python-$(PYTHON_VERSION)
+ tar zxf downloads/python-$(PYTHON_PKG_VERSION)-macos11.pkg -C build/macOS/macosx/python-$(PYTHON_VERSION)
+
+ # Unpack payload inside .pkg file
+ mkdir -p $$(PYTHON_FRAMEWORK-macosx)
+ tar zxf build/macOS/macosx/python-$(PYTHON_VERSION)/Python_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/PayloadPython_Framework.pkgPython_Framework.pkg/Payload -C $$(PYTHON_FRAMEWORK-macosx) -X patch/Python/release.macOS.exclude
+
+ # Apply the App Store compliance patch
+ patch --strip 2 --directory $$(PYTHON_INSTALL_VERSION-macosx)/lib/python$(PYTHON_VER) --input $(PROJECT_DIR)/patch/Python/app-store-compliance.patch
+
+ # Remove any .orig files produced by the patching process
+ find $$(PYTHON_INSTALL_VERSION-macosx) -name "*.orig" -exec rm {} \;
+
+ # Rewrite the framework to make it standalone
+ patch/make-relocatable.sh $$(PYTHON_INSTALL_VERSION-macosx) 2>&1 > /dev/null
+
+ # Create the modulemap file
+ cp -r patch/Python/module.modulemap.prefix $$(PYTHON_MODULEMAP-macosx)
+ echo "" >> $$(PYTHON_MODULEMAP-macosx)
+ cd $$(PYTHON_INCLUDE-macosx) && \
+ find cpython -name "*.h" | sort | sed -e 's/^/ exclude header "/' | sed 's/$$$$/"/' >> $$(PYTHON_MODULEMAP-macosx) && \
+ echo "" >> $$(PYTHON_MODULEMAP-macosx) && \
+ find internal -name "*.h" | sort | sed -e 's/^/ exclude header "/' | sed 's/$$$$/"/' >> $$(PYTHON_MODULEMAP-macosx)
+ echo "\n}" >> $$(PYTHON_MODULEMAP-macosx)
+
+ # Re-apply the signature on the binaries.
+ codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f $$(PYTHON_LIB-macosx) \
+ 2>&1 | tee $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log
+ find $$(PYTHON_FRAMEWORK-macosx) -name "*.dylib" -type f -exec codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \; \
+ 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log
+ find $$(PYTHON_FRAMEWORK-macosx) -name "*.so" -type f -exec codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f {} \; \
+ 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log
+ codesign -s - --preserve-metadata=identifier,entitlements,flags,runtime -f $$(PYTHON_FRAMEWORK-macosx) \
+ 2>&1 | tee -a $$(PYTHON_INSTALL-macosx)/python-$(os).codesign.log
+
+ # Create XCFramework out of the extracted framework
+ xcodebuild -create-xcframework -output $$(PYTHON_XCFRAMEWORK-$(os)) -framework $$(PYTHON_FRAMEWORK-macosx) \
+ 2>&1 | tee $$(PYTHON_INSTALL-macosx)/python-$(os).xcframework.log
+
+support/$(PYTHON_VER)/macOS/VERSIONS:
+ @echo ">>> Create VERSIONS file for macOS"
+ echo "Python version: $(PYTHON_VERSION) " > support/$(PYTHON_VER)/macOS/VERSIONS
+ echo "Build: $(BUILD_NUMBER)" >> support/$(PYTHON_VER)/macOS/VERSIONS
+ echo "Min macOS version: $$(VERSION_MIN-macOS)" >> support/$(PYTHON_VER)/macOS/VERSIONS
+
+dist/Python-$(PYTHON_VER)-macOS-support.$(BUILD_NUMBER).tar.gz: \
+ $$(PYTHON_XCFRAMEWORK-macOS)/Info.plist \
+ support/$(PYTHON_VER)/macOS/VERSIONS \
+ $$(foreach target,$$(TARGETS-macOS), $$(PYTHON_PLATFORM_SITECUSTOMIZE-$$(target)))
+
+ @echo ">>> Create final distribution artefact for macOS"
+ mkdir -p dist
+ # Strip xattrs from the support files
+ xattr -cr support/$(PYTHON_VER)/macOS
+ # Build a distributable tarball
+ tar zcvf $$@ -C support/$(PYTHON_VER)/macOS `ls -A support/$(PYTHON_VER)/macOS/`
-###########################################################################
-# Build: Python
-###########################################################################
+else
-$$(PYTHON_XCFRAMEWORK-$(os)): \
- $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_FATLIB-$$(sdk)) $$(PYTHON_FATINCLUDE-$$(sdk)))
+$$(PYTHON_XCFRAMEWORK-$(os))/Info.plist: \
+ $$(foreach sdk,$$(SDKS-$(os)),$$(PYTHON_PLATFORM_CONFIG-$$(sdk))/sitecustomize.py)
@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
+ -output $$(PYTHON_XCFRAMEWORK-$(os)) $$(foreach sdk,$$(SDKS-$(os)),-framework $$(PYTHON_FRAMEWORK-$$(sdk))) \
+ 2>&1 | tee -a support/$(PYTHON_VER)/python-$(os).xcframework.log
-$$(PYTHON_STDLIB-$(os)): \
- $$(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))
+ @echo ">>> Install build tools for $(os)"
+ mkdir $$(PYTHON_XCFRAMEWORK-$(os))/build
+ cp $$(PYTHON_SRCDIR-$$(firstword $$(SDK_TARGETS-$$(firstword $$(SDKS-$(os))))))/Apple/testbed/Python.xcframework/build/utils.sh $$(PYTHON_XCFRAMEWORK-$(os))/build
+ cp $$(PYTHON_SRCDIR-$$(firstword $$(SDK_TARGETS-$$(firstword $$(SDKS-$(os))))))/Apple/testbed/Python.xcframework/build/$$(PLATFORM_NAME-$(os))-dylib-Info-template.plist $$(PYTHON_XCFRAMEWORK-$(os))/build
- # Delete the single-SDK stdlib artefacts from $(os)
- rm -rf \
- $$(PYTHON_STDLIB-$(os))/_sysconfigdata__*.py \
- $$(PYTHON_STDLIB-$(os))/config-* \
- $$(PYTHON_STDLIB-$(os))/lib-dynload/*
-
- # Copy the config-* contents from every SDK in $(os) into the support folder.
- $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_FATSTDLIB-$$(sdk))/config-$(PYTHON_VER)-* $$(PYTHON_STDLIB-$(os)); )
-
- # Copy the _sysconfigdata modules from every SDK in $(os) into the support folder.
- $$(foreach sdk,$$(SDKS-$(os)),cp $$(PYTHON_FATSTDLIB-$$(sdk))/_sysconfigdata__*.py $$(PYTHON_STDLIB-$(os)); )
+ @echo ">>> Install stdlib for $(os)"
+ mkdir -p $$(PYTHON_XCFRAMEWORK-$(os))/lib
+ cp -r $$(PYTHON_STDLIB-$$(firstword $$(SDK_TARGETS-$$(firstword $$(SDKS-$(os))))))/ $$(PYTHON_XCFRAMEWORK-$(os))/lib/python$(PYTHON_VER)
- # 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; )
-
-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
+ # Delete the single-SDK parts of the standard library
+ rm -rf \
+ $$(PYTHON_XCFRAMEWORK-$(os))/lib/python$(PYTHON_VER)/_sysconfigdata__*.py \
+ $$(PYTHON_XCFRAMEWORK-$(os))/lib/python$(PYTHON_VER)/_sysconfig_vars__*.json \
+ $$(PYTHON_XCFRAMEWORK-$(os))/lib/python$(PYTHON_VER)/build-details.json \
+ $$(PYTHON_XCFRAMEWORK-$(os))/lib/python$(PYTHON_VER)/config-* \
+ $$(PYTHON_XCFRAMEWORK-$(os))/lib/python$(PYTHON_VER)/lib-dynload
+
+ @echo ">>> Install PYTHONHOME for $(os)"
+ $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_INSTALL-$$(sdk))/include $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk)); )
+ $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_INSTALL-$$(sdk))/bin $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk)); )
+ $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_INSTALL-$$(sdk))/lib* $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk)); )
+ $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_INSTALL-$$(sdk))/platform-config $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk)); )
+
+ # Create symlink for dylib
+ $$(foreach sdk,$$(SDKS-$(os)),ln -si ../Python.framework/Python $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk))/lib/libpython$(PYTHON_VER).dylib; )
+
+ # Disable dSYM production (for now)
+ # $$(foreach sdk,$$(SDKS-$(os)),cp -r $$(PYTHON_INSTALL-$$(sdk))/Python.dSYM $$(PYTHON_XCFRAMEWORK-$(os))/$$(SDK_SLICE-$$(sdk)); )
+
+ifeq ($(filter $(os),iOS tvOS visionOS),$(os))
+ @echo ">>> Clone testbed project for $(os)"
+ $(HOST_PYTHON) $$(PYTHON_SRCDIR-$$(firstword $$(SDK_TARGETS-$$(firstword $$(SDKS-$(os))))))/Apple/testbed clone --platform $(os) --framework $$(PYTHON_XCFRAMEWORK-$(os)) support/$(PYTHON_VER)/$(os)/testbed
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
+ @echo ">>> Create VERSIONS file for $(os)"
+ echo "Python version: $(PYTHON_VERSION) " > support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "Build: $(BUILD_NUMBER)" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "Min $(os) version: $$(VERSION_MIN-$(os))" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "---------------------" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "BZip2: $(BZIP2_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "libFFI: $(LIBFFI_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "mpdecimal: $(MPDECIMAL_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "OpenSSL: $(OPENSSL_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "XZ: $(XZ_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+ echo "Zstandard: $(ZSTD_VERSION)" >> support/$(PYTHON_VER)/$(os)/VERSIONS
+
+dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz: \
+ $$(PYTHON_XCFRAMEWORK-$(os))/Info.plist \
+ $$(foreach target,$$(TARGETS-$(os)), $$(PYTHON_PLATFORM_SITECUSTOMIZE-$$(target)))
@echo ">>> Create final distribution artefact for $(os)"
mkdir -p dist
- # Build a "full" tarball with all content for test purposes
- tar zcvf dist/Python-$(PYTHON_VER)-$(os)-support.test-$(BUILD_NUMBER).tar.gz -X patch/Python/test.exclude -C support/$(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)`
+ tar zcvf $$@ -X patch/Python/release.$(os).exclude -C support/$(PYTHON_VER)/$(os) `ls -A support/$(PYTHON_VER)/$(os)/`
-Python-$(os): dist/Python-$(PYTHON_VER)-$(os)-support.$(BUILD_NUMBER).tar.gz
+endif
-clean-Python-$(os):
+clean-$(os):
@echo ">>> Clean Python build products on $(os)"
rm -rf \
build/$(os)/*/python-$(PYTHON_VER)* \
build/$(os)/*/python-$(PYTHON_VER)*.*.log \
install/$(os)/*/python-$(PYTHON_VER)* \
install/$(os)/*/python-$(PYTHON_VER)*.*.log \
- merge/$(os)/*/python-$(PYTHON_VER)* \
- merge/$(os)/*/python-$(PYTHON_VER)*.*.log \
- support/$(os) \
- support/*-$(os).*.log \
+ support/$(PYTHON_VER)/$(os) \
+ support/$(PYTHON_VER)/python-$(os).*.log \
dist/Python-$(PYTHON_VER)-$(os)-*
-dev-clean-Python-$(os):
+dev-clean-$(os):
@echo ">>> Partially clean Python build products on $(os) so that local code modifications can be made"
rm -rf \
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 \
+ support/$(PYTHON_VER)/$(os) \
dist/Python-$(PYTHON_VER)-$(os)-*
###########################################################################
@@ -1132,18 +759,6 @@ merge-clean-Python-$(os):
###########################################################################
$(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
@@ -1152,49 +767,33 @@ clean-wheels-$(os): $(foreach dep,$(DEPENDENCIES),clean-$(dep)-wheels-$(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 "LIBFFI_SRCDIR-$(os): $$(LIBFFI_SRCDIR-$(os))"
@echo "LIBPYTHON_XCFRAMEWORK-$(os): $$(LIBPYTHON_XCFRAMEWORK-$(os))"
@echo "PYTHON_XCFRAMEWORK-$(os): $$(PYTHON_XCFRAMEWORK-$(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))
+ @echo ">>> Environment variables for $(os)"
+ @echo "HOST_ARCH: $(HOST_ARCH)"
+ @echo "HOST_PYTHON: $(HOST_PYTHON)"
+ @echo
+
+config:
+ @echo "PYTHON_VERSION=$(PYTHON_VERSION)"
+ @echo "PYTHON_VER=$(PYTHON_VER)"
+ @echo "BUILD_NUMBER=$(BUILD_NUMBER)"
+ @echo "BZIP2_VERSION=$(BZIP2_VERSION)"
+ @echo "LIBFFI_VERSION=$(LIBFFI_VERSION)"
+ @echo "MPDECIMAL_VERSION=$(MPDECIMAL_VERSION)"
+ @echo "OPENSSL_VERSION=$(OPENSSL_VERSION)"
+ @echo "XZ_VERSION=$(XZ_VERSION)"
+ @echo "ZSTD_VERSION=$(ZSTD_VERSION)"
# Expand cross-platform build and clean targets for each output product
-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))
+clean: $(foreach os,$(OS_LIST),clean-$(os))
+dev-clean: $(foreach os,$(OS_LIST),dev-clean-$(os))
# Expand the build macro for every OS
$(foreach os,$(OS_LIST),$(eval $(call build,$(os))))
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..3da329cc
--- /dev/null
+++ b/README.md
@@ -0,0 +1,169 @@
+# Python Apple Support
+
+This is a meta-package for building a version of Python that can be
+embedded into a macOS, iOS, tvOS, watchOS, or visionOS project.
+
+**This branch builds a packaged version of Python 3.14**. Other Python
+versions are available by cloning other branches of the main repository:
+
+- [Python
+ 3.10](https://github.com/beeware/Python-Apple-support/tree/3.10)
+- [Python
+ 3.11](https://github.com/beeware/Python-Apple-support/tree/3.11)
+- [Python
+ 3.12](https://github.com/beeware/Python-Apple-support/tree/3.12)
+- [Python
+ 3.13](https://github.com/beeware/Python-Apple-support/tree/3.13)
+
+It works by downloading, patching, and building a fat binary of Python
+and selected pre-requisites, and packaging them as frameworks that can
+be incorporated into an Xcode project. The binary modules in the Python
+standard library are distributed as binaries that can be dynamically
+loaded at runtime.
+
+The macOS package is a re-bundling of the official macOS binary,
+modified so that it is relocatable, with the IDLE, Tkinter and turtle
+packages removed, and the App Store compliance patch applied.
+
+The iOS, tvOS, watchOS, and visionOS packages compiled by this project
+use the official [PEP 730](https://peps.python.org/pep-0730/) code that
+is part of Python 3.13 to provide iOS support; the relevant patches have
+been backported to 3.10-3.12. Additional patches have been applied to add
+tvOS, watchOS, and visionOS support.
+
+The binaries support x86_64 and arm64 for macOS; arm64 for iOS and
+appleTV devices; arm64_32 for watchOS devices; and arm64 for visionOS
+devices. It also supports device simulators on both x86_64 and M1
+hardware, except for visionOS, for which x86_64 simulators are
+officially unsupported. This should enable the code to run on:
+
+- macOS 11 (Big Sur) or later, on:
+ - MacBook (including MacBooks using Apple Silicon)
+ - iMac (including iMacs using Apple Silicon)
+ - Mac Mini (including Apple Silicon Mac minis)
+ - Mac Studio (all models)
+ - Mac Pro (all models)
+
+- iOS 13.0 or later, on:
+ - iPhone (6s or later)
+ - iPad (5th gen or later)
+ - iPad Air (all models)
+ - iPad Mini (2 or later)
+ - iPad Pro (all models)
+ - iPod Touch (7th gen or later)
+
+- tvOS 12.0 or later, on:
+ - Apple TV (4th gen or later)
+
+- watchOS 4.0 or later, on:
+ - Apple Watch (4th gen or later)
+
+- visionOS 2.0 or later, on:
+ - Apple Vision Pro
+
+## Quickstart
+
+The easist way to use these packages is by creating a project with
+[Briefcase](https://github.com/beeware/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 from the [Github
+releases page](https://github.com/beeware/Python-Apple-support/releases)
+and added to your project.
+
+Alternatively, to build the frameworks on your own, download/clone this
+repository, and then in the root directory, and run:
+
+- `make` (or `make all`) to build everything.
+- `make macOS` to build everything for macOS.
+- `make iOS` to build everything for iOS.
+- `make tvOS` to build everything for tvOS.
+- `make watchOS` to build everything for watchOS.
+- `make visionOS` to build everything for visionOS.
+
+This should:
+
+1. Download the original source packages
+2. Patch them as required for compatibility with the selected OS
+3. Build the packages as Xcode-compatible XCFrameworks.
+
+The resulting support packages will be packaged as `.tar.gz` files 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 the Python runtime
+ library.
+
+On iOS/tvOS/watchOS/visionOS, the `Python.xcframework` contains a slice
+for each supported ABI (device and simulator). The folder containing the
+slice can also be used as a `PYTHONHOME`, as it contains a `bin`,
+`include` and `lib` directory.
+
+The `bin` folder does not contain Python executables (as they can't be
+invoked). However, it *does* contain shell aliases for the compilers
+that are needed to build packages. This is required because Xcode uses
+the `xcrun` alias to dynamically generate the name of binaries, but a
+lot of C tooling expects that `CC` will not contain spaces.
+
+Each slice of an iOS/tvOS/watchOS/visionOS XCframework also contains a
+`platform-config` folder with a subfolder for each supported
+architecture in that slice. These subfolders can be used to make a macOS
+Python environment behave as if it were on an iOS/tvOS/watchOS/visionOS
+device. This works in one of two ways:
+
+1. **A sitecustomize.py script**. If the `platform-config` subfolder is
+ on your `PYTHONPATH` when a Python interpreter is started, a site
+ customization will be applied that patches methods in `sys`,
+ `sysconfig` and `platform` that are used to identify the system.
+2. **A make_cross_venv.py script**. If you call `make_cross_venv.py`,
+ providing the location of a virtual environment, the script will add
+ some files to the `site-packages` folder of that environment that
+ will automatically apply the same set of patches as the
+ `sitecustomize.py` script whenever the environment is activated,
+ without any need to modify `PYTHONPATH`. If you use `build` to
+ create an isolated PEP 517 environment to build a wheel, these
+ patches will also be applied to the isolated build environment that
+ is created.
+
+iOS and visionOS distributions also contain a copy of the iOS or
+visionOS `testbed` project - an Xcode project that can be used to run
+test suites of Python code. See the [CPython documentation on testing
+packages](https://docs.python.org/3/using/ios.html#testing-a-python-package)
+for details on how to use this testbed.
+
+For a detailed instructions on using the support package in your own
+project, see the [usage guide](./USAGE.md)
+
+## Building binary wheels
+
+This project packages the Python standard library, but does not address
+building binary wheels. Binary wheels for macOS can be obtained from
+PyPI. [Mobile Forge](https://github.com/beeware/mobile-forge) is a
+project that provides the tooling to build build binary wheels for iOS
+(and potentially for tvOS, watchOS, and visionOS, although that hasn't
+been tested).
+
+## Historical support
+
+The following versions were supported in the past, but are no longer
+maintained:
+
+- [Python 2.7](https://github.com/beeware/Python-Apple-support/tree/2.7)
+ (EOL January 2020)
+- [Python 3.4](https://github.com/beeware/Python-Apple-support/tree/3.4)
+ (EOL March 2019)
+- [Python 3.5](https://github.com/beeware/Python-Apple-support/tree/3.5)
+ (EOL February 2021)
+- [Python 3.6](https://github.com/beeware/Python-Apple-support/tree/3.6)
+ (EOL December 2021)
+- [Python 3.7](https://github.com/beeware/Python-Apple-support/tree/3.7)
+ (EOL September 2022)
+- [Python 3.8](https://github.com/beeware/Python-Apple-support/tree/3.8)
+ (EOL October 2024)
+- [Python 3.9](https://github.com/beeware/Python-Apple-support/tree/3.9)
+ (EOL October 2025)
diff --git a/README.rst b/README.rst
deleted file mode 100644
index 0ed59239..00000000
--- a/README.rst
+++ /dev/null
@@ -1,143 +0,0 @@
-Python Apple Support
-====================
-
-This is a meta-package for building a version of Python that can be embedded
-into a macOS, iOS, tvOS or watchOS project.
-
-**This branch builds a packaged version of Python 3.11.0**.
-Other Python versions are available by cloning other branches of the main
-repository:
-
-* `Python 3.8 `__
-* `Python 3.9 `__
-* `Python 3.10 `__
-* `Python 3.11 `__
-
-It works by downloading, patching, and building a fat binary of Python and
-selected pre-requisites, and packaging them as static libraries that can be
-incorporated into an XCode project. The binary modules in the Python standard
-library are statically compiled, but are distribted as ``.so`` objects that
-can be dynamically loaded at runtime.
-
-It exposes *almost* all the modules in the Python standard library except for:
- * dbm.gnu
- * tkinter
- * readline
- * nis (Deprecated by PEP594)
- * ossaudiodev (Deprecated by PEP594)
- * spwd (Deprecated by PEP594)
-
-The following standard library modules are available on macOS, but not the other
-Apple platforms:
- * 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
-x86_64 and M1 hardware. This should enable the code to run on:
-
-* macOS 10.15 (Catalina) or later, on:
- * MacBook (including MacBooks using Apple Silicon)
- * iMac (including iMacs using Apple Silicon)
- * Mac Mini (including M1 Apple Silicon Mac minis)
- * Mac Studio (all models)
- * Mac Pro (all models)
-* iOS 12.0 or later, on:
- * iPhone (6s or later)
- * iPad (5th gen or later)
- * iPad Air (all models)
- * iPad Mini (2 or later)
- * iPad Pro (all models)
- * iPod Touch (7th gen or later)
-* tvOS 9.0 or later, on Apple TV (4th gen or later)
-* watchOS 4.0 or later, on Apple Watch (4th gen or later)
-
-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.
-
-Alternatively, to build the frameworks on your own, download/clone this
-repository, and then in the root directory, and run:
-
-* `make` (or `make all`) to build everything.
-* `make macOS` to build everything for macOS.
-* `make iOS` to build everything for iOS.
-* `make tvOS` to build everything for tvOS.
-* `make watchOS` to build everything for watchOS.
-
-This should:
-
-1. Download the original source packages
-2. Patch them as required for compatibility with the selected OS
-3. Build the packages as XCode-compatible XCFrameworks.
-
-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.11.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.
-
-For a detailed instructions on using the support package in your own project,
-see the `usage guide <./USAGE.md>`__
-
-Building binary wheels
-----------------------
-
-When building binary wheels, you may need to use the libraries built by this
-project as inputs (e.g., the `cffi` module uses `libffi`). To support this, this
-project is able to package these dependencies as "wheels" that can be added to
-the `server/pypi/dist` directory of the `binary dependency builder
-project `__.
-
-To build these wheels, run:
-
-* `make wheels` to make all wheels for all mobile platforms
-* `make wheels-iOS` to build all the iOS wheels
-* `make wheels-tvOS` to build all the tvOS wheels
-* `make wheels-watchOS` to build all the watchOS wheels
-
-.. _for macOS: https://briefcase-support.s3.amazonaws.com/python/3.11/macOS/Python-3.11-macOS-support.b1.tar.gz
-.. _for iOS: https://briefcase-support.s3.amazonaws.com/python/3.11/iOS/Python-3.11-iOS-support.b1.tar.gz
-.. _for tvOS: https://briefcase-support.s3.amazonaws.com/python/3.11/tvOS/Python-3.11-tvOS-support.b1.tar.gz
-.. _for watchOS: https://briefcase-support.s3.amazonaws.com/python/3.11/watchOS/Python-3.11-watchOS-support.b1.tar.gz
-
-Historical support
-------------------
-
-The following versions were supported in the past, but are no longer
-maintained:
-
-* `Python 2.7 `__ (EOL January 2020)
-* `Python 3.4 `__ (EOL March 2019)
-* `Python 3.5 `__ (EOL February 2021)
-* `Python 3.6 `__ (EOL December 2021)
-* `Python 3.7 `__ (EOL September 2022)
diff --git a/USAGE.md b/USAGE.md
index 8363cd2a..b205cdcc 100644
--- a/USAGE.md
+++ b/USAGE.md
@@ -2,119 +2,123 @@
## The easy way
-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).
+The easiest way to use these packages is by creating a project with
+[Briefcase](https://github.com/beeware/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).
## The manual way
-The Python support package *can* be manually added to any Xcode project;
-however, you'll need to perform some steps manually (essentially reproducing what
-Briefcase is doing)
-
**NOTE** Briefcase usage is the officially supported approach for using this
-support package. If you are experiencing diffculties, one approach for debugging
+support package. If you are experiencing difficulties, one approach for debugging
is to generate a "Hello World" project with Briefcase, and compare the project that
Briefcase has generated with your own project.
-To add this support package to your own project:
+The Python support package *can* be manually added to any Xcode project;
+however, you'll need to perform some steps manually (essentially reproducing
+what Briefcase is doing). The steps required are documented in the CPython usage
+guides:
+
+* [macOS](https://docs.python.org/3/using/mac.html)
+* [iOS](https://docs.python.org/3/using/ios.html#adding-python-to-an-ios-project)
-1. [Download a release tarball for your desired Python version and Apple platform](https://github.com/beeware/Python-Apple-support/releases)
+For tvOS, watchOS, and visionOS, you should be able to broadly follow the instructions
+in the iOS guide, changing some platform names in the first script. The testbed projects
+generated on iOS and visionOS may be used as rough references as well.
-2. Add the `python-stdlib` and `Python.xcframework` to your Xcode project. Both
- the `python-stdlib` folder and the `Python.xcframework` should be members of
- any target that needs to use Python.
+### Using Objective C
-3. In Xcode, select the root node of the project tree, and select the target you
- want to build.
+Once you've added the Python XCFramework to your project, you'll need to
+initialize the Python runtime in your Objective C code (This is step 10 of the
+iOS guide linked above). This initialization should generally be done as early
+as possible in the application's lifecycle, but definitely needs to be done
+before you invoke Python code.
-4. Select "General" -> "Frameworks, Libraries and Embedded Content", and ensure
- that `Python.xcframework` is on the list of frameworks. It should be marked
- "Do not embed".
+As a *bare minimum*, you can do the following:
-5. Select "General" -> "Build Phases", and ensure that the `python-stdlib` folder
- is listed in the "Copy Bundle Resources" step.
+1. Import the Python C API headers:
+ ```objc
+ #include
+ ```
-6. Add a new "Run script" build phase named "Sign Python Binary Modules", with the following content:
+2. Initialize the Python interpreter:
+ ```objc
+ NSString *resourcePath = [[NSBundle mainBundle] resourcePath];
+ NSString *pythonHome = [NSString stringWithFormat:@"%@/python", resourcePath, nil];
+ NSString *appPath = [NSString stringWithFormat:@"%@/app", resourcePath, nil];
-```bash
-set -e
-echo "Signing as $EXPANDED_CODE_SIGN_IDENTITY_NAME ($EXPANDED_CODE_SIGN_IDENTITY)"
-find "$CODESIGNING_FOLDER_PATH/Contents/Resources/python-stdlib/lib-dynload" -name "*.so" -exec /usr/bin/codesign --force --sign "$EXPANDED_CODE_SIGN_IDENTITY" -o runtime --timestamp=none --preserve-metadata=identifier,entitlements,flags --generate-entitlement-der {} \;
-```
+ setenv("PYTHONHOME", [pythonHome UTF8String], 1);
+ setenv("PYTHONPATH", [appPath UTF8String], 1);
+
+ Py_Initialize();
+
+ // we now have a Python interpreter ready to be used
+ ```
+
+Again - this is the *bare minimum* initialization. In practice, you will likely
+need to configure other aspects of the Python interpreter using the
+`PyPreConfig` and `PyConfig` mechanisms. Consult the [Python documentation on
+interpreter configuration](https://docs.python.org/3/c-api/init_config.html) for
+more details on the configuration options that are available. You may find the
+[bootstrap mainline code used by
+Briefcase](https://github.com/beeware/briefcase-iOS-Xcode-template/blob/main/%7B%7B%20cookiecutter.format%20%7D%7D/%7B%7B%20cookiecutter.class_name%20%7D%7D/main.m)
+a helpful point of comparison.
+
+### Using Swift
+
+If you want to use Swift instead of Objective C, the bare minimum initialization
+code will look something like this:
+
+1. Import the Python framework:
+ ```swift
+ import Python
+ ```
-You will now be able to access the Python runtime in your Python code.
+2. Initialize the Python interpreter:
+ ```swift
+ guard let pythonHome = Bundle.main.path(forResource: "python", ofType: nil) else { return }
+ let appPath = Bundle.main.path(forResource: "app", ofType: nil)
-If you are on iOS, you will be able to deploy to an iOS simulator without specifying
-development team; however, you will need to specify a valid development team to sign
-the binaries for deployment onto a physical device (or for submission to the App Store).
+ setenv("PYTHONHOME", pythonHome, 1)
+ setenv("PYTHONPATH", appPath, 1)
+ Py_Initialize()
+ // we now have a Python interpreter ready to be used
+ ```
-If you are on macOS, you will need to specify a valid development team to run
-the app. If you don't want to specify a development team in your project, you
-will also need to enable the "Disable Library Validation" entitlement under
-"Signing & Capabilities" -> "Hardened Runtime" for your project.
+ Again, references to a specific Python version should reflect the version of
+ Python you are using; and you will likely need to use `PyPreConfig` and
+ `PreConfig` APIs.
## Accessing the Python runtime
There are 2 ways to access the Python runtime in your project code.
-### Embedded C API.
+### Embedded C API
You can use the [Python Embedded C
-API](https://docs.python.org/3/extending/embedding.html) to instantiate a Python
-interpreter. This is the approach taken by Briefcase; you may find the bootstrap
-mainline code generated by Briefcase a helpful guide to what is needed to start
-an interpreter and run Python code.
+API](https://docs.python.org/3/extending/embedding.html) to invoke Python code
+and interact with Python objects. This is a raw C API that is accessible to both
+Objective C and Swift.
### PythonKit
-An alternate approach is to use
+If you're using Swift, an alternate approach is to use
[PythonKit](https://github.com/pvieito/PythonKit). PythonKit is a package that
provides a Swift API to running Python code.
-To use PythonKit in your project:
+To use PythonKit in your project, add the Python Apple Support package to your
+project and instantiate a Python interpreter as described above; then add
+PythonKit to your project using the Swift Package manager (see the [PythonKit
+documentation](https://github.com/pvieito/PythonKit) for details).
-1. Add PythonKit to your project using the Swift Package manager. See the
- PythonKit documentation for details.
-
-2. Create a file called `module.modulemap` inside
- `Python.xcframework/macos-arm64_x86_64/Headers/`, containing the following
- code:
-```
-module Python {
- umbrella header "Python.h"
- export *
- link "Python"
-}
-```
-
-3. In your Swift code, initialize the Python runtime. This should generally be
- done as early as possible in the application's lifecycle, but definitely
- needs to be done before you invoke Python code:
+Once you've done this, you can import PythonKit:
```swift
-import Python
-
-guard let stdLibPath = Bundle.main.path(forResource: "python-stdlib", ofType: nil) else { return }
-guard let libDynloadPath = Bundle.main.path(forResource: "python-stdlib/lib-dynload", ofType: nil) else { return }
-setenv("PYTHONHOME", stdLibPath, 1)
-setenv("PYTHONPATH", "\(stdLibPath):\(libDynloadPath)", 1)
-Py_Initialize()
-// we now have a Python interpreter ready to be used
+import PythonKit
```
-
-5. Invoke Python code in your app. For example:
+and use the PythonKit Swift API to interact with Python code:
```swift
-import PythonKit
-
let sys = Python.import("sys")
print("Python Version: \(sys.version_info.major).\(sys.version_info.minor)")
print("Python Encoding: \(sys.getdefaultencoding().upper())")
print("Python Path: \(sys.path)")
-
-_ = Python.import("math") // verifies `lib-dynload` is found and signed successfully
```
-
-To integrate 3rd party python code and dependencies, you will need to make sure
-`PYTHONPATH` contains their paths; once this has been done, you can run
-`Python.import("")`. to import that module from inside swift.
diff --git a/patch/Python/OpenSSL.xcprivacy b/patch/Python/OpenSSL.xcprivacy
new file mode 100644
index 00000000..95780a09
--- /dev/null
+++ b/patch/Python/OpenSSL.xcprivacy
@@ -0,0 +1,23 @@
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryFileTimestamp
+ NSPrivacyAccessedAPITypeReasons
+
+ C617.1
+
+
+
+ NSPrivacyCollectedDataTypes
+
+ NSPrivacyTrackingDomains
+
+ NSPrivacyTracking
+
+
+
diff --git a/patch/Python/Python.patch b/patch/Python/Python.patch
index b51b93fb..fec095dd 100644
--- a/patch/Python/Python.patch
+++ b/patch/Python/Python.patch
@@ -1,2651 +1,4603 @@
+diff --git a/Apple/__main__.py b/Apple/__main__.py
+index 256966e76c2..a7bbc8b289e 100644
+--- a/Apple/__main__.py
++++ b/Apple/__main__.py
+@@ -5,17 +5,19 @@
+ # This script simplifies the process of configuring, compiling and packaging an
+ # XCframework for an Apple platform.
+ #
+-# At present, it only supports iOS, but it has been constructed so that it
+-# could be used on any Apple platform.
++# At present, it supports iOS, tvOS, visionOS and watchOS, but it has been
++# constructed so that it could be used on any Apple platform.
+ #
+ # The simplest entry point is:
+ #
+ # $ python Apple ci iOS
+ #
++# (replace iOS with tvOS, visionOS or watchOS as required.)
++#
+ # which will:
+ # * Clean any pre-existing build artefacts
+ # * Configure and make a Python that can be used for the build
+-# * Configure and make a Python for each supported iOS architecture and ABI
++# * Configure and make a Python for each supported iOS/tvOS architecture and ABI
+ # * Combine the outputs of the builds from the previous step into a single
+ # XCframework, merging binaries into a "fat" binary if necessary
+ # * Clone a copy of the testbed, configured to use the XCframework
+@@ -75,6 +77,32 @@
+ "x86_64-apple-ios-simulator": "x86_64-iphonesimulator",
+ },
+ },
++ "tvOS": {
++ "tvos-arm64": {
++ "arm64-apple-tvos": "arm64-appletvos",
++ },
++ "tvos-arm64_x86_64-simulator": {
++ "arm64-apple-tvos-simulator": "arm64-appletvsimulator",
++ "x86_64-apple-tvos-simulator": "x86_64-appletvsimulator",
++ },
++ },
++ "visionOS": {
++ "xros-arm64": {
++ "arm64-apple-xros": "arm64-xros",
++ },
++ "xros-arm64-simulator": {
++ "arm64-apple-xros-simulator": "arm64-xrsimulator",
++ },
++ },
++ "watchOS": {
++ "watchos-arm64_32": {
++ "arm64_32-apple-watchos": "arm64_32-watchos",
++ },
++ "watchos-arm64_x86_64-simulator": {
++ "arm64-apple-watchos-simulator": "arm64-watchsimulator",
++ "x86_64-apple-watchos-simulator": "x86_64-watchsimulator",
++ },
++ },
+ }
+
+
+@@ -136,11 +164,24 @@
+ print(f"export {key}={shlex.quote(value)}")
+
+
++def platform_for_host(host):
++ """Determine the platform for a given host triple."""
++ for plat, slices in HOSTS.items():
++ for _, candidates in slices.items():
++ for candidate in candidates:
++ if candidate == host:
++ return plat
++ raise KeyError(host)
++
++
+ def apple_env(host: str) -> EnvironmentT:
+ """Construct an Apple development environment for the given host."""
+ env = {
+ "PATH": ":".join([
+- str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
++ str(
++ PYTHON_DIR
++ / f"Apple/{platform_for_host(host)}/Resources/bin"
++ ),
+ str(subdir(host) / "prefix"),
+ "/usr/bin",
+ "/bin",
+@@ -302,8 +343,8 @@
+ Downloads binaries if they aren't already present. Downloads will be stored
+ in provided cache directory.
+
+- On iOS, as a safety mechanism, any dynamic libraries will be purged from
+- the unpacked dependencies.
++ On non-macOS platforms, as a safety mechanism, any dynamic libraries will be
++ purged from the unpacked dependencies.
+ """
+ # To create new builds of these dependencies, usually all that's necessary
+ # is to push a tag to the cpython-apple-source-deps repository, and GitHub
+@@ -328,9 +369,9 @@
+ )
+ shutil.unpack_archive(archive_path, prefix_dir)
+
+- # Dynamic libraries will be preferentially linked over static;
+- # On iOS, ensure that no dylibs are available in the prefix folder.
+- if platform == "iOS":
++ # Dynamic libraries will be preferentially linked over static; On non-macOS
++ # platforms, ensure that no dylibs are available in the prefix folder.
++ if platform != "macOS":
+ for dylib in prefix_dir.glob("**/*.dylib"):
+ dylib.unlink()
+
+@@ -392,6 +433,7 @@
+ f"--build={sysconfig.get_config_var('BUILD_GNU_TYPE')}",
+ f"--with-build-python={build_python_path()}",
+ "--with-system-libmpdec",
++ "--enable-ipv6",
+ "--enable-framework",
+ # Dependent libraries.
+ f"--with-openssl={prefix_dir}",
+@@ -432,7 +474,10 @@
+ :param host_triple: The host triple (e.g., arm64-apple-ios-simulator)
+ :param multiarch: The multiarch identifier (e.g., arm64-simulator)
+ """
+- return CROSS_BUILD_DIR / f"{host_triple}/Apple/iOS/Frameworks/{multiarch}"
++ return (
++ CROSS_BUILD_DIR
++ / f"{host_triple}/Apple/{platform_for_host(host_triple)}/Frameworks/{multiarch}"
++ )
+
+
+ def package_version(prefix_path: Path) -> str:
+@@ -653,7 +698,7 @@
+ host_path = (
+ CROSS_BUILD_DIR
+ / host_triple
+- / "Apple/iOS/Frameworks"
++ / f"Apple/{platform}/Frameworks"
+ / multiarch
+ )
+ host_framework = host_path / "Python.framework"
+@@ -699,18 +744,20 @@
+ # Create an XCframework
+ version = create_xcframework(context.platform)
+
+- # Clone testbed
+- print()
+- run([
+- sys.executable,
+- "Apple/testbed",
+- "clone",
+- "--platform",
+- context.platform,
+- "--framework",
+- CROSS_BUILD_DIR / context.platform / "Python.xcframework",
+- CROSS_BUILD_DIR / context.platform / "testbed",
+- ])
++ # watchOS doesn't have a testbed (yet!)
++ if context.platform != "watchOS":
++ # Clone testbed
++ print()
++ run([
++ sys.executable,
++ "Apple/testbed",
++ "clone",
++ "--platform",
++ context.platform,
++ "--framework",
++ CROSS_BUILD_DIR / context.platform / "Python.xcframework",
++ CROSS_BUILD_DIR / context.platform / "testbed",
++ ])
+
+ # Build the final archive
+ archive_name = (
+diff --git a/Apple/iOS/Resources/Info.plist.in b/Apple/iOS/Resources/Info.plist.in
+index c3e261ecd9e..26ef7a95de4 100644
+--- a/Apple/iOS/Resources/Info.plist.in
++++ b/Apple/iOS/Resources/Info.plist.in
+@@ -17,13 +17,13 @@
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+- @VERSION@
++ %VERSION%
+ CFBundleLongVersionString
+ %VERSION%, (c) 2001-2024 Python Software Foundation.
+ CFBundleSignature
+ ????
+ CFBundleVersion
+- 1
++ %VERSION%
+ CFBundleSupportedPlatforms
+
+ iPhoneOS
+diff --git a/Apple/testbed/Python.xcframework/Info.plist b/Apple/testbed/Python.xcframework/Info.plist
+index c6418de6e74..0587f4735f7 100644
+--- a/Apple/testbed/Python.xcframework/Info.plist
++++ b/Apple/testbed/Python.xcframework/Info.plist
+@@ -35,6 +35,98 @@
+ SupportedPlatformVariant
+ simulator
+
++
++ BinaryPath
++ Python.framework/Python
++ LibraryIdentifier
++ tvos-arm64
++ LibraryPath
++ Python.framework
++ SupportedArchitectures
++
++ arm64
++
++ SupportedPlatform
++ tvos
++
++
++ BinaryPath
++ Python.framework/Python
++ LibraryIdentifier
++ tvos-arm64_x86_64-simulator
++ LibraryPath
++ Python.framework
++ SupportedArchitectures
++
++ arm64
++ x86_64
++
++ SupportedPlatform
++ tvos
++ SupportedPlatformVariant
++ simulator
++
++
++ BinaryPath
++ Python.framework/Python
++ LibraryIdentifier
++ xros-arm64-simulator
++ LibraryPath
++ Python.framework
++ SupportedArchitectures
++
++ arm64
++
++ SupportedPlatform
++ xros
++ SupportedPlatformVariant
++ simulator
++
++
++ BinaryPath
++ Python.framework/Python
++ LibraryIdentifier
++ xros-arm64
++ LibraryPath
++ Python.framework
++ SupportedArchitectures
++
++ arm64
++
++ SupportedPlatform
++ xros
++
++
++ BinaryPath
++ Python.framework/Python
++ LibraryIdentifier
++ watchos-arm64_x86_64-simulator
++ LibraryPath
++ Python.framework
++ SupportedArchitectures
++
++ arm64
++ x86_64
++
++ SupportedPlatform
++ watchos
++ SupportedPlatformVariant
++ simulator
++
++
++ BinaryPath
++ Python.framework/Python
++ LibraryIdentifier
++ watchos-arm64_32
++ LibraryPath
++ Python.framework
++ SupportedArchitectures
++
++ arm64_32
++
++ SupportedPlatform
++ watchos
++
+
+ CFBundlePackageType
+ XFWK
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/build/tvOS-dylib-Info-template.plist
+@@ -0,0 +1,26 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++
++ CFBundleIdentifier
++
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSupportedPlatforms
++
++ tvOS
++
++ MinimumOSVersion
++ 9.0
++ CFBundleVersion
++ 1
++
++
+diff --git a/Apple/testbed/Python.xcframework/build/utils.sh b/Apple/testbed/Python.xcframework/build/utils.sh
+index e7155d8b30e..aa56a29dcbd 100755
+--- a/Apple/testbed/Python.xcframework/build/utils.sh
++++ b/Apple/testbed/Python.xcframework/build/utils.sh
+@@ -34,9 +34,38 @@
+ else
+ SLICE_FOLDER="ios-arm64_x86_64-simulator"
+ fi
+- else
++ elif [ "$EFFECTIVE_PLATFORM_NAME" = "-iphoneos" ]; then
+ echo "Installing Python modules for iOS Device"
+ SLICE_FOLDER="ios-arm64"
++ elif [ "$EFFECTIVE_PLATFORM_NAME" = "-appletvsimulator" ]; then
++ echo "Installing Python modules for tvOS Simulator"
++ if [ -d "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/tvos-arm64-simulator" ]; then
++ SLICE_FOLDER="tvos-arm64-simulator"
++ else
++ SLICE_FOLDER="tvos-arm64_x86_64-simulator"
++ fi
++ elif [ "$EFFECTIVE_PLATFORM_NAME" = "-appletvos" ]; then
++ echo "Installing Python modules for tvOS Device"
++ SLICE_FOLDER="tvos-arm64"
++ elif [ "$EFFECTIVE_PLATFORM_NAME" = "-watchsimulator" ]; then
++ echo "Installing Python modules for watchOS Simulator"
++ if [ -d "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/watchos-arm64-simulator" ]; then
++ SLICE_FOLDER="watchos-arm64-simulator"
++ else
++ SLICE_FOLDER="watchos-arm64_x86_64-simulator"
++ fi
++ elif [ "$EFFECTIVE_PLATFORM_NAME" = "-watchos" ]; then
++ echo "Installing Python modules for watchOS Device"
++ SLICE_FOLDER="watchos-arm64"
++ elif [ "$EFFECTIVE_PLATFORM_NAME" = "-xrsimulator" ]; then
++ echo "Installing Python modules for visionOS Simulator"
++ SLICE_FOLDER="xros-arm64-simulator"
++ elif [ "$EFFECTIVE_PLATFORM_NAME" = "-xros" ]; then
++ echo "Installing Python modules for visionOS Device"
++ SLICE_FOLDER="xros-arm64"
++ else
++ echo "Unsupported platform name $EFFECTIVE_PLATFORM_NAME"
++ exit 1
+ fi
+
+ # If the XCframework has a shared lib folder, then it's a full framework.
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/build/watchOS-dylib-Info-template.plist
+@@ -0,0 +1,26 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++
++ CFBundleIdentifier
++
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSupportedPlatforms
++
++ watchOS
++
++ MinimumOSVersion
++ 4.0
++ CFBundleVersion
++ 1
++
++
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/build/xrOS-dylib-Info-template.plist
+@@ -0,0 +1,30 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleExecutable
++
++ CFBundleIdentifier
++
++ CFBundlePackageType
++ FMWK
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSupportedPlatforms
++
++ XROS
++
++ CFBundleVersion
++ 1
++ MinimumOSVersion
++ 2.0
++ UIDeviceFamily
++
++ 7
++
++
++
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/tvos-arm64/README
+@@ -0,0 +1,4 @@
++This directory is intentionally empty.
++
++It should be used as a target for `--enable-framework` when compiling a tvOS
++on-device build for testing purposes.
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/tvos-arm64_x86_64-simulator/README
+@@ -0,0 +1,4 @@
++This directory is intentionally empty.
++
++It should be used as a target for `--enable-framework` when compiling a tvOS
++simulator build for testing purposes (either x86_64 or ARM64).
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/watchos-arm64_32/README
+@@ -0,0 +1,4 @@
++This directory is intentionally empty.
++
++It should be used as a target for `--enable-framework` when compiling a watchOS on-device
++build for testing purposes.
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/watchos-arm64_x86_64-simulator/README
+@@ -0,0 +1,4 @@
++This directory is intentionally empty.
++
++It should be used as a target for `--enable-framework` when compiling a watchOS
++simulator build for testing purposes (either x86_64 or ARM64).
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/xros-arm64-simulator/README
+@@ -0,0 +1,4 @@
++This directory is intentionally empty.
++
++It should be used as a target for `--enable-framework` when compiling an visionOS simulator
++build for testing purposes (either x86_64 or ARM64).
+--- /dev/null
++++ b/Apple/testbed/Python.xcframework/xros-arm64/README
+@@ -0,0 +1,4 @@
++This directory is intentionally empty.
++
++It should be used as a target for `--enable-framework` when compiling an visionOS on-device
++build for testing purposes.
+diff --git a/Apple/testbed/__main__.py b/Apple/testbed/__main__.py
+index 0dd77ab8b82..0b9bdba36a4 100644
+--- a/Apple/testbed/__main__.py
++++ b/Apple/testbed/__main__.py
+@@ -10,6 +10,9 @@
+
+ TEST_SLICES = {
+ "iOS": "ios-arm64_x86_64-simulator",
++ "tvOS": "tvos-arm64_x86_64-simulator",
++ "visionOS": "xros-arm64-simulator",
++ "watchOS": "watchos-arm64_x86_64-simulator",
+ }
+
+ DECODE_ARGS = ("UTF-8", "backslashreplace")
+@@ -21,7 +24,7 @@
+ LOG_PREFIX_REGEX = re.compile(
+ r"^\d{4}-\d{2}-\d{2}" # YYYY-MM-DD
+ r"\s+\d+:\d{2}:\d{2}\.\d+\+\d{4}" # HH:MM:SS.ssssss+ZZZZ
+- r"\s+iOSTestbed\[\d+:\w+\]" # Process/thread ID
++ r"\s+.*Testbed\[\d+:\w+\]" # Process/thread ID
+ )
+
+
+@@ -54,6 +57,24 @@
+ )
+ )
+ simulator = se_simulators[-1][1]
++ elif platform == "tvOS":
++ # Find the most recent tvOS release.
++ simulators = sorted(
++ (devicetype["minRuntimeVersion"], devicetype["name"])
++ for devicetype in json_data["devicetypes"]
++ if devicetype["productFamily"] == "Apple TV"
++ )
++ simulator = simulators[-1][1]
++ elif platform == "visionOS":
++ # Find the most recent visionOS release.
++ simulators = sorted(
++ (devicetype["minRuntimeVersion"], devicetype["name"])
++ for devicetype in json_data["devicetypes"]
++ if devicetype["productFamily"] == "Apple Vision"
++ )
++ simulator = simulators[-1][1]
++ elif platform == "watchOS":
++ raise NotImplementedError(f"Don't know how to launch watchOS (yet)")
+ else:
+ raise ValueError(f"Unknown platform {platform}")
+
+@@ -289,7 +310,7 @@
+ # many platforms, but when cloned, only one platform is preserved.
+ available_platforms = [
+ platform
+- for platform in ["iOS"]
++ for platform in ["iOS", "tvOS", "visionOS", "watchOS"]
+ if (Path(__file__).parent / f"{platform}Testbed").is_dir()
+ ]
+
+@@ -343,7 +364,7 @@
+ ),
+ description=(
+ "Run a testbed project. The arguments provided after `--` will be "
+- "passed to the running iOS process as if they were arguments to "
++ "passed to the running test process as if they were arguments to "
+ "`python -m`."
+ ),
+ help="Run a testbed project",
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed.xcodeproj/project.pbxproj
+@@ -0,0 +1,505 @@
++// !$*UTF8*$!
++{
++ archiveVersion = 1;
++ classes = {
++ };
++ objectVersion = 77;
++ objects = {
++
++/* Begin PBXBuildFile section */
++ EE7C8A1E2DCD6FF3003206DB /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE7C8A1C2DCD6FF3003206DB /* Python.xcframework */; };
++ EE7C8A1F2DCD70CD003206DB /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EE7C8A1C2DCD6FF3003206DB /* Python.xcframework */; };
++ EE7C8A202DCD70CD003206DB /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EE7C8A1C2DCD6FF3003206DB /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
++/* End PBXBuildFile section */
++
++/* Begin PBXContainerItemProxy section */
++ EE989E662DCD6E7A0036B268 /* PBXContainerItemProxy */ = {
++ isa = PBXContainerItemProxy;
++ containerPortal = EE989E462DCD6E780036B268 /* Project object */;
++ proxyType = 1;
++ remoteGlobalIDString = EE989E4D2DCD6E780036B268;
++ remoteInfo = tvOSTestbed;
++ };
++/* End PBXContainerItemProxy section */
++
++/* Begin PBXCopyFilesBuildPhase section */
++ EE7C8A212DCD70CD003206DB /* Embed Frameworks */ = {
++ isa = PBXCopyFilesBuildPhase;
++ buildActionMask = 2147483647;
++ dstPath = "";
++ dstSubfolderSpec = 10;
++ files = (
++ EE7C8A202DCD70CD003206DB /* Python.xcframework in Embed Frameworks */,
++ );
++ name = "Embed Frameworks";
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXCopyFilesBuildPhase section */
++
++/* Begin PBXFileReference section */
++ 6077B3802E82A4BE00E3D6A3 /* tvOSTestbed.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = tvOSTestbed.xctestplan; sourceTree = ""; };
++ EE7C8A1C2DCD6FF3003206DB /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; };
++ EE989E4E2DCD6E780036B268 /* tvOSTestbed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = tvOSTestbed.app; sourceTree = BUILT_PRODUCTS_DIR; };
++ EE989E652DCD6E7A0036B268 /* TestbedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestbedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
++/* End PBXFileReference section */
++
++/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
++ 6077B37F2E81892A00E3D6A3 /* Exceptions for "tvOSTestbed" folder in "tvOSTestbed" target */ = {
++ isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
++ membershipExceptions = (
++ "tvOSTestbed-Info.plist",
++ );
++ target = EE989E4D2DCD6E780036B268 /* tvOSTestbed */;
++ };
++/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
++
++/* Begin PBXFileSystemSynchronizedRootGroup section */
++ EE989E502DCD6E780036B268 /* tvOSTestbed */ = {
++ isa = PBXFileSystemSynchronizedRootGroup;
++ exceptions = (
++ 6077B37F2E81892A00E3D6A3 /* Exceptions for "tvOSTestbed" folder in "tvOSTestbed" target */,
++ );
++ explicitFolders = (
++ app,
++ app_packages,
++ );
++ path = tvOSTestbed;
++ sourceTree = "";
++ };
++ EE989E682DCD6E7A0036B268 /* TestbedTests */ = {
++ isa = PBXFileSystemSynchronizedRootGroup;
++ path = TestbedTests;
++ sourceTree = "";
++ };
++/* End PBXFileSystemSynchronizedRootGroup section */
++
++/* Begin PBXFrameworksBuildPhase section */
++ EE989E4B2DCD6E780036B268 /* Frameworks */ = {
++ isa = PBXFrameworksBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ EE7C8A1F2DCD70CD003206DB /* Python.xcframework in Frameworks */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ EE989E622DCD6E7A0036B268 /* Frameworks */ = {
++ isa = PBXFrameworksBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ EE7C8A1E2DCD6FF3003206DB /* Python.xcframework in Frameworks */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXFrameworksBuildPhase section */
++
++/* Begin PBXGroup section */
++ EE989E452DCD6E780036B268 = {
++ isa = PBXGroup;
++ children = (
++ 6077B3802E82A4BE00E3D6A3 /* tvOSTestbed.xctestplan */,
++ EE7C8A1C2DCD6FF3003206DB /* Python.xcframework */,
++ EE989E502DCD6E780036B268 /* tvOSTestbed */,
++ EE989E682DCD6E7A0036B268 /* TestbedTests */,
++ EE989E4F2DCD6E780036B268 /* Products */,
++ );
++ sourceTree = "";
++ };
++ EE989E4F2DCD6E780036B268 /* Products */ = {
++ isa = PBXGroup;
++ children = (
++ EE989E4E2DCD6E780036B268 /* tvOSTestbed.app */,
++ EE989E652DCD6E7A0036B268 /* TestbedTests.xctest */,
++ );
++ name = Products;
++ sourceTree = "";
++ };
++/* End PBXGroup section */
++
++/* Begin PBXNativeTarget section */
++ EE989E4D2DCD6E780036B268 /* tvOSTestbed */ = {
++ isa = PBXNativeTarget;
++ buildConfigurationList = EE989E792DCD6E7A0036B268 /* Build configuration list for PBXNativeTarget "tvOSTestbed" */;
++ buildPhases = (
++ EE989E4A2DCD6E780036B268 /* Sources */,
++ EE989E4B2DCD6E780036B268 /* Frameworks */,
++ EE989E4C2DCD6E780036B268 /* Resources */,
++ EE7C8A222DCD70F4003206DB /* Process Python libraries */,
++ EE7C8A212DCD70CD003206DB /* Embed Frameworks */,
++ );
++ buildRules = (
++ );
++ dependencies = (
++ );
++ fileSystemSynchronizedGroups = (
++ EE989E502DCD6E780036B268 /* tvOSTestbed */,
++ );
++ name = tvOSTestbed;
++ packageProductDependencies = (
++ );
++ productName = tvOSTestbed;
++ productReference = EE989E4E2DCD6E780036B268 /* tvOSTestbed.app */;
++ productType = "com.apple.product-type.application";
++ };
++ EE989E642DCD6E7A0036B268 /* TestbedTests */ = {
++ isa = PBXNativeTarget;
++ buildConfigurationList = EE989E7C2DCD6E7A0036B268 /* Build configuration list for PBXNativeTarget "TestbedTests" */;
++ buildPhases = (
++ EE989E612DCD6E7A0036B268 /* Sources */,
++ EE989E622DCD6E7A0036B268 /* Frameworks */,
++ EE989E632DCD6E7A0036B268 /* Resources */,
++ );
++ buildRules = (
++ );
++ dependencies = (
++ EE989E672DCD6E7A0036B268 /* PBXTargetDependency */,
++ );
++ fileSystemSynchronizedGroups = (
++ EE989E682DCD6E7A0036B268 /* TestbedTests */,
++ );
++ name = TestbedTests;
++ packageProductDependencies = (
++ );
++ productName = TestbedTests;
++ productReference = EE989E652DCD6E7A0036B268 /* TestbedTests.xctest */;
++ productType = "com.apple.product-type.bundle.unit-test";
++ };
++/* End PBXNativeTarget section */
++
++/* Begin PBXProject section */
++ EE989E462DCD6E780036B268 /* Project object */ = {
++ isa = PBXProject;
++ attributes = {
++ BuildIndependentTargetsInParallel = 1;
++ LastUpgradeCheck = 1620;
++ TargetAttributes = {
++ EE989E4D2DCD6E780036B268 = {
++ CreatedOnToolsVersion = 16.2;
++ };
++ EE989E642DCD6E7A0036B268 = {
++ CreatedOnToolsVersion = 16.2;
++ TestTargetID = EE989E4D2DCD6E780036B268;
++ };
++ };
++ };
++ buildConfigurationList = EE989E492DCD6E780036B268 /* Build configuration list for PBXProject "tvOSTestbed" */;
++ developmentRegion = en;
++ hasScannedForEncodings = 0;
++ knownRegions = (
++ en,
++ Base,
++ );
++ mainGroup = EE989E452DCD6E780036B268;
++ minimizedProjectReferenceProxies = 1;
++ preferredProjectObjectVersion = 77;
++ productRefGroup = EE989E4F2DCD6E780036B268 /* Products */;
++ projectDirPath = "";
++ projectRoot = "";
++ targets = (
++ EE989E4D2DCD6E780036B268 /* tvOSTestbed */,
++ EE989E642DCD6E7A0036B268 /* TestbedTests */,
++ );
++ };
++/* End PBXProject section */
++
++/* Begin PBXResourcesBuildPhase section */
++ EE989E4C2DCD6E780036B268 /* Resources */ = {
++ isa = PBXResourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ EE989E632DCD6E7A0036B268 /* Resources */ = {
++ isa = PBXResourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXResourcesBuildPhase section */
++
++/* Begin PBXShellScriptBuildPhase section */
++ EE7C8A222DCD70F4003206DB /* Process Python libraries */ = {
++ isa = PBXShellScriptBuildPhase;
++ alwaysOutOfDate = 1;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ inputFileListPaths = (
++ );
++ inputPaths = (
++ );
++ name = "Process Python libraries";
++ outputFileListPaths = (
++ );
++ outputPaths = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ shellPath = /bin/sh;
++ shellScript = "set -e\n\nsource $PROJECT_DIR/Python.xcframework/build/utils.sh\n\ninstall_python Python.xcframework app app_packages\n";
++ };
++/* End PBXShellScriptBuildPhase section */
++
++/* Begin PBXSourcesBuildPhase section */
++ EE989E4A2DCD6E780036B268 /* Sources */ = {
++ isa = PBXSourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ EE989E612DCD6E7A0036B268 /* Sources */ = {
++ isa = PBXSourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXSourcesBuildPhase section */
++
++/* Begin PBXTargetDependency section */
++ EE989E672DCD6E7A0036B268 /* PBXTargetDependency */ = {
++ isa = PBXTargetDependency;
++ target = EE989E4D2DCD6E780036B268 /* tvOSTestbed */;
++ targetProxy = EE989E662DCD6E7A0036B268 /* PBXContainerItemProxy */;
++ };
++/* End PBXTargetDependency section */
++
++/* Begin XCBuildConfiguration section */
++ EE989E772DCD6E7A0036B268 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ALWAYS_SEARCH_USER_PATHS = NO;
++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
++ CLANG_ANALYZER_NONNULL = YES;
++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
++ CLANG_ENABLE_MODULES = YES;
++ CLANG_ENABLE_OBJC_ARC = YES;
++ CLANG_ENABLE_OBJC_WEAK = YES;
++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
++ CLANG_WARN_BOOL_CONVERSION = YES;
++ CLANG_WARN_COMMA = YES;
++ CLANG_WARN_CONSTANT_CONVERSION = YES;
++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
++ CLANG_WARN_EMPTY_BODY = YES;
++ CLANG_WARN_ENUM_CONVERSION = YES;
++ CLANG_WARN_INFINITE_RECURSION = YES;
++ CLANG_WARN_INT_CONVERSION = YES;
++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
++ CLANG_WARN_STRICT_PROTOTYPES = YES;
++ CLANG_WARN_SUSPICIOUS_MOVE = YES;
++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
++ CLANG_WARN_UNREACHABLE_CODE = YES;
++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
++ COPY_PHASE_STRIP = NO;
++ DEBUG_INFORMATION_FORMAT = dwarf;
++ ENABLE_STRICT_OBJC_MSGSEND = YES;
++ ENABLE_TESTABILITY = YES;
++ ENABLE_USER_SCRIPT_SANDBOXING = NO;
++ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
++ GCC_C_LANGUAGE_STANDARD = gnu17;
++ GCC_DYNAMIC_NO_PIC = NO;
++ GCC_NO_COMMON_BLOCKS = YES;
++ GCC_OPTIMIZATION_LEVEL = 0;
++ GCC_PREPROCESSOR_DEFINITIONS = (
++ "DEBUG=1",
++ "$(inherited)",
++ );
++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
++ GCC_WARN_UNDECLARED_SELECTOR = YES;
++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
++ GCC_WARN_UNUSED_FUNCTION = YES;
++ GCC_WARN_UNUSED_VARIABLE = YES;
++ HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/Python.framework/Headers";
++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
++ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
++ MTL_FAST_MATH = YES;
++ ONLY_ACTIVE_ARCH = YES;
++ SDKROOT = appletvos;
++ TVOS_DEPLOYMENT_TARGET = 18.2;
++ };
++ name = Debug;
++ };
++ EE989E782DCD6E7A0036B268 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ALWAYS_SEARCH_USER_PATHS = NO;
++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
++ CLANG_ANALYZER_NONNULL = YES;
++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
++ CLANG_ENABLE_MODULES = YES;
++ CLANG_ENABLE_OBJC_ARC = YES;
++ CLANG_ENABLE_OBJC_WEAK = YES;
++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
++ CLANG_WARN_BOOL_CONVERSION = YES;
++ CLANG_WARN_COMMA = YES;
++ CLANG_WARN_CONSTANT_CONVERSION = YES;
++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
++ CLANG_WARN_EMPTY_BODY = YES;
++ CLANG_WARN_ENUM_CONVERSION = YES;
++ CLANG_WARN_INFINITE_RECURSION = YES;
++ CLANG_WARN_INT_CONVERSION = YES;
++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
++ CLANG_WARN_STRICT_PROTOTYPES = YES;
++ CLANG_WARN_SUSPICIOUS_MOVE = YES;
++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
++ CLANG_WARN_UNREACHABLE_CODE = YES;
++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
++ COPY_PHASE_STRIP = NO;
++ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
++ ENABLE_NS_ASSERTIONS = NO;
++ ENABLE_STRICT_OBJC_MSGSEND = YES;
++ ENABLE_TESTABILITY = YES;
++ ENABLE_USER_SCRIPT_SANDBOXING = NO;
++ FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)";
++ GCC_C_LANGUAGE_STANDARD = gnu17;
++ GCC_NO_COMMON_BLOCKS = YES;
++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
++ GCC_WARN_UNDECLARED_SELECTOR = YES;
++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
++ GCC_WARN_UNUSED_FUNCTION = YES;
++ GCC_WARN_UNUSED_VARIABLE = YES;
++ HEADER_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)/Python.framework/Headers";
++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
++ MTL_ENABLE_DEBUG_INFO = NO;
++ MTL_FAST_MATH = YES;
++ SDKROOT = appletvos;
++ TVOS_DEPLOYMENT_TARGET = 18.2;
++ VALIDATE_PRODUCT = YES;
++ };
++ name = Release;
++ };
++ EE989E7A2DCD6E7A0036B268 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ GENERATE_INFOPLIST_FILE = NO;
++ INFOPLIST_FILE = "tvOSTestbed/tvOSTestbed-Info.plist";
++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
++ INFOPLIST_KEY_UIMainStoryboardFile = Main;
++ INFOPLIST_KEY_UIUserInterfaceStyle = Automatic;
++ LD_RUNPATH_SEARCH_PATHS = (
++ "$(inherited)",
++ "@executable_path/Frameworks",
++ );
++ MARKETING_VERSION = 1.0;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.tvOSTestbed;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SWIFT_EMIT_LOC_STRINGS = YES;
++ TARGETED_DEVICE_FAMILY = 3;
++ };
++ name = Debug;
++ };
++ EE989E7B2DCD6E7A0036B268 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ GENERATE_INFOPLIST_FILE = NO;
++ INFOPLIST_FILE = "tvOSTestbed/tvOSTestbed-Info.plist";
++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
++ INFOPLIST_KEY_UIMainStoryboardFile = Main;
++ INFOPLIST_KEY_UIUserInterfaceStyle = Automatic;
++ LD_RUNPATH_SEARCH_PATHS = (
++ "$(inherited)",
++ "@executable_path/Frameworks",
++ );
++ MARKETING_VERSION = 1.0;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.tvOSTestbed;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SWIFT_EMIT_LOC_STRINGS = YES;
++ TARGETED_DEVICE_FAMILY = 3;
++ };
++ name = Release;
++ };
++ EE989E7D2DCD6E7A0036B268 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ BUNDLE_LOADER = "$(TEST_HOST)";
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ GENERATE_INFOPLIST_FILE = YES;
++ MARKETING_VERSION = 1.0;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.TestbedTests;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SWIFT_EMIT_LOC_STRINGS = NO;
++ TARGETED_DEVICE_FAMILY = 3;
++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/tvOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/tvOSTestbed";
++ TVOS_DEPLOYMENT_TARGET = 18.2;
++ };
++ name = Debug;
++ };
++ EE989E7E2DCD6E7A0036B268 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ BUNDLE_LOADER = "$(TEST_HOST)";
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ GENERATE_INFOPLIST_FILE = YES;
++ MARKETING_VERSION = 1.0;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.TestbedTests;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SWIFT_EMIT_LOC_STRINGS = NO;
++ TARGETED_DEVICE_FAMILY = 3;
++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/tvOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/tvOSTestbed";
++ TVOS_DEPLOYMENT_TARGET = 18.2;
++ };
++ name = Release;
++ };
++/* End XCBuildConfiguration section */
++
++/* Begin XCConfigurationList section */
++ EE989E492DCD6E780036B268 /* Build configuration list for PBXProject "tvOSTestbed" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ EE989E772DCD6E7A0036B268 /* Debug */,
++ EE989E782DCD6E7A0036B268 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++ EE989E792DCD6E7A0036B268 /* Build configuration list for PBXNativeTarget "tvOSTestbed" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ EE989E7A2DCD6E7A0036B268 /* Debug */,
++ EE989E7B2DCD6E7A0036B268 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++ EE989E7C2DCD6E7A0036B268 /* Build configuration list for PBXNativeTarget "TestbedTests" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ EE989E7D2DCD6E7A0036B268 /* Debug */,
++ EE989E7E2DCD6E7A0036B268 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++/* End XCConfigurationList section */
++ };
++ rootObject = EE989E462DCD6E780036B268 /* Project object */;
++}
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed.xcodeproj/xcshareddata/xcschemes/tvOSTestbed.xcscheme
+@@ -0,0 +1,97 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed.xctestplan
+@@ -0,0 +1,46 @@
++{
++ "configurations" : [
++ {
++ "id" : "F5A95CE4-1ADE-4A6E-A0E1-CDBAE26DF0C5",
++ "name" : "Test Scheme Action",
++ "options" : {
++
++ }
++ }
++ ],
++ "defaultOptions" : {
++ "commandLineArgumentEntries" : [
++ {
++ "argument" : "test"
++ },
++ {
++ "argument" : "-uall"
++ },
++ {
++ "argument" : "--single-process"
++ },
++ {
++ "argument" : "--rerun"
++ },
++ {
++ "argument" : "-W"
++ }
++ ],
++ "targetForVariableExpansion" : {
++ "containerPath" : "container:tvOSTestbed.xcodeproj",
++ "identifier" : "607A66112B0EFA380010BFC8",
++ "name" : "tvOSTestbed"
++ }
++ },
++ "testTargets" : [
++ {
++ "parallelizable" : false,
++ "target" : {
++ "containerPath" : "container:tvOSTestbed.xcodeproj",
++ "identifier" : "EE989E642DCD6E7A0036B268",
++ "name" : "TestbedTests"
++ }
++ }
++ ],
++ "version" : 1
++}
+\ No newline at end of file
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed/AppDelegate.h
+@@ -0,0 +1,11 @@
++//
++// AppDelegate.h
++// tvOSTestbed
++//
++
++#import
++
++@interface AppDelegate : UIResponder
++
++
++@end
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed/AppDelegate.m
+@@ -0,0 +1,19 @@
++//
++// AppDelegate.m
++// tvOSTestbed
++//
++
++#import "AppDelegate.h"
++
++@interface AppDelegate ()
++
++@end
++
++@implementation AppDelegate
++
++
++- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
++ return YES;
++}
++
++@end
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed/Base.lproj/LaunchScreen.storyboard
+@@ -0,0 +1,24 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed/app/README
+@@ -0,0 +1,7 @@
++This folder can contain any Python application code.
++
++During the build, any binary modules found in this folder will be processed into
++Framework form.
++
++When the test suite runs, this folder will be on the PYTHONPATH, and will be the
++working directory for the test suite.
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed/app_packages/README
+@@ -0,0 +1,7 @@
++This folder can be a target for installing any Python dependencies needed by the
++test suite.
++
++During the build, any binary modules found in this folder will be processed into
++Framework form.
++
++When the test suite runs, this folder will be on the PYTHONPATH.
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed/main.m
+@@ -0,0 +1,16 @@
++//
++// main.m
++// tvOSTestbed
++//
++
++#import
++#import "AppDelegate.h"
++
++int main(int argc, char * argv[]) {
++ NSString * appDelegateClassName;
++ @autoreleasepool {
++ appDelegateClassName = NSStringFromClass([AppDelegate class]);
++
++ return UIApplicationMain(argc, argv, nil, appDelegateClassName);
++ }
++}
+--- /dev/null
++++ b/Apple/testbed/tvOSTestbed/tvOSTestbed-Info.plist
+@@ -0,0 +1,52 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleDisplayName
++ ${PRODUCT_NAME}
++ CFBundleExecutable
++ ${EXECUTABLE_NAME}
++ CFBundleIdentifier
++ org.python.tvOSTestbed
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ ${PRODUCT_NAME}
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ 1
++ LSRequiresIPhoneOS
++
++ UIRequiresFullScreen
++
++ UILaunchStoryboardName
++ Launch Screen
++ UISupportedInterfaceOrientations
++
++ UIInterfaceOrientationPortrait
++ UIInterfaceOrientationLandscapeLeft
++ UIInterfaceOrientationLandscapeRight
++
++ UISupportedInterfaceOrientations~ipad
++
++ UIInterfaceOrientationPortrait
++ UIInterfaceOrientationPortraitUpsideDown
++ UIInterfaceOrientationLandscapeLeft
++ UIInterfaceOrientationLandscapeRight
++
++ UIApplicationSceneManifest
++
++ UIApplicationSupportsMultipleScenes
++
++ UISceneConfigurations
++
++
++
++
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed.xcodeproj/project.pbxproj
+@@ -0,0 +1,558 @@
++// !$*UTF8*$!
++{
++ archiveVersion = 1;
++ classes = {
++ };
++ objectVersion = 56;
++ objects = {
++
++/* Begin PBXBuildFile section */
++ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66162B0EFA380010BFC8 /* AppDelegate.m */; };
++ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 607A66212B0EFA390010BFC8 /* Assets.xcassets */; };
++ 607A66282B0EFA390010BFC8 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66272B0EFA390010BFC8 /* main.m */; };
++ 607A66322B0EFA3A0010BFC8 /* TestbedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 607A66312B0EFA3A0010BFC8 /* TestbedTests.m */; };
++ 608619542CB77BA900F46182 /* app_packages in Resources */ = {isa = PBXBuildFile; fileRef = 608619532CB77BA900F46182 /* app_packages */; };
++ 608619562CB7819B00F46182 /* app in Resources */ = {isa = PBXBuildFile; fileRef = 608619552CB7819B00F46182 /* app */; };
++ EEB367CE2DADF5C900B9A1D7 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EEE9C80C2DAB5ECA0056F8C6 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
++ EEB367CF2DADF5D300B9A1D7 /* Python.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EEE9C80C2DAB5ECA0056F8C6 /* Python.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
++ EEE9C80D2DAB5ECA0056F8C6 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEE9C80C2DAB5ECA0056F8C6 /* Python.xcframework */; };
++ EEE9C80E2DAB5ECA0056F8C6 /* Python.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EEE9C80C2DAB5ECA0056F8C6 /* Python.xcframework */; };
++/* End PBXBuildFile section */
++
++/* Begin PBXContainerItemProxy section */
++ 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */ = {
++ isa = PBXContainerItemProxy;
++ containerPortal = 607A660A2B0EFA380010BFC8 /* Project object */;
++ proxyType = 1;
++ remoteGlobalIDString = 607A66112B0EFA380010BFC8;
++ remoteInfo = iOSTestbed;
++ };
++/* End PBXContainerItemProxy section */
++
++/* Begin PBXCopyFilesBuildPhase section */
++ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */ = {
++ isa = PBXCopyFilesBuildPhase;
++ buildActionMask = 2147483647;
++ dstPath = "";
++ dstSubfolderSpec = 10;
++ files = (
++ EEB367CF2DADF5D300B9A1D7 /* Python.xcframework in Embed Frameworks */,
++ );
++ name = "Embed Frameworks";
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */ = {
++ isa = PBXCopyFilesBuildPhase;
++ buildActionMask = 2147483647;
++ dstPath = "";
++ dstSubfolderSpec = 10;
++ files = (
++ EEB367CE2DADF5C900B9A1D7 /* Python.xcframework in Embed Frameworks */,
++ );
++ name = "Embed Frameworks";
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXCopyFilesBuildPhase section */
++
++/* Begin PBXFileReference section */
++ 6077B3D62E82E60C00E3D6A3 /* visionOSTestbed.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = visionOSTestbed.xctestplan; sourceTree = ""; };
++ 607A66122B0EFA380010BFC8 /* visionOSTestbed.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = visionOSTestbed.app; sourceTree = BUILT_PRODUCTS_DIR; };
++ 607A66152B0EFA380010BFC8 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
++ 607A66162B0EFA380010BFC8 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
++ 607A66212B0EFA390010BFC8 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
++ 607A66272B0EFA390010BFC8 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
++ 607A662D2B0EFA3A0010BFC8 /* TestbedTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestbedTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
++ 607A66312B0EFA3A0010BFC8 /* TestbedTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestbedTests.m; sourceTree = ""; };
++ 607A66592B0F08600010BFC8 /* visionOSTestbed-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "visionOSTestbed-Info.plist"; sourceTree = ""; };
++ 608619532CB77BA900F46182 /* app_packages */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app_packages; sourceTree = ""; };
++ 608619552CB7819B00F46182 /* app */ = {isa = PBXFileReference; lastKnownFileType = folder; path = app; sourceTree = ""; };
++ EEE9C80C2DAB5ECA0056F8C6 /* Python.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; path = Python.xcframework; sourceTree = ""; };
++/* End PBXFileReference section */
++
++/* Begin PBXFrameworksBuildPhase section */
++ 607A660F2B0EFA380010BFC8 /* Frameworks */ = {
++ isa = PBXFrameworksBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ EEE9C80D2DAB5ECA0056F8C6 /* Python.xcframework in Frameworks */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ 607A662A2B0EFA3A0010BFC8 /* Frameworks */ = {
++ isa = PBXFrameworksBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ EEE9C80E2DAB5ECA0056F8C6 /* Python.xcframework in Frameworks */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXFrameworksBuildPhase section */
++
++/* Begin PBXGroup section */
++ 607A66092B0EFA380010BFC8 = {
++ isa = PBXGroup;
++ children = (
++ 6077B3D62E82E60C00E3D6A3 /* visionOSTestbed.xctestplan */,
++ EEE9C80C2DAB5ECA0056F8C6 /* Python.xcframework */,
++ 607A66142B0EFA380010BFC8 /* visionOSTestbed */,
++ 607A66302B0EFA3A0010BFC8 /* TestbedTests */,
++ 607A66132B0EFA380010BFC8 /* Products */,
++ 607A664F2B0EFFE00010BFC8 /* Frameworks */,
++ );
++ sourceTree = "";
++ };
++ 607A66132B0EFA380010BFC8 /* Products */ = {
++ isa = PBXGroup;
++ children = (
++ 607A66122B0EFA380010BFC8 /* visionOSTestbed.app */,
++ 607A662D2B0EFA3A0010BFC8 /* TestbedTests.xctest */,
++ );
++ name = Products;
++ sourceTree = "";
++ };
++ 607A66142B0EFA380010BFC8 /* visionOSTestbed */ = {
++ isa = PBXGroup;
++ children = (
++ 608619552CB7819B00F46182 /* app */,
++ 608619532CB77BA900F46182 /* app_packages */,
++ 607A66592B0F08600010BFC8 /* visionOSTestbed-Info.plist */,
++ 607A66152B0EFA380010BFC8 /* AppDelegate.h */,
++ 607A66162B0EFA380010BFC8 /* AppDelegate.m */,
++ 607A66212B0EFA390010BFC8 /* Assets.xcassets */,
++ 607A66272B0EFA390010BFC8 /* main.m */,
++ );
++ path = visionOSTestbed;
++ sourceTree = "";
++ };
++ 607A66302B0EFA3A0010BFC8 /* TestbedTests */ = {
++ isa = PBXGroup;
++ children = (
++ 607A66312B0EFA3A0010BFC8 /* TestbedTests.m */,
++ );
++ path = TestbedTests;
++ sourceTree = "";
++ };
++ 607A664F2B0EFFE00010BFC8 /* Frameworks */ = {
++ isa = PBXGroup;
++ children = (
++ );
++ name = Frameworks;
++ sourceTree = "";
++ };
++/* End PBXGroup section */
++
++/* Begin PBXNativeTarget section */
++ 607A66112B0EFA380010BFC8 /* visionOSTestbed */ = {
++ isa = PBXNativeTarget;
++ buildConfigurationList = 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "visionOSTestbed" */;
++ buildPhases = (
++ 607A660E2B0EFA380010BFC8 /* Sources */,
++ 607A660F2B0EFA380010BFC8 /* Frameworks */,
++ 607A66102B0EFA380010BFC8 /* Resources */,
++ 607A66552B0F061D0010BFC8 /* Process Python libraries */,
++ 607A664E2B0EFC080010BFC8 /* Embed Frameworks */,
++ );
++ buildRules = (
++ );
++ dependencies = (
++ );
++ name = visionOSTestbed;
++ productName = iOSTestbed;
++ productReference = 607A66122B0EFA380010BFC8 /* visionOSTestbed.app */;
++ productType = "com.apple.product-type.application";
++ };
++ 607A662C2B0EFA3A0010BFC8 /* TestbedTests */ = {
++ isa = PBXNativeTarget;
++ buildConfigurationList = 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "TestbedTests" */;
++ buildPhases = (
++ 607A66292B0EFA3A0010BFC8 /* Sources */,
++ 607A662A2B0EFA3A0010BFC8 /* Frameworks */,
++ 607A662B2B0EFA3A0010BFC8 /* Resources */,
++ 607A66522B0EFFE00010BFC8 /* Embed Frameworks */,
++ );
++ buildRules = (
++ );
++ dependencies = (
++ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */,
++ );
++ name = TestbedTests;
++ productName = iOSTestbedTests;
++ productReference = 607A662D2B0EFA3A0010BFC8 /* TestbedTests.xctest */;
++ productType = "com.apple.product-type.bundle.unit-test";
++ };
++/* End PBXNativeTarget section */
++
++/* Begin PBXProject section */
++ 607A660A2B0EFA380010BFC8 /* Project object */ = {
++ isa = PBXProject;
++ attributes = {
++ BuildIndependentTargetsInParallel = 1;
++ LastUpgradeCheck = 1500;
++ TargetAttributes = {
++ 607A66112B0EFA380010BFC8 = {
++ CreatedOnToolsVersion = 15.0.1;
++ };
++ 607A662C2B0EFA3A0010BFC8 = {
++ CreatedOnToolsVersion = 15.0.1;
++ TestTargetID = 607A66112B0EFA380010BFC8;
++ };
++ };
++ };
++ buildConfigurationList = 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "visionOSTestbed" */;
++ compatibilityVersion = "Xcode 14.0";
++ developmentRegion = en;
++ hasScannedForEncodings = 0;
++ knownRegions = (
++ en,
++ Base,
++ );
++ mainGroup = 607A66092B0EFA380010BFC8;
++ productRefGroup = 607A66132B0EFA380010BFC8 /* Products */;
++ projectDirPath = "";
++ projectRoot = "";
++ targets = (
++ 607A66112B0EFA380010BFC8 /* visionOSTestbed */,
++ 607A662C2B0EFA3A0010BFC8 /* TestbedTests */,
++ );
++ };
++/* End PBXProject section */
++
++/* Begin PBXResourcesBuildPhase section */
++ 607A66102B0EFA380010BFC8 /* Resources */ = {
++ isa = PBXResourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ 608619562CB7819B00F46182 /* app in Resources */,
++ 607A66222B0EFA390010BFC8 /* Assets.xcassets in Resources */,
++ 608619542CB77BA900F46182 /* app_packages in Resources */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ 607A662B2B0EFA3A0010BFC8 /* Resources */ = {
++ isa = PBXResourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXResourcesBuildPhase section */
++
++/* Begin PBXShellScriptBuildPhase section */
++ 607A66552B0F061D0010BFC8 /* Process Python libraries */ = {
++ isa = PBXShellScriptBuildPhase;
++ alwaysOutOfDate = 1;
++ buildActionMask = 2147483647;
++ files = (
++ );
++ inputFileListPaths = (
++ );
++ inputPaths = (
++ );
++ name = "Process Python libraries";
++ outputFileListPaths = (
++ );
++ outputPaths = (
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ shellPath = /bin/sh;
++ shellScript = "set -e\n\nsource $PROJECT_DIR/Python.xcframework/build/utils.sh\n\ninstall_python Python.xcframework app app_packages\n";
++ showEnvVarsInLog = 0;
++ };
++/* End PBXShellScriptBuildPhase section */
++
++/* Begin PBXSourcesBuildPhase section */
++ 607A660E2B0EFA380010BFC8 /* Sources */ = {
++ isa = PBXSourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ 607A66172B0EFA380010BFC8 /* AppDelegate.m in Sources */,
++ 607A66282B0EFA390010BFC8 /* main.m in Sources */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++ 607A66292B0EFA3A0010BFC8 /* Sources */ = {
++ isa = PBXSourcesBuildPhase;
++ buildActionMask = 2147483647;
++ files = (
++ 607A66322B0EFA3A0010BFC8 /* TestbedTests.m in Sources */,
++ );
++ runOnlyForDeploymentPostprocessing = 0;
++ };
++/* End PBXSourcesBuildPhase section */
++
++/* Begin PBXTargetDependency section */
++ 607A662F2B0EFA3A0010BFC8 /* PBXTargetDependency */ = {
++ isa = PBXTargetDependency;
++ target = 607A66112B0EFA380010BFC8 /* visionOSTestbed */;
++ targetProxy = 607A662E2B0EFA3A0010BFC8 /* PBXContainerItemProxy */;
++ };
++/* End PBXTargetDependency section */
++
++/* Begin XCBuildConfiguration section */
++ 607A663F2B0EFA3A0010BFC8 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ALWAYS_SEARCH_USER_PATHS = NO;
++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
++ CLANG_ANALYZER_NONNULL = YES;
++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
++ CLANG_ENABLE_MODULES = YES;
++ CLANG_ENABLE_OBJC_ARC = YES;
++ CLANG_ENABLE_OBJC_WEAK = YES;
++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
++ CLANG_WARN_BOOL_CONVERSION = YES;
++ CLANG_WARN_COMMA = YES;
++ CLANG_WARN_CONSTANT_CONVERSION = YES;
++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
++ CLANG_WARN_EMPTY_BODY = YES;
++ CLANG_WARN_ENUM_CONVERSION = YES;
++ CLANG_WARN_INFINITE_RECURSION = YES;
++ CLANG_WARN_INT_CONVERSION = YES;
++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
++ CLANG_WARN_STRICT_PROTOTYPES = YES;
++ CLANG_WARN_SUSPICIOUS_MOVE = YES;
++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
++ CLANG_WARN_UNREACHABLE_CODE = YES;
++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
++ COPY_PHASE_STRIP = NO;
++ DEBUG_INFORMATION_FORMAT = dwarf;
++ ENABLE_STRICT_OBJC_MSGSEND = YES;
++ ENABLE_TESTABILITY = YES;
++ ENABLE_USER_SCRIPT_SANDBOXING = YES;
++ GCC_C_LANGUAGE_STANDARD = gnu17;
++ GCC_DYNAMIC_NO_PIC = NO;
++ GCC_NO_COMMON_BLOCKS = YES;
++ GCC_OPTIMIZATION_LEVEL = 0;
++ GCC_PREPROCESSOR_DEFINITIONS = (
++ "DEBUG=1",
++ "$(inherited)",
++ );
++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
++ GCC_WARN_UNDECLARED_SELECTOR = YES;
++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
++ GCC_WARN_UNUSED_FUNCTION = YES;
++ GCC_WARN_UNUSED_VARIABLE = YES;
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
++ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
++ MTL_FAST_MATH = YES;
++ ONLY_ACTIVE_ARCH = YES;
++ SDKROOT = xros;
++ };
++ name = Debug;
++ };
++ 607A66402B0EFA3A0010BFC8 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ALWAYS_SEARCH_USER_PATHS = NO;
++ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
++ CLANG_ANALYZER_NONNULL = YES;
++ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
++ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
++ CLANG_ENABLE_MODULES = YES;
++ CLANG_ENABLE_OBJC_ARC = YES;
++ CLANG_ENABLE_OBJC_WEAK = YES;
++ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
++ CLANG_WARN_BOOL_CONVERSION = YES;
++ CLANG_WARN_COMMA = YES;
++ CLANG_WARN_CONSTANT_CONVERSION = YES;
++ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
++ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
++ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
++ CLANG_WARN_EMPTY_BODY = YES;
++ CLANG_WARN_ENUM_CONVERSION = YES;
++ CLANG_WARN_INFINITE_RECURSION = YES;
++ CLANG_WARN_INT_CONVERSION = YES;
++ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
++ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
++ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
++ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
++ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
++ CLANG_WARN_STRICT_PROTOTYPES = YES;
++ CLANG_WARN_SUSPICIOUS_MOVE = YES;
++ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
++ CLANG_WARN_UNREACHABLE_CODE = YES;
++ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
++ COPY_PHASE_STRIP = NO;
++ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
++ ENABLE_NS_ASSERTIONS = NO;
++ ENABLE_STRICT_OBJC_MSGSEND = YES;
++ ENABLE_USER_SCRIPT_SANDBOXING = YES;
++ GCC_C_LANGUAGE_STANDARD = gnu17;
++ GCC_NO_COMMON_BLOCKS = YES;
++ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
++ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
++ GCC_WARN_UNDECLARED_SELECTOR = YES;
++ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
++ GCC_WARN_UNUSED_FUNCTION = YES;
++ GCC_WARN_UNUSED_VARIABLE = YES;
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
++ MTL_ENABLE_DEBUG_INFO = NO;
++ MTL_FAST_MATH = YES;
++ SDKROOT = xros;
++ VALIDATE_PRODUCT = YES;
++ };
++ name = Release;
++ };
++ 607A66422B0EFA3A0010BFC8 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ DEVELOPMENT_TEAM = "";
++ ENABLE_USER_SCRIPT_SANDBOXING = NO;
++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
++ INFOPLIST_FILE = "visionOSTestbed/visionOSTestbed-Info.plist";
++ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
++ INFOPLIST_KEY_UIMainStoryboardFile = Main;
++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
++ LD_RUNPATH_SEARCH_PATHS = (
++ "$(inherited)",
++ "@executable_path/Frameworks",
++ );
++ MARKETING_VERSION = 3.13.0a1;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.visionOSTestbed;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SUPPORTED_PLATFORMS = "xros xrsimulator";
++ SUPPORTS_MACCATALYST = NO;
++ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
++ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
++ SWIFT_EMIT_LOC_STRINGS = YES;
++ TARGETED_DEVICE_FAMILY = 7;
++ XROS_DEPLOYMENT_TARGET = 2.0;
++ };
++ name = Debug;
++ };
++ 607A66432B0EFA3A0010BFC8 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
++ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ DEVELOPMENT_TEAM = "";
++ ENABLE_TESTABILITY = YES;
++ ENABLE_USER_SCRIPT_SANDBOXING = NO;
++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
++ INFOPLIST_FILE = "visionOSTestbed/visionOSTestbed-Info.plist";
++ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
++ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
++ INFOPLIST_KEY_UIMainStoryboardFile = Main;
++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
++ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
++ LD_RUNPATH_SEARCH_PATHS = (
++ "$(inherited)",
++ "@executable_path/Frameworks",
++ );
++ MARKETING_VERSION = 3.13.0a1;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.visionOSTestbed;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SUPPORTED_PLATFORMS = "xros xrsimulator";
++ SUPPORTS_MACCATALYST = NO;
++ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
++ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
++ SWIFT_EMIT_LOC_STRINGS = YES;
++ TARGETED_DEVICE_FAMILY = 7;
++ XROS_DEPLOYMENT_TARGET = 2.0;
++ };
++ name = Release;
++ };
++ 607A66452B0EFA3A0010BFC8 /* Debug */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ BUNDLE_LOADER = "$(TEST_HOST)";
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ DEVELOPMENT_TEAM = 3HEZE76D99;
++ GENERATE_INFOPLIST_FILE = YES;
++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ MARKETING_VERSION = 1.0;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.TestbedTests;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SUPPORTED_PLATFORMS = "xros xrsimulator";
++ SUPPORTS_MACCATALYST = NO;
++ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
++ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
++ SWIFT_EMIT_LOC_STRINGS = NO;
++ TARGETED_DEVICE_FAMILY = 7;
++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/visionOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/visionOSTestbed";
++ };
++ name = Debug;
++ };
++ 607A66462B0EFA3A0010BFC8 /* Release */ = {
++ isa = XCBuildConfiguration;
++ buildSettings = {
++ BUNDLE_LOADER = "$(TEST_HOST)";
++ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO;
++ CODE_SIGN_STYLE = Automatic;
++ CURRENT_PROJECT_VERSION = 1;
++ DEVELOPMENT_TEAM = 3HEZE76D99;
++ GENERATE_INFOPLIST_FILE = YES;
++ HEADER_SEARCH_PATHS = "\"$(BUILT_PRODUCTS_DIR)/Python.framework/Headers\"";
++ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
++ MARKETING_VERSION = 1.0;
++ PRODUCT_BUNDLE_IDENTIFIER = org.python.TestbedTests;
++ PRODUCT_NAME = "$(TARGET_NAME)";
++ SUPPORTED_PLATFORMS = "xros xrsimulator";
++ SUPPORTS_MACCATALYST = NO;
++ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
++ SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
++ SWIFT_EMIT_LOC_STRINGS = NO;
++ TARGETED_DEVICE_FAMILY = 7;
++ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/visionOSTestbed.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/visionOSTestbed";
++ };
++ name = Release;
++ };
++/* End XCBuildConfiguration section */
++
++/* Begin XCConfigurationList section */
++ 607A660D2B0EFA380010BFC8 /* Build configuration list for PBXProject "visionOSTestbed" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ 607A663F2B0EFA3A0010BFC8 /* Debug */,
++ 607A66402B0EFA3A0010BFC8 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++ 607A66412B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "visionOSTestbed" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ 607A66422B0EFA3A0010BFC8 /* Debug */,
++ 607A66432B0EFA3A0010BFC8 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++ 607A66442B0EFA3A0010BFC8 /* Build configuration list for PBXNativeTarget "TestbedTests" */ = {
++ isa = XCConfigurationList;
++ buildConfigurations = (
++ 607A66452B0EFA3A0010BFC8 /* Debug */,
++ 607A66462B0EFA3A0010BFC8 /* Release */,
++ );
++ defaultConfigurationIsVisible = 0;
++ defaultConfigurationName = Release;
++ };
++/* End XCConfigurationList section */
++ };
++ rootObject = 607A660A2B0EFA380010BFC8 /* Project object */;
++}
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed.xcodeproj/xcshareddata/xcschemes/visionOSTestbed.xcscheme
+@@ -0,0 +1,97 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed.xctestplan
+@@ -0,0 +1,46 @@
++{
++ "configurations" : [
++ {
++ "id" : "C17FA044-0B70-48CA-AFF8-BC252081002F",
++ "name" : "Test Scheme Action",
++ "options" : {
++
++ }
++ }
++ ],
++ "defaultOptions" : {
++ "commandLineArgumentEntries" : [
++ {
++ "argument" : "test"
++ },
++ {
++ "argument" : "-uall"
++ },
++ {
++ "argument" : "--single-process"
++ },
++ {
++ "argument" : "--rerun"
++ },
++ {
++ "argument" : "-W"
++ }
++ ],
++ "targetForVariableExpansion" : {
++ "containerPath" : "container:visionOSTestbed.xcodeproj",
++ "identifier" : "607A66112B0EFA380010BFC8",
++ "name" : "visionOSTestbed"
++ }
++ },
++ "testTargets" : [
++ {
++ "parallelizable" : false,
++ "target" : {
++ "containerPath" : "container:visionOSTestbed.xcodeproj",
++ "identifier" : "607A662C2B0EFA3A0010BFC8",
++ "name" : "TestbedTests"
++ }
++ }
++ ],
++ "version" : 1
++}
+\ No newline at end of file
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed/AppDelegate.h
+@@ -0,0 +1,11 @@
++//
++// AppDelegate.h
++// visionOSTestbed
++//
++
++#import
++
++@interface AppDelegate : UIResponder
++
++
++@end
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed/AppDelegate.m
+@@ -0,0 +1,19 @@
++//
++// AppDelegate.m
++// visionOSTestbed
++//
++
++#import "AppDelegate.h"
++
++@interface AppDelegate ()
++
++@end
++
++@implementation AppDelegate
++
++
++- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
++ return YES;
++}
++
++@end
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed/Assets.xcassets/AccentColor.colorset/Contents.json
+@@ -0,0 +1,11 @@
++{
++ "colors" : [
++ {
++ "idiom" : "universal"
++ }
++ ],
++ "info" : {
++ "author" : "xcode",
++ "version" : 1
++ }
++}
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed/Assets.xcassets/AppIcon.appiconset/Contents.json
+@@ -0,0 +1,13 @@
++{
++ "images" : [
++ {
++ "idiom" : "universal",
++ "platform" : "ios",
++ "size" : "1024x1024"
++ }
++ ],
++ "info" : {
++ "author" : "xcode",
++ "version" : 1
++ }
++}
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed/Assets.xcassets/Contents.json
+@@ -0,0 +1,6 @@
++{
++ "info" : {
++ "author" : "xcode",
++ "version" : 1
++ }
++}
--- /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
++++ b/Apple/testbed/visionOSTestbed/app/README
+@@ -0,0 +1,7 @@
++This folder can contain any Python application code.
++
++During the build, any binary modules found in this folder will be processed into
++iOS Framework form.
++
++When the test suite runs, this folder will be on the PYTHONPATH, and will be the
++working directory for the test suite.
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed/app_packages/README
+@@ -0,0 +1,7 @@
++This folder can be a target for installing any Python dependencies needed by the
++test suite.
++
++During the build, any binary modules found in this folder will be processed into
++iOS Framework form.
++
++When the test suite runs, this folder will be on the PYTHONPATH.
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed/main.m
+@@ -0,0 +1,16 @@
++//
++// main.m
++// visionOSTestbed
++//
++
++#import
++#import "AppDelegate.h"
++
++int main(int argc, char * argv[]) {
++ NSString * appDelegateClassName;
++ @autoreleasepool {
++ appDelegateClassName = NSStringFromClass([AppDelegate class]);
++
++ return UIApplicationMain(argc, argv, nil, appDelegateClassName);
++ }
++}
+--- /dev/null
++++ b/Apple/testbed/visionOSTestbed/visionOSTestbed-Info.plist
+@@ -0,0 +1,56 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleDisplayName
++ ${PRODUCT_NAME}
++ CFBundleExecutable
++ ${EXECUTABLE_NAME}
++ CFBundleIdentifier
++ org.python.visionOSTestbed
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ ${PRODUCT_NAME}
++ CFBundlePackageType
++ APPL
++ CFBundleShortVersionString
++ 1.0
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ 1
++ TestArgs
++
++ test
++ -uall
++ --single-process
++ --rerun
++ -W
++
++ UIApplicationSceneManifest
++
++ UIApplicationSupportsMultipleScenes
++
++ UISceneConfigurations
++
++
++ UIRequiresFullScreen
++
++ UISupportedInterfaceOrientations
++
++ UIInterfaceOrientationPortrait
++ UIInterfaceOrientationLandscapeLeft
++ UIInterfaceOrientationLandscapeRight
++
++ UISupportedInterfaceOrientations~ipad
++
++ UIInterfaceOrientationPortrait
++ UIInterfaceOrientationPortraitUpsideDown
++ UIInterfaceOrientationLandscapeLeft
++ UIInterfaceOrientationLandscapeRight
++
++
++
+--- /dev/null
++++ b/Apple/tvOS/README.rst
+@@ -0,0 +1,108 @@
++=====================
++Python on tvOS README
++=====================
++
++:Authors:
++ Russell Keith-Magee (2023-11)
++
++This document provides a quick overview of some tvOS specific features in the
++Python distribution.
++
++Compilers for building on tvOS
++==============================
++
++Building for tvOS requires the use of Apple's Xcode tooling. It is strongly
++recommended that you use the most recent stable release of Xcode, on the
++most recently released macOS.
++
++tvOS specific arguments to configure
++===================================
++
++* ``--enable-framework[=DIR]``
++
++ This argument specifies the location where the Python.framework will
++ be installed.
++
++* ``--with-framework-name=NAME``
++
++ Specify the name for the python framework, defaults to ``Python``.
++
++
++Building and using Python on tvOS
++=================================
++
++ABIs and Architectures
++----------------------
++
++tvOS apps can be deployed on physical devices, and on the tvOS simulator.
++Although the API used on these devices is identical, the ABI is different - you
++need to link against different libraries for an tvOS device build
++(``appletvos``) or an tvOS simulator build (``appletvsimulator``). Apple uses
++the XCframework format to allow specifying a single dependency that supports
++multiple ABIs. An XCframework is a wrapper around multiple ABI-specific
++frameworks.
++
++tvOS can also support different CPU architectures within each ABI. At present,
++there is only a single support ed architecture on physical devices - ARM64.
++However, the *simulator* supports 2 architectures - ARM64 (for running on Apple
++Silicon machines), and x86_64 (for running on older Intel-based machines.)
++
++To support multiple CPU architectures on a single platform, Apple uses a "fat
++binary" format - a single physical file that contains support for multiple
++architectures.
++
++How do I build Python for tvOS?
++-------------------------------
++
++The Python build system will build a ``Python.framework`` that supports a
++*single* ABI with a *single* architecture. If you want to use Python in an tvOS
++project, you need to:
++
++1. Produce multiple ``Python.framework`` builds, one for each ABI and architecture;
++2. Merge the binaries for each architecture on a given ABI into a single "fat" binary;
++3. Merge the "fat" frameworks for each ABI into a single XCframework.
++
++tvOS builds of Python *must* be constructed as framework builds. To support this,
++you must provide the ``--enable-framework`` flag when configuring the build.
++
++The build also requires the use of cross-compilation. The commands for building
++Python for tvOS will look somethign like::
++
++ $ ./configure \
++ --enable-framework=/path/to/install \
++ --host=aarch64-apple-tvos \
++ --build=aarch64-apple-darwin \
++ --with-build-python=/path/to/python.exe
++ $ make
++ $ make install
++
++In this invocation:
++
++* ``/path/to/install`` is the location where the final Python.framework will be
++ output.
++
++* ``--host`` is the architecture and ABI that you want to build, in GNU compiler
++ triple format. This will be one of:
++
++ - ``aarch64-apple-tvos`` for ARM64 tvOS devices.
++ - ``aarch64-apple-tvos-simulator`` for the tvOS simulator running on Apple
++ Silicon devices.
++ - ``x86_64-apple-tvos-simulator`` for the tvOS simulator running on Intel
++ devices.
++
++* ``--build`` is the GNU compiler triple for the machine that will be running
++ the compiler. This is one of:
++
++ - ``aarch64-apple-darwin`` for Apple Silicon devices.
++ - ``x86_64-apple-darwin`` for Intel devices.
++
++* ``/path/to/python.exe`` is the path to a Python binary on the machine that
++ will be running the compiler. This is needed because the Python compilation
++ process involves running some Python code. On a normal desktop build of
++ Python, you can compile a python interpreter and then use that interpreter to
++ run Python code. However, the binaries produced for tvOS won't run on macOS, so
++ you need to provide an external Python interpreter. This interpreter must be
++ the version as the Python that is being compiled.
++
++Using a framework-based Python on tvOS
++======================================
+--- /dev/null
++++ b/Apple/tvOS/Resources/Info.plist.in
+@@ -0,0 +1,34 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++ Python
++ CFBundleGetInfoString
++ Python Runtime and Library
++ CFBundleIdentifier
++ @PYTHONFRAMEWORKIDENTIFIER@
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ Python
++ CFBundlePackageType
++ FMWK
++ CFBundleShortVersionString
++ %VERSION%
++ CFBundleLongVersionString
++ %VERSION%, (c) 2001-2024 Python Software Foundation.
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ 1
++ CFBundleSupportedPlatforms
++
++ tvOS
++
++ MinimumOSVersion
++ @TVOS_DEPLOYMENT_TARGET@
++
++
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvos${TVOS_SDK_VERSION} ar "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvos${TVOS_SDK_VERSION} clang -target arm64-apple-tvos${TVOS_DEPLOYMENT_TARGET} "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-clang++
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvos${TVOS_SDK_VERSION} clang++ -target arm64-apple-tvos${TVOS_DEPLOYMENT_TARGET} "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvos${TVOS_SDK_VERSION} clang -target arm64-apple-tvos${TVOS_DEPLOYMENT_TARGET} -E "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} ar "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target arm64-apple-tvos${TVOS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-simulator-clang++
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang++ -target arm64-apple-tvos${TVOS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target arm64-apple-tvos${TVOS_DEPLOYMENT_TARGET}-simulator -E "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-simulator-strip
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} strip -arch arm64 "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/arm64-apple-tvos-strip
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk iphoneos${TVOS_SDK_VERSION} strip -arch arm64 "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/x86_64-apple-tvos-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} ar "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/x86_64-apple-tvos-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target x86_64-apple-tvos${TVOS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/x86_64-apple-tvos-simulator-clang++
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang++ -target x86_64-apple-tvos${TVOS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/x86_64-apple-tvos-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} clang -target x86_64-apple-tvos${TVOS_DEPLOYMENT_TARGET}-simulator -E "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/bin/x86_64-apple-tvos-simulator-strip
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk appletvsimulator${TVOS_SDK_VERSION} strip -arch x86_64 "$@"
+--- /dev/null
++++ b/Apple/tvOS/Resources/pyconfig.h
+@@ -0,0 +1,7 @@
++#ifdef __arm64__
++#include "pyconfig-arm64.h"
++#endif
++
++#ifdef __x86_64__
++#include "pyconfig-x86_64.h"
++#endif
+--- /dev/null
++++ b/Apple/visionOS/Resources/Info.plist.in
+@@ -0,0 +1,34 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++ Python
++ CFBundleGetInfoString
++ Python Runtime and Library
++ CFBundleIdentifier
++ @PYTHONFRAMEWORKIDENTIFIER@
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ Python
++ CFBundlePackageType
++ FMWK
++ CFBundleShortVersionString
++ %VERSION%
++ CFBundleLongVersionString
++ %VERSION%, (c) 2001-2023 Python Software Foundation.
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ %VERSION%
++ CFBundleSupportedPlatforms
++
++ XROS
++
++ MinimumOSVersion
++ @XROS_DEPLOYMENT_TARGET@
++
++
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk xros${XROS_SDK_VERSION} ar "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk xros${XROS_SDK_VERSION} clang -target arm64-apple-xros${XROS_DEPLOYMENT_TARGET} "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-clang++
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk xros${XROS_SDK_VERSION} clang++ -target arm64-apple-xros${XROS_DEPLOYMENT_TARGET} "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk xros${XROS_SDK_VERSION} clang -target arm64-apple-xros${XROS_DEPLOYMENT_TARGET} -E "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk xrsimulator${XROS_SDK_VERSION} ar "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk xrsimulator${XROS_SDK_VERSION} clang -target arm64-apple-xros${XROS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-simulator-clang++
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk xrsimulator${XROS_SDK_VERSION} clang++ -target arm64-apple-xros${XROS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk xrsimulator${XROS_SDK_VERSION} clang -target arm64-apple-xros${XROS_DEPLOYMENT_TARGET}-simulator -E "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-simulator-strip
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk xrsimulator${XROS_SDK_VERSION} strip -arch arm64 "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/bin/arm64-apple-xros-strip
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk xros${XROS_SDK_VERSION} strip -arch arm64 "$@"
+--- /dev/null
++++ b/Apple/visionOS/Resources/pyconfig.h
+@@ -0,0 +1,3 @@
++#ifdef __arm64__
++#include "pyconfig-arm64.h"
++#endif
+--- /dev/null
++++ b/Apple/watchOS/README.rst
+@@ -0,0 +1,108 @@
++========================
++Python on watchOS README
++========================
++
++:Authors:
++ Russell Keith-Magee (2023-11)
++
++This document provides a quick overview of some watchOS specific features in the
++Python distribution.
++
++Compilers for building on watchOS
++=================================
++
++Building for watchOS requires the use of Apple's Xcode tooling. It is strongly
++recommended that you use the most recent stable release of Xcode, on the
++most recently released macOS.
++
++watchOS specific arguments to configure
++=======================================
++
++* ``--enable-framework[=DIR]``
++
++ This argument specifies the location where the Python.framework will
++ be installed.
+
++* ``--with-framework-name=NAME``
+
-+def get_platform_ios():
-+ objc = cdll.LoadLibrary(util.find_library(b'objc'))
++ Specify the name for the python framework, defaults to ``Python``.
+
-+ 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))
++Building and using Python on watchOS
++====================================
+
-+ SEL_systemVersion = c_void_p(objc.sel_registerName(b'systemVersion'))
-+ systemVersion = c_void_p(objc.objc_msgSend(device, SEL_systemVersion))
++ABIs and Architectures
++----------------------
+
-+ SEL_systemName = c_void_p(objc.sel_registerName(b'systemName'))
-+ systemName = c_void_p(objc.objc_msgSend(device, SEL_systemName))
++watchOS apps can be deployed on physical devices, and on the watchOS simulator.
++Although the API used on these devices is identical, the ABI is different - you
++need to link against different libraries for an watchOS device build
++(``watchos``) or an watchOS simulator build (``watchsimulator``). Apple uses the
++XCframework format to allow specifying a single dependency that supports
++multiple ABIs. An XCframework is a wrapper around multiple ABI-specific
++frameworks.
+
-+ SEL_model = c_void_p(objc.sel_registerName(b'model'))
-+ systemModel = c_void_p(objc.objc_msgSend(device, SEL_model))
++watchOS can also support different CPU architectures within each ABI. At present,
++there is only a single support ed architecture on physical devices - ARM64.
++However, the *simulator* supports 2 architectures - ARM64 (for running on Apple
++Silicon machines), and x86_64 (for running on older Intel-based machines.)
+
-+ # UTF8String returns a const char*;
-+ SEL_UTF8String = c_void_p(objc.sel_registerName(b'UTF8String'))
-+ objc.objc_msgSend.restype = c_char_p
++To support multiple CPU architectures on a single platform, Apple uses a "fat
++binary" format - a single physical file that contains support for multiple
++architectures.
+
-+ system = objc.objc_msgSend(systemName, SEL_UTF8String).decode()
-+ release = objc.objc_msgSend(systemVersion, SEL_UTF8String).decode()
-+ model = objc.objc_msgSend(systemModel, SEL_UTF8String).decode()
++How do I build Python for watchOS?
++-------------------------------
+
-+ return system, release, model
++The Python build system will build a ``Python.framework`` that supports a
++*single* ABI with a *single* architecture. If you want to use Python in an watchOS
++project, you need to:
++
++1. Produce multiple ``Python.framework`` builds, one for each ABI and architecture;
++2. Merge the binaries for each architecture on a given ABI into a single "fat" binary;
++3. Merge the "fat" frameworks for each ABI into a single XCframework.
++
++watchOS builds of Python *must* be constructed as framework builds. To support this,
++you must provide the ``--enable-framework`` flag when configuring the build.
++
++The build also requires the use of cross-compilation. The commands for building
++Python for watchOS will look somethign like::
++
++ $ ./configure \
++ --enable-framework=/path/to/install \
++ --host=aarch64-apple-watchos \
++ --build=aarch64-apple-darwin \
++ --with-build-python=/path/to/python.exe
++ $ make
++ $ make install
++
++In this invocation:
++
++* ``/path/to/install`` is the location where the final Python.framework will be
++ output.
++
++* ``--host`` is the architecture and ABI that you want to build, in GNU compiler
++ triple format. This will be one of:
++
++ - ``arm64_32-apple-watchos`` for ARM64-32 watchOS devices.
++ - ``aarch64-apple-watchos-simulator`` for the watchOS simulator running on Apple
++ Silicon devices.
++ - ``x86_64-apple-watchos-simulator`` for the watchOS simulator running on Intel
++ devices.
++
++* ``--build`` is the GNU compiler triple for the machine that will be running
++ the compiler. This is one of:
++
++ - ``aarch64-apple-darwin`` for Apple Silicon devices.
++ - ``x86_64-apple-darwin`` for Intel devices.
++
++* ``/path/to/python.exe`` is the path to a Python binary on the machine that
++ will be running the compiler. This is needed because the Python compilation
++ process involves running some Python code. On a normal desktop build of
++ Python, you can compile a python interpreter and then use that interpreter to
++ run Python code. However, the binaries produced for watchOS won't run on macOS, so
++ you need to provide an external Python interpreter. This interpreter must be
++ the version as the Python that is being compiled.
++
++Using a framework-based Python on watchOS
++======================================
+--- /dev/null
++++ b/Apple/watchOS/Resources/Info.plist.in
+@@ -0,0 +1,34 @@
++
++
++
++
++ CFBundleDevelopmentRegion
++ en
++ CFBundleExecutable
++ Python
++ CFBundleGetInfoString
++ Python Runtime and Library
++ CFBundleIdentifier
++ @PYTHONFRAMEWORKIDENTIFIER@
++ CFBundleInfoDictionaryVersion
++ 6.0
++ CFBundleName
++ Python
++ CFBundlePackageType
++ FMWK
++ CFBundleShortVersionString
++ %VERSION%
++ CFBundleLongVersionString
++ %VERSION%, (c) 2001-2023 Python Software Foundation.
++ CFBundleSignature
++ ????
++ CFBundleVersion
++ %VERSION%
++ CFBundleSupportedPlatforms
++
++ watchOS
++
++ MinimumOSVersion
++ @WATCHOS_DEPLOYMENT_TARGET@
++
++
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64-apple-watchos-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} ar "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64-apple-watchos-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target arm64-apple-watchos${WATCHOS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64-apple-watchos-simulator-clang++
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang++ -target arm64-apple-watchos${WATCHOS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64-apple-watchos-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator clang -target arm64-apple-watchos${WATCHOS_DEPLOYMENT_TARGET}-simulator -E "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64-apple-watchos-simulator-strip
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} strip -arch arm64 "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64-apple-watchos-strip
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk watchos${WATCHOS_SDK_VERSION} strip -arch arm64 "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64_32-apple-watchos-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchos${WATCHOS_SDK_VERSION} ar "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64_32-apple-watchos-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchos${WATCHOS_SDK_VERSION} clang -target arm64_32-apple-watchos${WATCHOS_DEPLOYMENT_TARGET} "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64_32-apple-watchos-clang++
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchos${WATCHOS_SDK_VERSION} clang++ -target arm64_32-apple-watchos${WATCHOS_DEPLOYMENT_TARGET} "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/arm64_32-apple-watchos-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchos${WATCHOS_SDK_VERSION} clang -target arm64_32-apple-watchos${WATCHOS_DEPLOYMENT_TARGET} -E "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/x86_64-apple-watchos-simulator-ar
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} ar "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/x86_64-apple-watchos-simulator-clang
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target x86_64-apple-watchos${WATCHOS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/x86_64-apple-watchos-simulator-clang++
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang++ -target x86_64-apple-watchos${WATCHOS_DEPLOYMENT_TARGET}-simulator "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/x86_64-apple-watchos-simulator-cpp
+@@ -0,0 +1,2 @@
++#!/bin/bash
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} clang -target x86_64-apple-watchos${WATCHOS_DEPLOYMENT_TARGET}-simulator -E "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/bin/x86_64-apple-watchos-simulator-strip
+@@ -0,0 +1,2 @@
++#!/bin/sh
++xcrun --sdk watchsimulator${WATCHOS_SDK_VERSION} strip -arch x86_64 "$@"
+--- /dev/null
++++ b/Apple/watchOS/Resources/pyconfig.h
+@@ -0,0 +1,11 @@
++#ifdef __arm64__
++# ifdef __LP64__
++#include "pyconfig-arm64.h"
++# else
++#include "pyconfig-arm64_32.h"
++# endif
++#endif
++
++#ifdef __x86_64__
++#include "pyconfig-x86_64.h"
++#endif
+diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py
+index 04ec0270148..cd14815a3bf 100644
+--- a/Lib/ctypes/__init__.py
++++ b/Lib/ctypes/__init__.py
+@@ -452,9 +452,9 @@
+
+ else:
+ def _load_library(self, name, mode, handle, winmode):
+- # If the filename that has been provided is an iOS/tvOS/watchOS
+- # .fwork file, dereference the location to the true origin of the
+- # binary.
++ # If the filename that has been provided is an iOS, tvOS, visionOS
++ # or watchOS .fwork file, dereference the location to the true
++ # origin of the binary.
+ if name and name.endswith(".fwork"):
+ with open(name) as f:
+ name = _os.path.join(
diff --git a/Lib/ctypes/util.py b/Lib/ctypes/util.py
-index 0c2510e161..6c3c43f11d 100644
+index 378f12167c6..591c69adfb7 100644
--- a/Lib/ctypes/util.py
+++ b/Lib/ctypes/util.py
-@@ -67,7 +67,7 @@
- return fname
- return None
+@@ -126,7 +126,7 @@
+ if (name := _get_module_filename(h)) is not None]
+ return libraries
--elif os.name == "posix" and sys.platform == "darwin":
-+elif os.name == "posix" and sys.platform in ('darwin', 'ios', 'tvos', 'watchos'):
+-elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "watchos"}:
++elif os.name == "posix" and sys.platform in {"darwin", "ios", "tvos", "visionos", "watchos"}:
from ctypes.macholib.dyld import dyld_find as _dyld_find
def find_library(name):
possible = ['lib%s.dylib' % name,
-diff --git a/Lib/distutils/tests/test_cygwinccompiler.py b/Lib/distutils/tests/test_cygwinccompiler.py
-index 0912ffd15c..959aa90522 100644
---- a/Lib/distutils/tests/test_cygwinccompiler.py
-+++ b/Lib/distutils/tests/test_cygwinccompiler.py
-@@ -5,11 +5,14 @@
- from io import BytesIO
- from test.support import run_unittest
-
--from distutils import cygwinccompiler
--from distutils.cygwinccompiler import (check_config_h,
-- CONFIG_H_OK, CONFIG_H_NOTOK,
-- CONFIG_H_UNCERTAIN, get_versions,
-- get_msvcr)
-+# Importing cygwinccompiler attempts to import other tools
-+# that may not exist unless you're on win32.
-+if sys.platform == 'win32':
-+ from distutils import cygwinccompiler
-+ from distutils.cygwinccompiler import (check_config_h,
-+ CONFIG_H_OK, CONFIG_H_NOTOK,
-+ CONFIG_H_UNCERTAIN, get_versions,
-+ get_msvcr)
- from distutils.tests import support
-
- class FakePopen(object):
-@@ -25,6 +28,7 @@
- self.stdout = os.popen(cmd, 'r')
-
-
-+@unittest.skipUnless(sys.platform == "win32", "These tests are only for win32")
- class CygwinCCompilerTestCase(support.TempdirManager,
- unittest.TestCase):
-
-diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py
-index d00c48981e..5d12b4779d 100644
---- a/Lib/distutils/unixccompiler.py
-+++ b/Lib/distutils/unixccompiler.py
-@@ -270,9 +270,9 @@
- static_f = self.library_filename(lib, lib_type='static')
-
- if sys.platform == 'darwin':
-- # On OSX users can specify an alternate SDK using
-- # '-isysroot', calculate the SDK root if it is specified
-- # (and use it further on)
-+ # On macOS users can specify an alternate SDK using
-+ # '-isysroot ' or --sysroot=, calculate the SDK root
-+ # if it is specified (and use it further on)
- #
- # Note that, as of Xcode 7, Apple SDKs may contain textual stub
- # libraries with .tbd extensions rather than the normal .dylib
-@@ -291,12 +291,14 @@
- cflags = sysconfig.get_config_var('CFLAGS')
- m = re.search(r'-isysroot\s*(\S+)', cflags)
- if m is None:
-- sysroot = _osx_support._default_sysroot(sysconfig.get_config_var('CC'))
-+ m = re.search(r'--sysroot=(\S+)', cflags)
-+ if m is None:
-+ sysroot = _osx_support._default_sysroot(sysconfig.get_config_var('CC'))
-+ else:
-+ sysroot = m.group(1)
- else:
- sysroot = m.group(1)
+@@ -444,7 +444,7 @@
+ # https://man.openbsd.org/dl_iterate_phdr
+ # https://docs.oracle.com/cd/E88353_01/html/E37843/dl-iterate-phdr-3c.html
+ if (os.name == "posix" and
+- sys.platform not in {"darwin", "ios", "tvos", "watchos"}):
++ sys.platform not in {"darwin", "ios", "tvos", "watchos", "visionos"}):
+ import ctypes
+ if hasattr((_libc := ctypes.CDLL(None)), "dl_iterate_phdr"):
--
--
- for dir in dirs:
- shared = os.path.join(dir, shared_f)
- dylib = os.path.join(dir, dylib_f)
-diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py
-index 2ce5c5b64d..6e10a0c4a5 100644
---- a/Lib/distutils/util.py
-+++ b/Lib/distutils/util.py
-@@ -170,7 +170,7 @@
- if _environ_checked:
- return
-
-- if os.name == 'posix' and 'HOME' not in os.environ:
-+ if os.name == 'posix' and 'HOME' not in os.environ and sys.platform not in ('ios', 'tvos', 'watchos'):
- try:
- import pwd
- os.environ['HOME'] = pwd.getpwuid(os.getuid())[5]
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
-index f603a89f7f..faea51d1b5 100644
+index 95ce14b2c39..dd6eb6489b9 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -52,7 +52,7 @@
# Bootstrap-related code ######################################################
_CASE_INSENSITIVE_PLATFORMS_STR_KEY = 'win',
--_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin'
-+_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos'
+-_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'watchos'
++_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY = 'cygwin', 'darwin', 'ios', 'tvos', 'visionos', 'watchos'
_CASE_INSENSITIVE_PLATFORMS = (_CASE_INSENSITIVE_PLATFORMS_BYTES_KEY
+ _CASE_INSENSITIVE_PLATFORMS_STR_KEY)
+@@ -1538,7 +1538,7 @@
+ """
+ extension_loaders = []
+ if hasattr(_imp, 'create_dynamic'):
+- if sys.platform in {"ios", "tvos", "watchos"}:
++ if sys.platform in {"ios", "tvos", "visionos", "watchos"}:
+ extension_loaders = [(AppleFrameworkLoader, [
+ suffix.replace(".so", ".fwork")
+ for suffix in _imp.extension_suffixes()
diff --git a/Lib/platform.py b/Lib/platform.py
-index c272c407c7..1b1aa6d141 100755
+index b017b841311..c8c794199f3 100644
--- a/Lib/platform.py
+++ b/Lib/platform.py
-@@ -451,6 +451,35 @@
- # 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, model). All tuple entries are strings.
-+
-+ Equivalent of:
-+ system = [[UIDevice currentDevice].systemName] UTF8String]
-+ release = [[UIDevice currentDevice].systemVersion] UTF8String]
-+ model = [[UIDevice currentDevice].model] UTF8String]
+@@ -539,6 +539,78 @@
+ return IOSVersionInfo(system, release, model, is_simulator)
+
+
++# A namedtuple for tvOS version information.
++TVOSVersionInfo = collections.namedtuple(
++ "TVOSVersionInfo",
++ ["system", "release", "model", "is_simulator"]
++)
++
++
++def tvos_ver(system="", release="", model="", is_simulator=False):
++ """Get tvOS version information, and return it as a namedtuple:
++ (system, release, model, is_simulator).
++
++ If values can't be determined, they are set to values provided as
++ parameters.
+ """
-+ import _ios_support
-+ return _ios_support.get_platform_ios()
++ if sys.platform == "tvos":
++ # TODO: Can the iOS implementation be used here?
++ import _ios_support
++ result = _ios_support.get_platform_ios()
++ if result is not None:
++ return TVOSVersionInfo(*result)
+
-+def is_simulator():
-+ """Determine if the current platform is a device simulator.
++ return TVOSVersionInfo(system, release, model, is_simulator)
+
-+ Only useful when working with iOS, tvOS or watchOS, because
-+ Apple provides simulator platforms for those devices.
+
-+ If the platform is actual hardware, returns False. Will also
-+ return False for device *emulators*, which are indistinguishable
-+ from actual devices because they are reproducing actual device
-+ properties.
++# A namedtuple for watchOS version information.
++WatchOSVersionInfo = collections.namedtuple(
++ "WatchOSVersionInfo",
++ ["system", "release", "model", "is_simulator"]
++)
++
++
++def watchos_ver(system="", release="", model="", is_simulator=False):
++ """Get watchOS version information, and return it as a namedtuple:
++ (system, release, model, is_simulator).
++
++ If values can't be determined, they are set to values provided as
++ parameters.
+ """
-+ if sys.platform in ('ios', 'tvos', 'watchos'):
-+ return sys.implementation._multiarch.endswith('simulator')
++ if sys.platform == "watchos":
++ # TODO: Can the iOS implementation be used here?
++ import _ios_support
++ result = _ios_support.get_platform_ios()
++ if result is not None:
++ return WatchOSVersionInfo(*result)
++
++ return WatchOSVersionInfo(system, release, model, is_simulator)
++
++
++# A namedtuple for visionOS version information.
++VisionOSVersionInfo = collections.namedtuple(
++ "VisionOSVersionInfo",
++ ["system", "release", "model", "is_simulator"]
++)
++
++
++def visionos_ver(system="", release="", model="", is_simulator=False):
++ """Get visionOS version information, and return it as a namedtuple:
++ (system, release, model, is_simulator).
++
++ If values can't be determined, they are set to values provided as
++ parameters.
++ """
++ if sys.platform == "visionos":
++ # TODO: Can the iOS implementation be used here?
++ import _ios_support
++ result = _ios_support.get_platform_ios()
++ if result is not None:
++ return VisionOSVersionInfo(*result)
++
++ return VisionOSVersionInfo(system, release, model, is_simulator)
+
-+ # All other platforms aren't simulators.
-+ return False
+
def _java_getprop(name, default):
-
+ """This private helper is deprecated in 3.13 and will be removed in 3.15"""
from java.lang import System
-@@ -607,7 +636,7 @@
+@@ -738,7 +810,7 @@
default in case the command should fail.
"""
-- if sys.platform in ('dos', 'win32', 'win16'):
-+ if sys.platform in ('dos', 'win32', 'win16', 'ios', 'tvos', 'watchos'):
+- if sys.platform in {'dos', 'win32', 'win16', 'ios', 'tvos', 'watchos'}:
++ if sys.platform in {'dos', 'win32', 'win16', 'ios', 'tvos', 'visionos', 'watchos'}:
# XXX Others too ?
return default
-@@ -749,6 +778,24 @@
+@@ -902,14 +974,30 @@
csid, cpu_number = vms_lib.getsyi('SYI$_CPU', 0)
return 'Alpha' if cpu_number >= 128 else 'VAX'
-+ # On iOS, tvOS and watchOS, os.uname returns the architecture
-+ # as uname.machine. On device it doesn't; but there's only
-+ # on CPU architecture on device
-+ def get_ios():
-+ if sys.implementation._multiarch.endswith('simulator'):
+- # On the iOS simulator, os.uname returns the architecture as uname.machine.
+- # On device it returns the model name for some reason; but there's only one
+- # CPU architecture for iOS devices, so we know the right answer.
++ # On the iOS/tvOS/visionOS/watchOS simulator, os.uname returns the
++ # architecture as uname.machine. On device it returns the model name for
++ # some reason; but there's only one CPU architecture for devices, so we know
++ # the right answer.
+ def get_ios():
+ if sys.implementation._multiarch.endswith("simulator"):
+ return os.uname().machine
+ return 'arm64'
+
++ def get_tvos():
++ if sys.implementation._multiarch.endswith("simulator"):
+ return os.uname().machine
+ return 'arm64'
+
-+ def get_tvos():
-+ if sys.implementation._multiarch.endswith('simulator'):
++ def get_visionos():
++ if sys.implementation._multiarch.endswith("simulator"):
+ return os.uname().machine
+ return 'arm64'
+
+ def get_watchos():
-+ if sys.implementation._multiarch.endswith('simulator'):
++ if sys.implementation._multiarch.endswith("simulator"):
+ return os.uname().machine
+ return 'arm64_32'
+
def from_subprocess():
"""
Fall back to `uname -p`
-@@ -900,6 +947,14 @@
- system = 'Windows'
- release = 'Vista'
+@@ -1069,9 +1157,15 @@
+ system = 'Android'
+ release = android_ver().release
+- # Normalize responses on iOS
+ # Normalize responses on Apple mobile platforms
-+ if sys.platform in ('ios', 'tvos'):
-+ system, release, model = iOS_ver()
-+ # 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'
-+
+ if sys.platform == 'ios':
+ system, release, _, _ = ios_ver()
++ if sys.platform == 'tvos':
++ system, release, _, _ = tvos_ver()
++ if sys.platform == 'visionos':
++ system, release, _, _ = visionos_ver()
++ if sys.platform == 'watchos':
++ system, release, _, _ = watchos_ver()
+
vals = system, node, release, version, machine
# Replace 'unknown' values with the more portable ''
- _uname_cache = uname_result(*map(_unknown_as_blank, vals))
-@@ -1212,11 +1267,13 @@
- system, release, version = system_alias(system, release, version)
-
- if system == 'Darwin':
-- # macOS (darwin kernel)
-- macos_release = mac_ver()[0]
-- if macos_release:
-- system = 'macOS'
-- release = macos_release
-+ if sys.platform in ('ios', 'tvos'):
-+ system, release, model = iOS_ver()
-+ else:
-+ macos_release = mac_ver()[0]
-+ if macos_release:
-+ system = 'macOS'
-+ release = macos_release
-
- if system == 'Windows':
- # MS platforms
+@@ -1361,6 +1455,12 @@
+ # macOS and iOS both report as a "Darwin" kernel
+ if sys.platform == "ios":
+ system, release, _, _ = ios_ver()
++ elif sys.platform == "tvos":
++ system, release, _, _ = tvos_ver()
++ elif sys.platform == "visionos":
++ system, release, _, _ = visionos_ver()
++ elif sys.platform == "watchos":
++ system, release, _, _ = watchos_ver()
+ else:
+ macos_release = mac_ver()[0]
+ if macos_release:
diff --git a/Lib/site.py b/Lib/site.py
-index 69670d9d7f..8287267e64 100644
+index aeb7c6cfc71..3fa222ea148 100644
--- a/Lib/site.py
+++ b/Lib/site.py
-@@ -294,6 +294,9 @@
-
- if sys.platform == 'darwin' and sys._framework:
- return f'{userbase}/lib/python/site-packages'
-+ elif sys.platform in ('ios', 'tvos', 'watchos'):
-+ from sysconfig import get_path
-+ return get_path('purelib', sys.platform)
-
- return f'{userbase}/lib/python{version[0]}.{version[1]}/site-packages'
+@@ -298,8 +298,8 @@
+ if env_base:
+ return env_base
+
+- # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories
+- if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
++ # Emscripten, iOS, tvOS, visionOS, VxWorks, WASI, and watchOS have no home directories
++ if sys.platform in {"emscripten", "ios", "tvos", "vxworks", "visionos", "wasi", "watchos"}:
+ return None
+ def joinuser(*args):
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
-index 7ae8df154b..08899c9921 100644
+index 6911cd8e859..164204de8ac 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
-@@ -74,8 +74,8 @@
- else:
+@@ -75,7 +75,7 @@
_mswindows = True
--# wasm32-emscripten and wasm32-wasi do not support processes
--_can_fork_exec = sys.platform not in {"emscripten", "wasi"}
-+# some platforms do not support processes
-+_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos"}
+ # some platforms do not support subprocesses
+-_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "watchos"}
++_can_fork_exec = sys.platform not in {"emscripten", "wasi", "ios", "tvos", "visionos", "watchos"}
if _mswindows:
import _winapi
-diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py
-index ebe3711827..ea00c3176d 100644
---- a/Lib/sysconfig.py
-+++ b/Lib/sysconfig.py
-@@ -95,6 +95,33 @@
- 'scripts': '{base}/Scripts',
- 'data': '{base}',
- },
-+ 'ios': {
-+ 'stdlib': '{installed_base}/lib/python%s' % sys.version[:3],
-+ 'platstdlib': '{installed_base}/lib/python%s' % sys.version[:3],
-+ 'purelib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3],
-+ 'platlib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3],
-+ 'include': '{installed_base}/include',
-+ 'scripts': '{installed_base}/bin',
-+ 'data': '{installed_base}/Resources',
-+ },
-+ 'tvos': {
-+ 'stdlib': '{installed_base}/lib/python%s' % sys.version[:3],
-+ 'platstdlib': '{installed_base}/lib/python%s' % sys.version[:3],
-+ 'purelib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3],
-+ 'platlib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3],
-+ 'include': '{installed_base}/include',
-+ 'scripts': '{installed_base}/bin',
-+ 'data': '{installed_base}/Resources',
-+ },
-+ 'watchos': {
-+ 'stdlib': '{installed_base}/lib/python%s' % sys.version[:3],
-+ 'platstdlib': '{installed_base}/lib/python%s' % sys.version[:3],
-+ 'purelib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3],
-+ 'platlib': '{installed_base}/lib/python%s/site-packages' % sys.version[:3],
-+ 'include': '{installed_base}/include',
-+ 'scripts': '{installed_base}/bin',
-+ 'data': '{installed_base}/Resources',
-+ },
- }
-
- # For the OS-native venv scheme, we essentially provide an alias:
-@@ -283,12 +310,19 @@
- 'home': 'posix_home',
- 'user': 'nt_user',
- }
-+ if sys.platform in ('ios', 'tvos', 'watchos'):
-+ return {
-+ 'prefix': sys.platform,
-+ 'home': sys.platform,
-+ 'user': sys.platform,
-+ }
- if sys.platform == 'darwin' and sys._framework:
- return {
- 'prefix': 'posix_prefix',
- 'home': 'posix_home',
- 'user': 'osx_framework_user',
- }
-+
- return {
- 'prefix': 'posix_prefix',
- 'home': 'posix_home',
-@@ -788,10 +822,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)
+diff --git a/Lib/sysconfig/__init__.py b/Lib/sysconfig/__init__.py
+index 2ecbff222fe..542d3f21cae 100644
+--- a/Lib/sysconfig/__init__.py
++++ b/Lib/sysconfig/__init__.py
+@@ -23,6 +23,9 @@
+ _ALWAYS_STR = {
+ 'IPHONEOS_DEPLOYMENT_TARGET',
+ 'MACOSX_DEPLOYMENT_TARGET',
++ 'TVOS_DEPLOYMENT_TARGET',
++ 'WATCHOS_DEPLOYMENT_TARGET',
++ 'XROS_DEPLOYMENT_TARGET',
+ }
- return f"{osname}-{release}-{machine}"
+ _INSTALL_SCHEMES = {
+@@ -119,7 +122,7 @@
+ # Emscripten, iOS, tvOS, VxWorks, WASI, and watchOS have no home directories.
+ # Use _PYTHON_HOST_PLATFORM to get the correct platform when cross-compiling.
+ system_name = os.environ.get('_PYTHON_HOST_PLATFORM', sys.platform).split('-')[0]
+- if system_name in {"emscripten", "ios", "tvos", "vxworks", "wasi", "watchos"}:
++ if system_name in {"emscripten", "ios", "tvos", "visionos", "vxworks", "wasi", "watchos"}:
+ return None
+ def joinuser(*args):
+@@ -734,6 +737,18 @@
+ release = get_config_vars().get("IPHONEOS_DEPLOYMENT_TARGET", "13.0")
+ osname = sys.platform
+ machine = sys.implementation._multiarch
++ elif sys.platform == "tvos":
++ release = get_config_vars().get("TVOS_DEPLOYMENT_TARGET", "12.0")
++ osname = sys.platform
++ machine = sys.implementation._multiarch
++ elif sys.platform == "watchos":
++ release = get_config_vars().get("WATCHOS_DEPLOYMENT_TARGET", "4.0")
++ osname = sys.platform
++ machine = sys.implementation._multiarch
++ elif sys.platform == "visionos":
++ release = get_config_vars().get("XROS_DEPLOYMENT_TARGET", "2.0")
++ osname = sys.platform
++ machine = sys.implementation._multiarch
+ else:
+ import _osx_support
+ osname, release, machine = _osx_support.get_platform_osx(
+diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
+index 0540f94fe93..52037e48722 100644
+--- a/Lib/test/datetimetester.py
++++ b/Lib/test/datetimetester.py
+@@ -7165,9 +7165,9 @@
+ self.assertEqual(dt_orig, dt_rt)
+
+ def test_type_check_in_subinterp(self):
+- # iOS requires the use of the custom framework loader,
++ # Apple mobile platforms require the use of the custom framework loader,
+ # not the ExtensionFileLoader.
+- if sys.platform == "ios":
++ if support.is_apple_mobile:
+ extension_loader = "AppleFrameworkLoader"
+ else:
+ extension_loader = "ExtensionFileLoader"
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
-index 46087a98a2..ea8c228f65 100644
+index da72b0c7dab..6da12ff86f6 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
-@@ -47,7 +47,7 @@
- "check__all__", "skip_if_buggy_ucrt_strfptime",
- "check_disallow_instantiation", "check_sanitizer", "skip_if_sanitizer",
- # sys
-- "is_jython", "is_android", "is_emscripten", "is_wasi",
-+ "is_jython", "is_android", "is_emscripten", "is_wasi", "is_apple_mobile",
- "check_impl_detail", "unix_shell", "setswitchinterval",
- # network
- "open_urlresource",
-@@ -507,7 +507,7 @@
-
- is_android = hasattr(sys, 'getandroidapilevel')
-
--if sys.platform not in ('win32', 'vxworks'):
-+if sys.platform not in ('win32', 'vxworks', 'ios', 'tvos', 'watchos'):
+@@ -573,7 +573,7 @@
+ sys.platform == "android", f"Android blocks {name} with SELinux"
+ )
+
+-if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos"}:
++if sys.platform not in {"win32", "vxworks", "ios", "tvos", "visionos", "watchos"}:
unix_shell = '/system/bin/sh' if is_android else '/bin/sh'
else:
unix_shell = None
-@@ -517,12 +517,25 @@
- is_emscripten = sys.platform == "emscripten"
- is_wasi = sys.platform == "wasi"
-
--has_fork_support = hasattr(os, "fork") and not is_emscripten and not is_wasi
-+# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not
-+# have subprocess or fork support.
-+is_apple_mobile = sys.platform in ('ios', 'tvos', 'watchos')
-+
-+has_fork_support = (
-+ hasattr(os, "fork")
-+ and not is_emscripten
-+ and not is_wasi
-+ and not is_apple_mobile
-+)
-
- def requires_fork():
- return unittest.skipUnless(has_fork_support, "requires working os.fork()")
-
--has_subprocess_support = not is_emscripten and not is_wasi
-+has_subprocess_support = (
-+ not is_emscripten
-+ and not is_wasi
-+ and not is_apple_mobile
-+)
-
- def requires_subprocess():
- """Used for subprocess, os.spawn calls, fd inheritance"""
-diff --git a/Lib/test/test_asyncio/test_events.py b/Lib/test/test_asyncio/test_events.py
-index 05d9107b28..6df2bcf163 100644
---- a/Lib/test/test_asyncio/test_events.py
-+++ b/Lib/test/test_asyncio/test_events.py
-@@ -33,6 +33,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
- from test.support import socket_helper
- from test.support import threading_helper
- from test.support import ALWAYS_EQ, LARGEST, SMALLEST
-@@ -542,6 +543,7 @@
- self._basetest_create_connection(conn_fut)
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_connection(self):
- # Issue #20682: On Mac OS X Tiger, getsockname() returns a
- # zero-length address for UNIX socket.
-@@ -634,6 +636,7 @@
- self.assertEqual(cm.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
-
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_ssl_connection(self):
- with test_utils.run_test_server(use_ssl=True) as httpd:
- create_connection = functools.partial(
-@@ -645,6 +648,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_ssl_unix_connection(self):
- # Issue #20682: On Mac OS X Tiger, getsockname() returns a
- # zero-length address for UNIX socket.
-@@ -860,6 +864,7 @@
- return server, path
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server(self):
- proto = MyProto(loop=self.loop)
- server, path = self._make_unix_server(lambda: proto)
-@@ -888,6 +893,7 @@
- server.close()
-
- @unittest.skipUnless(hasattr(socket, 'AF_UNIX'), 'No UNIX Sockets')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server_path_socket_error(self):
- proto = MyProto(loop=self.loop)
- sock = socket.socket()
-@@ -953,6 +959,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server_ssl(self):
- proto = MyProto(loop=self.loop)
- server, path = self._make_ssl_unix_server(
-@@ -983,6 +990,7 @@
- server.close()
-
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_server_ssl_verify_failed(self):
- proto = MyProto(loop=self.loop)
- server, host, port = self._make_ssl_server(
-@@ -1013,6 +1021,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server_ssl_verify_failed(self):
- proto = MyProto(loop=self.loop)
- server, path = self._make_ssl_unix_server(
-@@ -1073,6 +1082,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_create_unix_server_ssl_verified(self):
- proto = MyProto(loop=self.loop)
- server, path = self._make_ssl_unix_server(
-diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py
-index 0c49099bc4..c972bade4b 100644
---- a/Lib/test/test_asyncio/test_streams.py
-+++ b/Lib/test/test_asyncio/test_streams.py
-@@ -17,6 +17,7 @@
-
- import asyncio
- from test.test_asyncio import utils as test_utils
-+from test.support import is_apple_mobile
-
-
- def tearDownModule():
-@@ -60,6 +61,7 @@
- self._basetest_open_connection(conn_fut)
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_open_unix_connection(self):
- with test_utils.run_test_unix_server() as httpd:
- conn_fut = asyncio.open_unix_connection(httpd.address)
-@@ -91,6 +93,7 @@
-
- @socket_helper.skip_unless_bind_unix_socket
- @unittest.skipIf(ssl is None, 'No ssl module')
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_open_unix_connection_no_loop_ssl(self):
- with test_utils.run_test_unix_server(use_ssl=True) as httpd:
- conn_fut = asyncio.open_unix_connection(
-@@ -119,6 +122,7 @@
- self._basetest_open_connection_error(conn_fut)
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_open_unix_connection_error(self):
- with test_utils.run_test_unix_server() as httpd:
- conn_fut = asyncio.open_unix_connection(httpd.address)
-@@ -637,6 +641,7 @@
- self.assertEqual(messages, [])
-
- @socket_helper.skip_unless_bind_unix_socket
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_start_unix_server(self):
-
- class MyServer:
-diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py
-index 1d922783ce..81a5d2c699 100644
---- a/Lib/test/test_asyncio/test_unix_events.py
-+++ b/Lib/test/test_asyncio/test_unix_events.py
-@@ -13,6 +13,7 @@
- import threading
- import unittest
- from unittest import mock
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import socket_helper
-
-@@ -276,6 +277,7 @@
-
- @unittest.skipUnless(hasattr(socket, 'AF_UNIX'),
- 'UNIX Sockets are not supported')
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- class SelectorEventLoopUnixSocketTests(test_utils.TestCase):
-
- def setUp(self):
-diff --git a/Lib/test/test_fcntl.py b/Lib/test/test_fcntl.py
-index fc8c39365f..16235b8397 100644
---- a/Lib/test/test_fcntl.py
-+++ b/Lib/test/test_fcntl.py
-@@ -6,7 +6,7 @@
- import sys
- import unittest
- from multiprocessing import Process
--from test.support import verbose, cpython_only
-+from test.support import verbose, cpython_only, is_apple_mobile
- from test.support.import_helper import import_module
- from test.support.os_helper import TESTFN, unlink
-
-@@ -25,7 +25,7 @@
- start_len = "qq"
-
- if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd'))
-- or sys.platform == 'darwin'):
-+ or sys.platform == 'darwin' or is_apple_mobile):
- if struct.calcsize('l') == 8:
- off_t = 'l'
- pid_t = 'i'
-diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py
-index a937258069..3829c29fe5 100644
---- a/Lib/test/test_httpservers.py
-+++ b/Lib/test/test_httpservers.py
-@@ -30,6 +30,7 @@
-
- import unittest
- from test import support
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import threading_helper
-
-@@ -401,7 +402,7 @@
- with open(os.path.join(self.tempdir, filename), 'wb') as f:
- f.write(os_helper.TESTFN_UNDECODABLE)
- response = self.request(self.base_url + '/')
-- if sys.platform == 'darwin':
-+ 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):
-diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
-index daccbae5b4..607e40eb66 100644
---- a/Lib/test/test_io.py
-+++ b/Lib/test/test_io.py
-@@ -40,6 +40,7 @@
- from test.support.script_helper import (
- assert_python_ok, assert_python_failure, run_python_until_end)
- from test.support import import_helper
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import threading_helper
- from test.support import warnings_helper
-@@ -609,7 +610,7 @@
- # On Windows and Mac OSX this test consumes large resources; It takes
- # a long time to build the >2 GiB file and takes >2 GiB of disk space
- # therefore the resource must be enabled to run this test.
-- if sys.platform[:3] == 'win' or sys.platform == 'darwin':
-+ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or is_apple_mobile:
- support.requires(
- 'largefile',
- 'test requires %s bytes and a long time to run' % self.LARGE)
-diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
-index 350f4a57e2..54ef53a4c1 100644
---- a/Lib/test/test_logging.py
-+++ b/Lib/test/test_logging.py
-@@ -43,6 +43,7 @@
- import tempfile
- from test.support.script_helper import assert_python_ok, assert_python_failure
- from test import support
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import socket_helper
- from test.support import threading_helper
-@@ -1787,9 +1788,20 @@
- # just need a name - file can't be present, or we'll get an
- # 'address already in use' error.
- os.remove(fn)
-+ # Check the size of the socket file name. If it exceeds 108
-+ # characters (UNIX_PATH_MAX), it can't be used as a UNIX socket.
-+ # In this case, fall back to a path constructed somewhere that
-+ # is known to be short.
-+ if len(fn) > 108:
-+ fd, fn = tempfile.mkstemp(prefix='test_logging_', suffix='.sock', dir='/tmp')
-+ os.close(fd)
-+ # just need a name - file can't be present, or we'll get an
-+ # 'address already in use' error.
-+ os.remove(fn)
- return fn
-
- @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- class UnixSocketHandlerTest(SocketHandlerTest):
-
- """Test for SocketHandler with unix sockets."""
-@@ -1873,6 +1885,7 @@
- self.assertEqual(self.log_output, "spam\neggs\n")
-
- @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- class UnixDatagramHandlerTest(DatagramHandlerTest):
-
- """Test for DatagramHandler using Unix sockets."""
-@@ -1967,6 +1980,7 @@
- self.assertEqual(self.log_output, b'<11>sp\xc3\xa4m\x00')
-
- @unittest.skipUnless(hasattr(socket, "AF_UNIX"), "Unix sockets required")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- class UnixSysLogHandlerTest(SysLogHandlerTest):
-
- """Test for SysLogHandler with Unix sockets."""
-diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
-index aae86cc257..8be5af371b 100644
---- a/Lib/test/test_marshal.py
-+++ b/Lib/test/test_marshal.py
-@@ -1,5 +1,5 @@
- from test import support
--from test.support import os_helper, requires_debug_ranges
-+from test.support import os_helper, requires_debug_ranges, is_apple_mobile
- from test.support.script_helper import assert_python_ok
- import array
- import io
-@@ -260,7 +260,10 @@
- if os.name == 'nt':
- MAX_MARSHAL_STACK_DEPTH = 1000
- else:
-- MAX_MARSHAL_STACK_DEPTH = 2000
-+ if is_apple_mobile:
-+ MAX_MARSHAL_STACK_DEPTH = 1500
-+ else:
-+ MAX_MARSHAL_STACK_DEPTH = 2000
- for i in range(MAX_MARSHAL_STACK_DEPTH - 2):
- last.append([0])
- last = last[-1]
-diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py
-index 213a44d56f..87279579fe 100644
---- a/Lib/test/test_mmap.py
-+++ b/Lib/test/test_mmap.py
-@@ -1,5 +1,5 @@
- from test.support import (
-- requires, _2G, _4G, gc_collect, cpython_only, is_emscripten
-+ requires, _2G, _4G, gc_collect, cpython_only, is_emscripten, is_apple_mobile
- )
- from test.support.import_helper import import_module
- from test.support.os_helper import TESTFN, unlink
-@@ -245,7 +245,7 @@
- with open(TESTFN, "r+b") as f:
- self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize, access=4)
-
-- if os.name == "posix":
-+ if os.name == "posix" and not is_apple_mobile:
- # Try incompatible flags, prot and access parameters.
- with open(TESTFN, "r+b") as f:
- self.assertRaises(ValueError, mmap.mmap, f.fileno(), mapsize,
-@@ -896,7 +896,7 @@
- unlink(TESTFN)
-
- def _make_test_file(self, num_zeroes, tail):
-- if sys.platform[:3] == 'win' or sys.platform == 'darwin':
-+ if sys.platform[:3] == 'win' or sys.platform == 'darwin' or is_apple_mobile:
- requires('largefile',
- 'test requires %s bytes and a long time to run' % str(0x180000000))
- f = open(TESTFN, 'w+b')
+@@ -592,7 +592,7 @@
+ def skip_wasi_stack_overflow():
+ return unittest.skipIf(is_wasi, "Exhausts stack on WASI")
+
+-is_apple_mobile = sys.platform in {"ios", "tvos", "watchos"}
++is_apple_mobile = sys.platform in {"ios", "tvos", "visionos", "watchos"}
+ is_apple = is_apple_mobile or sys.platform == "darwin"
+
+ has_fork_support = hasattr(os, "fork") and not (
+diff --git a/Lib/test/test__interpreters.py b/Lib/test/test__interpreters.py
+index a32d5d81d2b..f9421619e98 100644
+--- a/Lib/test/test__interpreters.py
++++ b/Lib/test/test__interpreters.py
+@@ -612,6 +612,7 @@
+ f'assert(obj == {obj!r})',
+ )
+
++ @support.requires_subprocess()
+ def test_os_exec(self):
+ expected = 'spam spam spam spam spam'
+ subinterp = _interpreters.create()
+diff --git a/Lib/test/test_ctypes/test_dllist.py b/Lib/test/test_ctypes/test_dllist.py
+index 15603dc3d77..bff6c0fb95f 100644
+--- a/Lib/test/test_ctypes/test_dllist.py
++++ b/Lib/test/test_ctypes/test_dllist.py
+@@ -7,7 +7,7 @@
+
+
+ WINDOWS = os.name == "nt"
+-APPLE = sys.platform in {"darwin", "ios", "tvos", "watchos"}
++APPLE = sys.platform in {"darwin", "ios", "tvos", "watchos", "visionos"}
+
+ if WINDOWS:
+ KNOWN_LIBRARIES = ["KERNEL32.DLL"]
diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py
-index 9b2cd201f3..e47de5d468 100644
+index e879e48571f..07a2c6c76ce 100644
--- a/Lib/test/test_platform.py
+++ b/Lib/test/test_platform.py
-@@ -8,7 +8,7 @@
- from unittest import mock
-
- from test import support
--from test.support import os_helper
-+from test.support import os_helper, is_apple_mobile
-
- FEDORA_OS_RELEASE = """\
- NAME=Fedora
-@@ -315,7 +315,7 @@
- def test_mac_ver(self):
- res = platform.mac_ver()
-
-- if platform.uname().system == 'Darwin':
-+ if platform.uname().system == 'Darwin' and not is_apple_mobile:
- # We are on a macOS system, check that the right version
- # information is returned
- output = subprocess.check_output(['sw_vers'], text=True)
-@@ -347,6 +347,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_posix.py b/Lib/test/test_posix.py
-index ae25ef5588..2885d5fd52 100644
---- a/Lib/test/test_posix.py
-+++ b/Lib/test/test_posix.py
-@@ -2,6 +2,7 @@
-
- from test import support
- from test.support import import_helper
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import warnings_helper
- from test.support.script_helper import assert_python_ok
-@@ -69,12 +70,19 @@
- "getpid", "getpgrp", "getppid", "getuid", "sync",
- ]
-
-+ # getgroups can't be invoked on iOS/tvOS/watchOS.
-+ if is_apple_mobile:
-+ NO_ARG_FUNCTIONS.append("getgroups")
-+
- for name in NO_ARG_FUNCTIONS:
- posix_func = getattr(posix, name, None)
- if posix_func is not None:
- with self.subTest(name):
-- posix_func()
-- self.assertRaises(TypeError, posix_func, 1)
-+ try:
-+ posix_func()
-+ self.assertRaises(TypeError, posix_func, 1)
-+ except Exception as e:
-+ self.fail('Problem invoking %s: %s' % (name, e))
-
- @unittest.skipUnless(hasattr(posix, 'getresuid'),
- 'test needs posix.getresuid()')
-@@ -776,9 +784,10 @@
- check_stat(uid, gid)
- self.assertRaises(OSError, chown_func, first_param, 0, -1)
- check_stat(uid, gid)
-- if 0 not in os.getgroups():
-- self.assertRaises(OSError, chown_func, first_param, -1, 0)
-- check_stat(uid, gid)
-+ if hasattr(os, 'getgroups') and not is_apple_mobile:
-+ if 0 not in os.getgroups():
-+ self.assertRaises(OSError, chown_func, first_param, -1, 0)
-+ check_stat(uid, gid)
- # test illegal types
- for t in str, float:
- self.assertRaises(TypeError, chown_func, first_param, t(uid), gid)
-@@ -1129,7 +1138,7 @@
- self.assertIsInstance(hi, int)
- self.assertGreaterEqual(hi, lo)
- # OSX evidently just returns 15 without checking the argument.
-- if sys.platform != "darwin":
-+ if sys.platform != 'darwin' and not is_apple_mobile:
- self.assertRaises(OSError, posix.sched_get_priority_min, -23)
- self.assertRaises(OSError, posix.sched_get_priority_max, -23)
-
-diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
-index a2c4ab5081..45927b3163 100644
---- a/Lib/test/test_shutil.py
-+++ b/Lib/test/test_shutil.py
-@@ -1776,6 +1776,7 @@
- check_chown(dirname, uid, gid)
-
-
-+@unittest.skipIf(support.has_subprocess_support, 'Test requires support for subprocesses.')
- class TestWhich(BaseTest, unittest.TestCase):
-
- def setUp(self):
-@@ -2642,6 +2643,7 @@
- self.assertGreaterEqual(size.lines, 0)
-
- @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
-+ @unittest.skipUnless(support.has_subprocess_support, 'Test requires support for subprocesses.')
- @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
- 'need os.get_terminal_size()')
- def test_stty_match(self):
-diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
-index b07954989f..ac634d421c 100644
---- a/Lib/test/test_socket.py
-+++ b/Lib/test/test_socket.py
-@@ -1,5 +1,6 @@
- import unittest
- from test import support
-+from test.support import is_apple_mobile
- from test.support import os_helper
- from test.support import socket_helper
- from test.support import threading_helper
-@@ -1157,7 +1158,7 @@
- # I've ordered this by protocols that have both a tcp and udp
- # protocol, at least for modern Linuxes.
- if (sys.platform.startswith(('freebsd', 'netbsd', 'gnukfreebsd'))
-- or sys.platform in ('linux', 'darwin')):
-+ or sys.platform in ('linux', 'darwin') or is_apple_mobile):
- # avoid the 'echo' service on this platform, as there is an
- # assumption breaking non-standard port/protocol entry
- services = ('daytime', 'qotd', 'domain')
-@@ -3563,7 +3564,7 @@
- def _testFDPassCMSG_LEN(self):
- self.createAndSendFDs(1)
-
-- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- @unittest.skipIf(AIX, "skipping, see issue #22397")
- @requireAttrs(socket, "CMSG_SPACE")
- def testFDPassSeparate(self):
-@@ -3574,7 +3575,7 @@
- maxcmsgs=2)
-
- @testFDPassSeparate.client_skip
-- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- @unittest.skipIf(AIX, "skipping, see issue #22397")
- def _testFDPassSeparate(self):
- fd0, fd1 = self.newFDs(2)
-@@ -3587,7 +3588,7 @@
- array.array("i", [fd1]))]),
- len(MSG))
-
-- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- @unittest.skipIf(AIX, "skipping, see issue #22397")
- @requireAttrs(socket, "CMSG_SPACE")
- def testFDPassSeparateMinSpace(self):
-@@ -3601,7 +3602,7 @@
- maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC)
-
- @testFDPassSeparateMinSpace.client_skip
-- @unittest.skipIf(sys.platform == "darwin", "skipping, see issue #12958")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- @unittest.skipIf(AIX, "skipping, see issue #22397")
- def _testFDPassSeparateMinSpace(self):
- fd0, fd1 = self.newFDs(2)
-@@ -3625,7 +3626,7 @@
- nbytes = self.sendmsgToServer([msg])
- self.assertEqual(nbytes, len(msg))
-
-- @unittest.skipIf(sys.platform == "darwin", "see issue #24725")
-+ @unittest.skipIf(sys.platform == "darwin" or is_apple_mobile, "skipping, see issue #12958")
- def testFDPassEmpty(self):
- # Try to pass an empty FD array. Can receive either no array
- # or an empty array.
-@@ -4445,28 +4446,33 @@
- pass
-
- @requireAttrs(socket.socket, "sendmsg")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX")
- class SendmsgUnixStreamTest(SendmsgStreamTests, SendrecvmsgUnixStreamTestBase):
- pass
-
- @requireAttrs(socket.socket, "recvmsg")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX")
- class RecvmsgUnixStreamTest(RecvmsgTests, RecvmsgGenericStreamTests,
- SendrecvmsgUnixStreamTestBase):
- pass
-
- @requireAttrs(socket.socket, "recvmsg_into")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX")
- class RecvmsgIntoUnixStreamTest(RecvmsgIntoTests, RecvmsgGenericStreamTests,
- SendrecvmsgUnixStreamTestBase):
- pass
-
- @requireAttrs(socket.socket, "sendmsg", "recvmsg")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS")
- class RecvmsgSCMRightsStreamTest(SCMRightsTest, SendrecvmsgUnixStreamTestBase):
- pass
-
- @requireAttrs(socket.socket, "sendmsg", "recvmsg_into")
-+@unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- @requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS")
- class RecvmsgIntoSCMRightsStreamTest(RecvmsgIntoMixin, SCMRightsTest,
- SendrecvmsgUnixStreamTestBase):
-diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py
-index 2edb1e0c0e..62307168f6 100644
---- a/Lib/test/test_socketserver.py
-+++ b/Lib/test/test_socketserver.py
-@@ -8,13 +8,14 @@
- import select
- import signal
- import socket
-+import sys
- import tempfile
- import threading
- import unittest
- import socketserver
-
- import test.support
--from test.support import reap_children, verbose
-+from test.support import reap_children, verbose, is_apple_mobile
- from test.support import os_helper
- from test.support import socket_helper
- from test.support import threading_helper
-@@ -198,12 +199,14 @@
- self.stream_examine)
-
- @requires_unix_sockets
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_UnixStreamServer(self):
- self.run_server(socketserver.UnixStreamServer,
- socketserver.StreamRequestHandler,
- self.stream_examine)
-
- @requires_unix_sockets
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't fully support UNIX sockets." % sys.platform)
- def test_ThreadingUnixStreamServer(self):
- self.run_server(socketserver.ThreadingUnixStreamServer,
- socketserver.StreamRequestHandler,
-diff --git a/Lib/test/test_sundry.py b/Lib/test/test_sundry.py
-index de2e7305cc..ccf240397d 100644
---- a/Lib/test/test_sundry.py
-+++ b/Lib/test/test_sundry.py
-@@ -1,5 +1,6 @@
- """Do a minimal test of all the modules that aren't otherwise tested."""
- import importlib
-+import sys
- from test import support
- from test.support import import_helper
- from test.support import warnings_helper
-@@ -20,7 +21,8 @@
-
- import distutils.bcppcompiler
- import distutils.ccompiler
-- import distutils.cygwinccompiler
-+ if sys.platform.startswith('win'):
-+ import distutils.cygwinccompiler
- import distutils.filelist
- import distutils.text_file
- import distutils.unixccompiler
-diff --git a/Lib/test/test_sysconfig.py b/Lib/test/test_sysconfig.py
-index 578ac1db50..daf61113b2 100644
---- a/Lib/test/test_sysconfig.py
-+++ b/Lib/test/test_sysconfig.py
-@@ -336,7 +336,7 @@
- self.assertTrue(os.path.isfile(config_h), config_h)
-
- def test_get_scheme_names(self):
-- wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv']
-+ wanted = ['nt', 'posix_home', 'posix_prefix', 'posix_venv', 'nt_venv', 'venv', 'tvos', 'watchos']
- if HAS_USER_BASE:
- wanted.extend(['nt_user', 'osx_framework_user', 'posix_user'])
- self.assertEqual(get_scheme_names(), tuple(sorted(wanted)))
-diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
-index 9c6561c099..ccccfb8b0b 100644
---- a/Lib/test/test_threading.py
-+++ b/Lib/test/test_threading.py
-@@ -3,7 +3,7 @@
- """
-
- import test.support
--from test.support import threading_helper, requires_subprocess
-+from test.support import threading_helper, requires_subprocess, is_apple_mobile
- from test.support import verbose, cpython_only, os_helper
- from test.support.import_helper import import_module
- from test.support.script_helper import assert_python_ok, assert_python_failure
-@@ -1171,6 +1171,7 @@
- os.set_blocking(r, False)
- return (r, w)
-
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't have os.pipe" % sys.platform)
- def test_threads_join(self):
- # Non-daemon threads should be joined at subinterpreter shutdown
- # (issue #18808)
-@@ -1199,6 +1200,7 @@
- # The thread was joined properly.
- self.assertEqual(os.read(r, 1), b"x")
-
-+ @unittest.skipIf(is_apple_mobile, "%s doesn't have os.pipe" % sys.platform)
- def test_threads_join_2(self):
- # Same as above, but a delay gets introduced after the thread's
- # Python code returned but before the thread state is deleted.
-diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py
-index 74039f59f7..36dc82f871 100644
---- a/Lib/test/test_venv.py
-+++ b/Lib/test/test_venv.py
-@@ -19,7 +19,7 @@
- import tempfile
- from test.support import (captured_stdout, captured_stderr, requires_zlib,
- skip_if_broken_multiprocessing_synchronize, verbose,
-- requires_subprocess, is_emscripten, is_wasi,
-+ requires_subprocess, is_apple_mobile, is_emscripten, is_wasi,
- requires_venv_with_pip)
- from test.support.os_helper import (can_symlink, EnvironmentVarGuard, rmtree)
- import unittest
-@@ -40,6 +40,8 @@
-
- if is_emscripten or is_wasi:
- raise unittest.SkipTest("venv is not available on Emscripten/WASI.")
-+if is_apple_mobile:
-+ raise unittest.SkipTest("venv is not available on mobile Apple platforms.")
-
- @requires_subprocess()
- def check_output(cmd, encoding=None):
-diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
-index f4c11d88c8..fb1ef8b417 100644
---- a/Lib/test/test_zipfile.py
-+++ b/Lib/test/test_zipfile.py
-@@ -1166,6 +1166,7 @@
- self.skipTest('requires write access to the installed location')
- unlink(filename)
-
-+ @unittest.skipIf(sys.dont_write_bytecode, "Test requires ability to write bytecode")
- def test_write_pyfile(self):
- self.requiresWriteAccess(os.path.dirname(__file__))
- with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp:
-@@ -1210,6 +1211,7 @@
- self.assertCompiledIn('email/__init__.py', names)
- self.assertCompiledIn('email/mime/text.py', names)
-
-+ @unittest.skipIf(sys.dont_write_bytecode, "Test requires ability to write bytecode")
- def test_write_filtered_python_package(self):
- import test
- packagedir = os.path.dirname(test.__file__)
+@@ -271,13 +271,21 @@
+ if sys.platform == "android":
+ self.assertEqual(res.system, "Android")
+ self.assertEqual(res.release, platform.android_ver().release)
+- elif sys.platform == "ios":
++ elif support.is_apple_mobile:
+ # Platform module needs ctypes for full operation. If ctypes
+ # isn't available, there's no ObjC module, and dummy values are
+ # returned.
+ if _ctypes:
+- self.assertIn(res.system, {"iOS", "iPadOS"})
+- self.assertEqual(res.release, platform.ios_ver().release)
++ if sys.platform == "ios":
++ # iPads also identify as iOS
++ self.assertIn(res.system, {"iOS", "iPadOS"})
++ else:
++ # All other platforms - sys.platform is the lower case
++ # form of system (e.g., visionOS->visionos)
++ self.assertEqual(res.system.lower(), sys.platform)
++ # Use the platform-specific version method
++ platform_ver = getattr(platform, f"{sys.platform}_ver")
++ self.assertEqual(res.release, platform_ver().release)
+ else:
+ self.assertEqual(res.system, "")
+ self.assertEqual(res.release, "")
+diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py
+index 4c3ea1cd8df..04a210e5c86 100644
+--- a/Lib/test/test_webbrowser.py
++++ b/Lib/test/test_webbrowser.py
+@@ -236,7 +236,8 @@
+ arguments=[f'openURL({URL},new-tab)'])
+
+
+-@unittest.skipUnless(sys.platform == "ios", "Test only applicable to iOS")
++@unittest.skipUnless(sys.platform in {"ios", "visionOS"},
++ "Test only applicable to iOS and visionOS")
+ class IOSBrowserTest(unittest.TestCase):
+ def _obj_ref(self, *args):
+ # Construct a string representation of the arguments that can be used
diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py
-index 44974d433b..ae4e18802b 100755
+index f2e2394089d..2efbbfb0014 100644
--- a/Lib/webbrowser.py
+++ b/Lib/webbrowser.py
-@@ -596,6 +596,57 @@
+@@ -488,7 +488,8 @@
+ # macOS can use below Unix support (but we prefer using the macOS
+ # specific stuff)
- # what to do if _tryorder is now empty?
+- if sys.platform == "ios":
++ if sys.platform in {"ios", "visionos"}:
++ # iOS and visionOS provide a browser; tvOS and watchOS don't.
+ register("iosbrowser", None, IOSBrowser(), preferred=True)
-+#
-+# Platform support for iOS
-+#
-+if sys.platform == 'ios':
-+ class MobileSafari(BaseBrowser):
-+ def open(self, url, new=0, autoraise=True):
-+ # This code is the equivalent of:
-+ # NSURL *nsurl = [NSURL URLWithString:url];
-+ # [[UIApplication sharedApplication] openURL:nsurl];
-+ from ctypes import cdll, c_void_p, c_char_p, c_uint32
-+ from ctypes import util
-+ objc = cdll.LoadLibrary(util.find_library(b'objc'))
-+ cf = cdll.LoadLibrary(util.find_library(b'CoreFoundation'))
-+ objc.objc_getClass.restype = c_void_p
-+ objc.objc_getClass.argtypes = [c_char_p]
-+ objc.sel_registerName.restype = c_void_p
-+ objc.sel_registerName.argtypes = [c_char_p]
-+ cf.CFStringCreateWithCString.restype = c_void_p
-+ cf.CFStringCreateWithCString.argtypes = [c_void_p, c_char_p, c_uint32]
-+
-+ # Get an NSString describing the URL
-+ kCFStringEncodingUTF8 = 0x08000100
-+ url = c_void_p(cf.CFStringCreateWithCString(None, url.encode('utf-8'), kCFStringEncodingUTF8))
-+ autorelease = c_void_p(objc.sel_registerName(b'autorelease'))
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
-+ objc.objc_msgSend.restype = c_void_p
-+ objc.objc_msgSend(url, autorelease)
-+
-+ # Get an NSURL object representing the URL
-+ NSURL = c_void_p(objc.objc_getClass(b'NSURL'))
-+ urlWithString_ = c_void_p(objc.sel_registerName(b'URLWithString:'))
-+ objc.objc_msgSend.restype = c_void_p
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p]
-+ nsurl = c_void_p(objc.objc_msgSend(NSURL, urlWithString_, url))
-+
-+ # Get the shared UIApplication instance
-+ UIApplication = c_void_p(objc.objc_getClass(b'UIApplication'))
-+ sharedApplication = c_void_p(objc.sel_registerName(b'sharedApplication'))
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p]
-+ objc.objc_msgSend.restype = c_void_p
-+ shared_app = c_void_p(objc.objc_msgSend(UIApplication, sharedApplication))
-+
-+ # Open the URL on the shared application
-+ openURL_ = c_void_p(objc.sel_registerName(b'openURL:'))
-+ objc.objc_msgSend.argtypes = [c_void_p, c_void_p, c_void_p]
-+ objc.objc_msgSend.restype = None
-+ objc.objc_msgSend(shared_app, openURL_, nsurl)
-+
-+ return True
-+
-+ register("mobilesafari", None, MobileSafari(), preferred=True)
+ if sys.platform == "serenityos":
+@@ -653,9 +654,10 @@
+ return not rc
#
- # Platform support for Windows
+-# Platform support for iOS
++# Platform support for Apple Mobile platforms that provide a browser
++# (i.e., iOS and visionOS)
+ #
+-if sys.platform == "ios":
++if sys.platform in {"ios", "visionos"}:
+ from _ios_support import objc
+ if objc:
+ # If objc exists, we know ctypes is also importable.
diff --git a/Makefile.pre.in b/Makefile.pre.in
-index 8fbcd7ac17..0e85788dba 100644
+index 08ad5f4921d..8c1c9843c00 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
-@@ -344,6 +344,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 9132f13e81..36e00f7bfd 100644
---- a/Modules/_posixsubprocess.c
-+++ b/Modules/_posixsubprocess.c
-@@ -31,10 +31,20 @@
-
- #include "posixmodule.h"
-
-+#if defined(__APPLE__)
-+#include "TargetConditionals.h"
-+#endif
+@@ -209,6 +209,12 @@
+ # the build, and is only listed here so it will be included in sysconfigdata.
+ IPHONEOS_DEPLOYMENT_TARGET=@IPHONEOS_DEPLOYMENT_TARGET@
+
++# visionOS Deployment target is *actually* used during the build, by the
++# compiler shims; export.
++XROS_DEPLOYMENT_TARGET=@XROS_DEPLOYMENT_TARGET@
++@EXPORT_XROS_DEPLOYMENT_TARGET@export XROS_DEPLOYMENT_TARGET
+
- #ifdef _Py_MEMORY_SANITIZER
- # include
- #endif
-
-+// iOS/tvOS/watchOS *define* a number of POSIX functions, but you can't use them
-+// because they aren't conventional multiprocess environments.
-+#if TARGET_OS_IPHONE
-+# undef HAVE_FORK
-+#endif
+
- #if defined(__ANDROID__) && __ANDROID_API__ < 21 && !defined(SYS_getdents64)
- # include
- # define SYS_getdents64 __NR_getdents64
-@@ -660,11 +670,15 @@
- saved_errno = 0;
- for (i = 0; exec_array[i] != NULL; ++i) {
- const char *executable = exec_array[i];
-+#if defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) || defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
-+ errno = ENOTSUP;
-+#else
- if (envp) {
- execve(executable, argv, envp);
- } else {
- execv(executable, argv);
- }
-+#endif
- if (errno != ENOENT && errno != ENOTDIR && saved_errno == 0) {
- saved_errno = errno;
- }
-@@ -730,7 +744,9 @@
- PyObject *preexec_fn,
- PyObject *preexec_fn_args_tuple)
- {
--
-+/* iOS/tvOS/watchOS define the existence of fork, but it cannot be invoked;
-+ * so fail fast if any attempt is made to invoke fork_exec */
-+#ifdef HAVE_FORK
- pid_t pid;
-
- #ifdef VFORK_USABLE
-@@ -749,7 +765,7 @@
- pid = fork();
- }
- } else
--#endif
-+#endif /* VFORK_USABLE */
- {
- pid = fork();
- }
-@@ -757,7 +773,6 @@
- if (pid != 0) {
- return pid;
- }
--
- /* Child process.
- * See the comment above child_exec() for restrictions imposed on
- * the code below.
-@@ -780,6 +795,9 @@
- py_fds_to_keep, preexec_fn, preexec_fn_args_tuple);
- _exit(255);
- return 0; /* Dead code to avoid a potential compiler warning. */
-+#else /* HAVE_FORK */
-+ return -1;
-+#endif /* HAVE_FORK */
- }
-
-
-@@ -810,7 +828,9 @@
- int need_after_fork = 0;
- int saved_errno = 0;
- int allow_vfork;
--
-+/* iOS/tvOS/watchOS define the existence of fork, but it cannot be invoked;
-+ * so fail fast if any attempt is made to invoke fork_exec */
-+#ifdef HAVE_FORK
- if (!PyArg_ParseTuple(
- args, "OOpO!OOiiiiiiiiii" _Py_PARSE_PID "OOOiOp:fork_exec",
- &process_args, &executable_list,
-@@ -982,7 +1002,6 @@
- goto cleanup;
- #endif /* HAVE_SETREUID */
- }
--
- /* This must be the last thing done before fork() because we do not
- * want to call PyOS_BeforeFork() if there is any chance of another
- * error leading to the cleanup: code without calling fork(). */
-@@ -1017,7 +1036,7 @@
- }
- old_sigmask = &old_sigs;
- }
--#endif
-+#endif /* VFORK_USABLE */
-
- pid = do_fork_exec(exec_array, argv, envp, cwd,
- p2cread, p2cwrite, c2pread, c2pwrite,
-@@ -1049,7 +1068,7 @@
- * the thread signal mask. */
- (void) pthread_sigmask(SIG_SETMASK, old_sigmask, NULL);
- }
--#endif
-+#endif /* VFORK_USABLE */
-
- if (need_after_fork)
- PyOS_AfterFork_Parent();
-@@ -1078,8 +1097,10 @@
- PyGC_Enable();
- }
- Py_XDECREF(gc_module);
--
- return pid == -1 ? NULL : PyLong_FromPid(pid);
-+#else /* HAVE_FORK */
-+ return NULL;
-+#endif
- }
-
-
-diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c
-index 4847c1cb87..4a4c890846 100644
---- a/Modules/faulthandler.c
-+++ b/Modules/faulthandler.c
-@@ -1,3 +1,7 @@
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
- #include "Python.h"
- #include "pycore_initconfig.h" // _PyStatus_ERR
- #include "pycore_pyerrors.h" // _Py_DumpExtensionModules
-@@ -19,6 +23,11 @@
- # include
- #endif
-
-+// tvOS and watchOS don't provide a number of important POSIX functions.
-+#if defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) || defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__)
-+# undef HAVE_SIGALTSTACK
-+#endif /* TVOS || WATCHOS */
-+
- /* Using an alternative stack requires sigaltstack()
- and sigaction() SA_ONSTACK */
- #if defined(HAVE_SIGALTSTACK) && defined(HAVE_SIGACTION)
-diff --git a/Modules/mathmodule.c b/Modules/mathmodule.c
-index aa93e756c6..fcf3784c2f 100644
---- a/Modules/mathmodule.c
-+++ b/Modules/mathmodule.c
-@@ -76,6 +76,10 @@
- /*[clinic end generated code: output=da39a3ee5e6b4b0d input=76bc7002685dd942]*/
-
-
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
- /*
- sin(pi*x), giving accurate results for all finite x (especially x
- integral or close to an integer). This is here for use in the
-diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
-index 378032501f..25a035acd7 100644
---- a/Modules/posixmodule.c
-+++ b/Modules/posixmodule.c
-@@ -69,6 +69,8 @@
- */
- #if defined(__APPLE__)
-
-+#include "TargetConditionals.h"
-+
- #if defined(__has_builtin)
- #if __has_builtin(__builtin_available)
- #define HAVE_BUILTIN_AVAILABLE 1
-@@ -325,6 +327,26 @@
- # endif /* _MSC_VER */
- #endif /* ! __WATCOMC__ || __QNX__ */
-
-+// iOS/tvOS/watchOS *define* a number of POSIX functions, but you can't use them
-+// because they aren't conventional multiprocess environment.
-+#if TARGET_OS_IPHONE
-+# undef HAVE_EXECV
-+# undef HAVE_FORK
-+# undef HAVE_FORK1
-+# undef HAVE_FORKPTY
-+# undef HAVE_GETGROUPS
-+# undef HAVE_POSIX_SPAWN
-+# undef HAVE_POSIX_SPAWNP
-+# undef HAVE_SCHED_H
-+# undef HAVE_SENDFILE
-+# undef HAVE_SETPRIORITY
-+# undef HAVE_SPAWNV
-+# undef HAVE_WAIT
-+# undef HAVE_WAIT3
-+# undef HAVE_WAIT4
-+# undef HAVE_WAITPID
-+#endif
-+
- /*[clinic input]
- # one of the few times we lie about this name!
- module os
-@@ -1573,7 +1595,9 @@
- */
- #include
- #elif !defined(_MSC_VER) && (!defined(__WATCOMC__) || defined(__QNX__) || defined(__VXWORKS__))
-+# if !TARGET_OS_TV && !TARGET_OS_WATCH
- extern char **environ;
-+# endif
- #endif /* !_MSC_VER */
-
- static PyObject *
-@@ -1589,6 +1613,7 @@
- d = PyDict_New();
- if (d == NULL)
- return NULL;
-+#if !TARGET_OS_TV && !TARGET_OS_WATCH
- #ifdef MS_WINDOWS
- /* _wenviron must be initialized in this way if the program is started
- through main() instead of wmain(). */
-@@ -1642,6 +1667,7 @@
- Py_DECREF(k);
- Py_DECREF(v);
- }
-+#endif
- return d;
- }
-
-@@ -4935,6 +4961,9 @@
- /*[clinic end generated code: output=290fc437dd4f33a0 input=86a58554ba6094af]*/
- {
- long result;
-+#if TARGET_OS_IPHONE
-+ result = -1;
-+#else
- const char *bytes = PyBytes_AsString(command);
-
- if (PySys_Audit("os.system", "(O)", command) < 0) {
-@@ -4944,6 +4973,7 @@
- Py_BEGIN_ALLOW_THREADS
- result = system(bytes);
- Py_END_ALLOW_THREADS
-+#endif
- return result;
- }
- #endif
-@@ -13700,6 +13730,7 @@
- int is_symlink;
- int need_stat;
- #endif
-+#if !TARGET_OS_TV && !TARGET_OS_WATCH
- #ifdef MS_WINDOWS
- unsigned long dir_bits;
- #endif
-@@ -13760,6 +13791,7 @@
- #endif
-
- return result;
-+#endif
-
- error:
- Py_XDECREF(st_mode);
-diff --git a/Modules/pwdmodule.c b/Modules/pwdmodule.c
-index a757380bd0..5a20864a1c 100644
---- a/Modules/pwdmodule.c
-+++ b/Modules/pwdmodule.c
-@@ -1,6 +1,10 @@
-
- /* UNIX password file access module */
-
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
- #include "Python.h"
- #include "posixmodule.h"
-
-@@ -182,6 +186,22 @@
- if (nomem == 1) {
- return PyErr_NoMemory();
- }
-+
-+// iPhone has a "user" with UID 501, username "mobile"; but the simulator
-+// doesn't reflect this. Generate a simulated response.
-+#if TARGET_IPHONE_SIMULATOR
-+ if (uid == 501) {
-+ struct passwd mp;
-+ mp.pw_name = "mobile";
-+ mp.pw_passwd = "/smx7MYTQIi2M";
-+ mp.pw_uid = 501;
-+ mp.pw_gid = 501;
-+ mp.pw_gecos = "Mobile User";
-+ mp.pw_dir = "/var/mobile";
-+ mp.pw_shell = "/bin/sh";
-+ return mkpwent(module, &mp);
-+ }
-+#endif
- PyObject *uid_obj = _PyLong_FromUid(uid);
- if (uid_obj == NULL)
- return NULL;
-@@ -265,6 +285,22 @@
- PyErr_NoMemory();
- }
- else {
-+// iPhone has a "user" with UID 501, username "mobile"; but the simulator
-+// doesn't reflect this. Generate a simulated response.
-+#if TARGET_IPHONE_SIMULATOR
-+ if (strcmp(name, "mobile") == 0) {
-+ struct passwd mp;
-+ mp.pw_name = "mobile";
-+ mp.pw_passwd = "/smx7MYTQIi2M";
-+ mp.pw_uid = 501;
-+ mp.pw_gid = 501;
-+ mp.pw_gecos = "Mobile User";
-+ mp.pw_dir = "/var/mobile";
-+ mp.pw_shell = "/bin/sh";
-+ retval = mkpwent(module, &mp);
-+ goto out;
-+ }
-+#endif
- PyErr_Format(PyExc_KeyError,
- "getpwnam(): name not found: %R", name);
- }
-diff --git a/Modules/timemodule.c b/Modules/timemodule.c
-index 18f9ddb909..2ed289a92f 100644
---- a/Modules/timemodule.c
-+++ b/Modules/timemodule.c
-@@ -62,6 +62,11 @@
- #define SEC_TO_NS (1000 * 1000 * 1000)
-
-
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
-+
- /* Forward declarations */
- static int pysleep(_PyTime_t timeout);
-
-@@ -263,11 +268,13 @@
- if (_PyTime_AsTimespec(t, &tp) == -1)
- return NULL;
-
-+#if !TARGET_OS_IPHONE
- ret = clock_settime((clockid_t)clk_id, &tp);
- if (ret != 0) {
- PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
- }
-+#endif
- Py_RETURN_NONE;
- }
-
-@@ -296,11 +303,13 @@
- return NULL;
- }
-
-+#if !TARGET_OS_IPHONE
- ret = clock_settime((clockid_t)clk_id, &ts);
- if (ret != 0) {
- PyErr_SetFromErrno(PyExc_OSError);
- return NULL;
- }
-+#endif
- Py_RETURN_NONE;
- }
-
-diff --git a/Python/bootstrap_hash.c b/Python/bootstrap_hash.c
-index 3a2a731808..cb2d9e53e2 100644
---- a/Python/bootstrap_hash.c
-+++ b/Python/bootstrap_hash.c
-@@ -35,6 +35,10 @@
- #endif
-
-
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
- #ifdef Py_DEBUG
- int _Py_HashSecret_Initialized = 0;
- #else
-@@ -180,6 +184,9 @@
- }
-
- #elif defined(HAVE_GETENTROPY)
-+// iOS, tvOS and watchOS have an incomplete definitions of getentropy
-+// so it is *found* by configure, but doesn't actually exist.
-+#elif defined(HAVE_GETENTROPY) && !TARGET_OS_IPHONE
- #define PY_GETENTROPY 1
-
- /* Fill buffer with size pseudo-random bytes generated by getentropy():
-diff --git a/Python/marshal.c b/Python/marshal.c
-index 90a4405091..65dd71d868 100644
---- a/Python/marshal.c
-+++ b/Python/marshal.c
-@@ -14,6 +14,10 @@
- #include "pycore_hashtable.h" // _Py_hashtable_t
- #include "marshal.h" // Py_MARSHAL_VERSION
-
-+#ifdef __APPLE__
-+# include "TargetConditionals.h"
-+#endif /* __APPLE__ */
-+
- /*[clinic input]
- module marshal
- [clinic start generated code]*/
-@@ -33,9 +37,13 @@
- * #if defined(MS_WINDOWS) && defined(_DEBUG)
- */
- #if defined(MS_WINDOWS)
--#define MAX_MARSHAL_STACK_DEPTH 1000
-+# define MAX_MARSHAL_STACK_DEPTH 1000
- #else
--#define MAX_MARSHAL_STACK_DEPTH 2000
-+# if TARGET_OS_IPHONE
-+# define MAX_MARSHAL_STACK_DEPTH 1500
-+# else
-+# define MAX_MARSHAL_STACK_DEPTH 2000
-+# endif
- #endif
-
- #define TYPE_NULL '0'
-diff --git a/aclocal.m4 b/aclocal.m4
-index 6a33c0cc9d..09ae5d1aa8 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,
-@@ -184,7 +184,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], [
-@@ -227,7 +227,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"
-@@ -276,7 +276,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
-@@ -318,7 +318,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
-@@ -419,7 +419,7 @@
- AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
-
- pkg_failed=no
--AC_MSG_CHECKING([for $1])
-+AC_MSG_CHECKING([for $2])
-
- _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
- _PKG_CONFIG([$1][_LIBS], [libs], [$2])
-@@ -429,11 +429,11 @@
- See the pkg-config man page for more details.])
-
- if test $pkg_failed = yes; then
-- AC_MSG_RESULT([no])
-+ AC_MSG_RESULT([no])
- _PKG_SHORT_ERRORS_SUPPORTED
- if test $_pkg_short_errors_supported = yes; then
- $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
-- else
-+ else
- $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
- fi
- # Put the nasty error message in config.log where it belongs
-@@ -450,7 +450,7 @@
- _PKG_TEXT])[]dnl
- ])
- elif test $pkg_failed = untried; then
-- AC_MSG_RESULT([no])
-+ AC_MSG_RESULT([no])
- 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
-@@ -551,77 +551,9 @@
- 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
--
- # AM_CONDITIONAL -*- Autoconf -*-
-
--# Copyright (C) 1997-2020 Free Software Foundation, Inc.
-+# Copyright (C) 1997-2021 Free Software Foundation, Inc.
- #
- # This file is free software; the Free Software Foundation
- # gives unlimited permission to copy and/or distribute it,
-@@ -652,7 +584,7 @@
- Usually this means the macro was only invoked conditionally.]])
- fi])])
-
--# Copyright (C) 2006-2020 Free Software Foundation, Inc.
-+# Copyright (C) 2006-2021 Free Software Foundation, Inc.
- #
- # This file is free software; the Free Software Foundation
- # gives unlimited permission to copy and/or distribute it,
+ # Option to install to strip binaries
+ STRIPFLAG=-s
+
+diff --git a/Misc/platform_triplet.c b/Misc/platform_triplet.c
+index f5cd73bdea8..6c1863c943b 100644
+--- a/Misc/platform_triplet.c
++++ b/Misc/platform_triplet.c
+@@ -257,6 +257,32 @@
+ # else
+ PLATFORM_TRIPLET=arm64-iphoneos
+ # endif
++# elif defined(TARGET_OS_TV) && TARGET_OS_TV
++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
++# if __x86_64__
++PLATFORM_TRIPLET=x86_64-appletvsimulator
++# else
++PLATFORM_TRIPLET=arm64-appletvsimulator
++# endif
++# else
++PLATFORM_TRIPLET=arm64-appletvos
++# endif
++# elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH
++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
++# if __x86_64__
++PLATFORM_TRIPLET=x86_64-watchsimulator
++# else
++PLATFORM_TRIPLET=arm64-watchsimulator
++# endif
++# else
++PLATFORM_TRIPLET=arm64_32-watchos
++# endif
++# elif defined(TARGET_OS_VISION) && TARGET_OS_VISION
++# if defined(TARGET_OS_SIMULATOR) && TARGET_OS_SIMULATOR
++PLATFORM_TRIPLET=arm64-xrsimulator
++# else
++PLATFORM_TRIPLET=arm64-xros
++# endif
+ // Older macOS SDKs do not define TARGET_OS_OSX
+ # elif !defined(TARGET_OS_OSX) || TARGET_OS_OSX
+ PLATFORM_TRIPLET=darwin
diff --git a/config.sub b/config.sub
-index d74fb6deac..a30f74f03d 100755
+index 1bb6a05dc11..49febd56a37 100755
--- a/config.sub
+++ b/config.sub
-@@ -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 @@
+@@ -1743,7 +1743,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* \
+- | os9* | macos* | osx* | ios* | tvos* | watchos* \
++ | os9* | macos* | osx* | ios* | tvos* | watchos* | xros* \
| mpw* | magic* | mmixware* | mon960* | lnews* \
| amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
| aos* | aros* | cloudabi* | sortix* | twizzler* \
-@@ -1786,6 +1785,8 @@
+@@ -1867,7 +1867,7 @@
;;
- *-eabi* | *-gnueabi*)
+ *-eabi*- | *-gnueabi*-)
;;
-+ ios*-simulator | tvos*-simulator | watchos*-simulator)
-+ ;;
- -*)
- # Blank kernel with real OS is always fine.
+- ios*-simulator- | tvos*-simulator- | watchos*-simulator- )
++ ios*-simulator- | tvos*-simulator- | watchos*-simulator- | xros*-simulator-)
;;
+ none--*)
+ # None (no kernel, i.e. freestanding / bare metal),
diff --git a/configure b/configure
-index 784f8d3060..2ca708e27b 100755
+index 46eb0665bf4..73035fb9efa 100755
--- a/configure
+++ b/configure
-@@ -836,6 +836,8 @@
- LIBMPDEC_INTERNAL
- LIBMPDEC_LDFLAGS
- LIBMPDEC_CFLAGS
-+LIBFFI_LIB
-+LIBFFI_LIBDIR
- LIBFFI_INCLUDEDIR
- LIBEXPAT_INTERNAL
- LIBEXPAT_LDFLAGS
-@@ -988,7 +990,6 @@
- docdir
- oldincludedir
- includedir
--runstatedir
- localstatedir
- sharedstatedir
- sysconfdir
-@@ -1139,7 +1140,6 @@
- sysconfdir='${prefix}/etc'
- sharedstatedir='${prefix}/com'
- localstatedir='${prefix}/var'
--runstatedir='${localstatedir}/run'
- includedir='${prefix}/include'
- oldincludedir='/usr/include'
- docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
-@@ -1392,15 +1392,6 @@
- | -silent | --silent | --silen | --sile | --sil)
- silent=yes ;;
-
-- -runstatedir | --runstatedir | --runstatedi | --runstated \
-- | --runstate | --runstat | --runsta | --runst | --runs \
-- | --run | --ru | --r)
-- ac_prev=runstatedir ;;
-- -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
-- | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
-- | --run=* | --ru=* | --r=*)
-- runstatedir=$ac_optarg ;;
--
- -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
- ac_prev=sbindir ;;
- -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
-@@ -1538,7 +1529,7 @@
- for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
- datadir sysconfdir sharedstatedir localstatedir includedir \
- oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-- libdir localedir mandir runstatedir
-+ libdir localedir mandir
- do
- eval ac_val=\$$ac_var
- # Remove trailing slashes.
-@@ -1691,7 +1682,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]
-- --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
- --libdir=DIR object code libraries [EPREFIX/lib]
- --includedir=DIR C header files [PREFIX/include]
- --oldincludedir=DIR C header files for non-gcc [/usr/include]
-@@ -3820,6 +3810,15 @@
- *-*-cygwin*)
- ac_sys_system=Cygwin
+@@ -983,6 +983,10 @@
+ CFLAGS
+ CC
+ HAS_XCRUN
++EXPORT_XROS_DEPLOYMENT_TARGET
++WATCHOS_DEPLOYMENT_TARGET
++XROS_DEPLOYMENT_TARGET
++TVOS_DEPLOYMENT_TARGET
+ IPHONEOS_DEPLOYMENT_TARGET
+ EXPORT_MACOSX_DEPLOYMENT_TARGET
+ CONFIGURE_MACOSX_DEPLOYMENT_TARGET
+@@ -4117,6 +4121,15 @@
+ *-apple-ios*)
+ ac_sys_system=iOS
;;
-+ *-apple-ios*)
-+ ac_sys_system=iOS
-+ ;;
+ *-apple-tvos*)
+ ac_sys_system=tvOS
+ ;;
++ *-apple-xros*)
++ ac_sys_system=visionOS
++ ;;
++ *-apple-watchos*)
++ ac_sys_system=watchOS
++ ;;
+ *-*-darwin*)
+ ac_sys_system=Darwin
+ ;;
+@@ -4198,7 +4211,7 @@
+ # On cross-compile builds, configure will look for a host-specific compiler by
+ # prepending the user-provided host triple to the required binary name.
+ #
+-# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc",
++# On iOS/tvOS/visionOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc",
+ # which isn't a binary that exists, and isn't very convenient, as it contains the
+ # iOS version. As the default cross-compiler name won't exist, configure falls
+ # back to gcc, which *definitely* won't work. We're providing wrapper scripts for
+@@ -4213,6 +4226,17 @@
+ aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;;
+ aarch64-apple-ios*) AR=arm64-apple-ios-ar ;;
+ x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;;
++
++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;;
++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;;
++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;;
++
++ aarch64-apple-xros*-simulator) AR=arm64-apple-xros-simulator-ar ;;
++ aarch64-apple-xros*) AR=arm64-apple-xros-ar ;;
++
++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;;
++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;;
++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;;
+ *)
+ esac
+ fi
+@@ -4221,6 +4245,17 @@
+ aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;;
+ aarch64-apple-ios*) CC=arm64-apple-ios-clang ;;
+ x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;;
++
++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;;
++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;;
++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;;
++
++ aarch64-apple-xros*-simulator) CC=arm64-apple-xros-simulator-clang ;;
++ aarch64-apple-xros*) CC=arm64-apple-xros-clang ;;
++
++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;;
++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;;
++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;;
+ *)
+ esac
+ fi
+@@ -4229,6 +4264,17 @@
+ aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;;
+ aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;;
+ x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;;
++
++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;;
++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;;
++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;;
++
++ aarch64-apple-xros*-simulator) CPP=arm64-apple-xros-simulator-cpp ;;
++ aarch64-apple-xros*) CPP=arm64-apple-xros-cpp ;;
++
++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;;
++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;;
++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;;
+ *)
+ esac
+ fi
+@@ -4237,6 +4283,17 @@
+ aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;;
+ aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;;
+ x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;;
++
++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;;
++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;;
++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;;
++
++ aarch64-apple-xros*-simulator) CXX=arm64-apple-xros-simulator-clang++ ;;
++ aarch64-apple-xros*) CXX=arm64-apple-xros-clang++ ;;
++
++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;;
++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;;
++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;;
+ *)
+ esac
+ fi
+@@ -4359,8 +4416,11 @@
+ case $enableval in
+ yes)
+ case $ac_sys_system in
+- Darwin) enableval=/Library/Frameworks ;;
+- iOS) enableval=Apple/iOS/Frameworks/\$\(MULTIARCH\) ;;
++ Darwin) enableval=/Library/Frameworks ;;
++ iOS) enableval=Apple/iOS/Frameworks/\$\(MULTIARCH\) ;;
++ tvOS) enableval=Apple/tvOS/Frameworks/\$\(MULTIARCH\) ;;
++ visionOS) enableval=Apple/visionOS/Frameworks/\$\(MULTIARCH\) ;;
++ watchOS) enableval=Apple/watchOS/Frameworks/\$\(MULTIARCH\) ;;
+ *) as_fn_error $? "Unknown platform for framework build" "$LINENO" 5
+ esac
+ esac
+@@ -4369,6 +4429,9 @@
+ no)
+ case $ac_sys_system in
+ iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;;
++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;;
++ visionOS) as_fn_error $? "visionOS builds must use --enable-framework" "$LINENO" 5 ;;
++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;;
+ *)
+ PYTHONFRAMEWORK=
+ PYTHONFRAMEWORKDIR=no-framework
+@@ -4475,6 +4538,51 @@
+
+ ac_config_files="$ac_config_files Apple/iOS/Resources/Info.plist"
+
++ ;;
++ tvOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=Apple/tvOS/Resources
++
++ ac_config_files="$ac_config_files Apple/tvOS/Resources/Info.plist"
++
++ ;;
++ visionOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=Apple/visionOS/Resources
++
++ ac_config_files="$ac_config_files Apple/visionOS/Resources/Info.plist"
++
++ ;;
++ watchOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=Apple/watchOS/Resources
++
++ ac_config_files="$ac_config_files Apple/watchOS/Resources/Info.plist"
++
+ ;;
+ *)
+ as_fn_error $? "Unknown platform for framework build" "$LINENO" 5
+@@ -4486,6 +4594,9 @@
+ e)
+ case $ac_sys_system in
+ iOS) as_fn_error $? "iOS builds must use --enable-framework" "$LINENO" 5 ;;
++ tvOS) as_fn_error $? "tvOS builds must use --enable-framework" "$LINENO" 5 ;;
++ visionOS) as_fn_error $? "visionOS builds must use --enable-framework" "$LINENO" 5 ;;
++ watchOS) as_fn_error $? "watchOS builds must use --enable-framework" "$LINENO" 5 ;;
+ *)
+ PYTHONFRAMEWORK=
+ PYTHONFRAMEWORKDIR=no-framework
+@@ -4540,8 +4651,8 @@
+ case "$withval" in
+ yes)
+ case $ac_sys_system in
+- Darwin|iOS)
+- # iOS is able to share the macOS patch
++ Darwin|iOS|tvOS|visionOS|watchOS)
++ # iOS/tvOS/visionOS/watchOS is able to share the macOS patch
+ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
+ ;;
+ *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;;
+@@ -4559,8 +4670,8 @@
+ else case e in #(
+ e)
+ case $ac_sys_system in
+- iOS)
+- # Always apply the compliance patch on iOS; we can use the macOS patch
++ iOS|tvOS|visionOS|watchOS)
++ # Always apply the compliance patch on iOS/tvOS/visionOS/watchOS; we can use the macOS patch
+ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5
+ printf "%s\n" "applying default app store compliance patch" >&6; }
+@@ -4578,6 +4689,8 @@
+
+
+
++EXPORT_XROS_DEPLOYMENT_TARGET='#'
++
+
+ if test "$cross_compiling" = yes; then
+ case "$host" in
+@@ -4615,6 +4728,78 @@
+ ;;
+ esac
+ ;;
++ *-apple-tvos*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking tvOS deployment target" >&5
++printf %s "checking tvOS deployment target... " >&6; }
++ TVOS_DEPLOYMENT_TARGET=${_host_os:4}
++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0}
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $TVOS_DEPLOYMENT_TARGET" >&5
++printf "%s\n" "$TVOS_DEPLOYMENT_TARGET" >&6; }
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device}
++ ;;
++ *)
++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device}
++ ;;
++ esac
++ ;;
++ *-apple-xros*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # XROS_DEPLOYMENT_TARGET is the minimum supported visionOS version
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking visionOS deployment target" >&5
++printf %s "checking visionOS deployment target... " >&6; }
++ XROS_DEPLOYMENT_TARGET=${_host_os:8}
++ XROS_DEPLOYMENT_TARGET=${XROS_DEPLOYMENT_TARGET:=2.0}
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $XROS_DEPLOYMENT_TARGET" >&5
++printf "%s\n" "$XROS_DEPLOYMENT_TARGET" >&6; }
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking exporting flag of visionOS deployment target" >&5
++printf %s "checking exporting flag of visionOS deployment target... " >&6; }
++ export XROS_DEPLOYMENT_TARGET
++ EXPORT_XROS_DEPLOYMENT_TARGET=''
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $EXPORT_XROS_DEPLOYMENT_TARGET" >&5
++printf "%s\n" "$EXPORT_XROS_DEPLOYMENT_TARGET" >&6; }
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${XROS_DEPLOYMENT_TARGET}-arm64-xr${_host_device}
++ ;;
++ *)
++ _host_ident=${XROS_DEPLOYMENT_TARGET}-$host_cpu-xr${_host_device}
++ ;;
++ esac
++ ;;
+ *-apple-watchos*)
-+ ac_sys_system=watchOS
-+ ;;
- *-*-vxworks*)
- ac_sys_system=VxWorks
- ;;
-@@ -3876,6 +3875,15 @@
- *-*-cygwin*)
- _host_cpu=
- ;;
-+ *-apple-*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking watchOS deployment target" >&5
++printf %s "checking watchOS deployment target... " >&6; }
++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7}
++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0}
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WATCHOS_DEPLOYMENT_TARGET" >&5
++printf "%s\n" "$WATCHOS_DEPLOYMENT_TARGET" >&6; }
++
+ case "$host_cpu" in
-+ arm*)
-+ _host_cpu=arm
-+ ;;
-+ *)
-+ _host_cpu=$host_cpu
++ aarch64)
++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device}
++ ;;
++ *)
++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device}
++ ;;
+ esac
+ ;;
- *-*-vxworks*)
- _host_cpu=$host_cpu
- ;;
-@@ -3954,6 +3962,13 @@
+ *-*-darwin*)
+ case "$host_cpu" in
+ arm*)
+@@ -4705,9 +4890,15 @@
define_xopen_source=no;;
Darwin/[12][0-9].*)
define_xopen_source=no;;
-+ # On iOS, defining _POSIX_C_SOURCE also disables platform specific features.
-+ iOS/*)
-+ define_xopen_source=no;;
+- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features.
++ # On iOS/tvOS/visionOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features.
+ iOS/*)
+ define_xopen_source=no;;
+ tvOS/*)
+ define_xopen_source=no;;
++ visionOS/*)
++ define_xopen_source=no;;
+ watchOS/*)
+ define_xopen_source=no;;
# On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
# defining NI_NUMERICHOST.
QNX/6.3.2)
-@@ -6146,7 +6161,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
- #elif defined(__wasm32__)
-@@ -6191,6 +6229,12 @@
- case $ac_sys_system in #(
- Darwin*) :
+@@ -4770,7 +4961,14 @@
+ CONFIGURE_MACOSX_DEPLOYMENT_TARGET=
+ EXPORT_MACOSX_DEPLOYMENT_TARGET='#'
+
+-# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple.
++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET /
++# XROS_DEPLOYMENT_TARGET / WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple.
++
++
++
++
++
++# XROS_DEPLOYMENT_TARGET should get exported
+
+
+ # checks for alternative programs
+@@ -4811,6 +5009,16 @@
+ as_fn_append CFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"
+ as_fn_append LDFLAGS " -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"
+ ;; #(
++ tvOS) :
++
++ as_fn_append CFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"
++ as_fn_append LDFLAGS " -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"
++ ;; #(
++ watchOS) :
++
++ as_fn_append CFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"
++ as_fn_append LDFLAGS " -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"
++ ;; #(
+ *) :
+ ;;
+ esac
+@@ -7180,6 +7388,12 @@
+ MULTIARCH="" ;; #(
+ iOS) :
MULTIARCH="" ;; #(
-+ iOS*) :
++ tvOS) :
+ MULTIARCH="" ;; #(
-+ tvOS*) :
++ visionOS) :
+ MULTIARCH="" ;; #(
-+ watchOS*) :
++ watchOS) :
+ MULTIARCH="" ;; #(
FreeBSD*) :
MULTIARCH="" ;; #(
*) :
-@@ -6253,7 +6297,7 @@
- x86_64-*-freebsd*/clang) :
- PY_SUPPORT_TIER=3 ;; #(
- *) :
-- PY_SUPPORT_TIER=0
-+ PY_SUPPORT_TIER=0
- ;;
- esac
-
-@@ -7052,11 +7096,23 @@
- fi
-
- if test "$cross_compiling" = yes; then
-- case "$READELF" in
-- readelf|:)
-- as_fn_error $? "readelf for the host is required for cross builds" "$LINENO" 5
-- ;;
-- esac
-+ case "$host" in
-+ *-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|:)
-+ as_fn_error $? "readelf for the host is required for cross builds" "$LINENO" 5
-+ ;;
-+ esac
-+ esac
- fi
+@@ -7200,7 +7414,7 @@
+ printf "%s\n" "$MULTIARCH" >&6; }
-
-@@ -10709,6 +10765,9 @@
+ case $ac_sys_system in #(
+- iOS) :
++ iOS|tvOS|visionOS|watchOS) :
+ SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2` ;; #(
+ *) :
+ SOABI_PLATFORM=$PLATFORM_TRIPLET
+@@ -7263,6 +7477,18 @@
+ PY_SUPPORT_TIER=3 ;; #(
+ aarch64-apple-ios*/clang) :
+ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-tvos*-simulator/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-tvos*/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-xros*-simulator/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-xros*/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ aarch64-apple-watchos*-simulator/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
++ arm64_32-apple-watchos*/clang) :
++ PY_SUPPORT_TIER=3 ;; #(
+ aarch64-*-linux-android/clang) :
+ PY_SUPPORT_TIER=3 ;; #(
+ x86_64-*-linux-android/clang) :
+@@ -7701,7 +7927,7 @@
+ case $ac_sys_system in
+ Darwin)
+ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';;
+- iOS)
++ iOS|tvOS|visionOS|watchOS)
+ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';;
+ *)
+ as_fn_error $? "Unknown platform for framework build" "$LINENO" 5;;
+@@ -7767,7 +7993,7 @@
+ BLDLIBRARY='-L. -lpython$(LDVERSION)'
+ RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}
+ ;;
+- iOS)
++ iOS|tvOS|visionOS|watchOS)
+ LDLIBRARY='libpython$(LDVERSION).dylib'
+ ;;
+ AIX*)
+@@ -13583,7 +13809,7 @@
BLDSHARED="$LDSHARED"
fi
;;
-+ iOS/*|tvOS/*|watchOS/*)
-+ LDSHARED='$(CC) -bundle -undefined dynamic_lookup'
-+ LDCXXSHARED='$(CXX) -bundle -undefined dynamic_lookup';;
- Emscripten|WASI)
- LDSHARED='$(CC) -shared'
- LDCXXSHARED='$(CXX) -shared';;
-@@ -11117,8 +11176,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBUUID" >&5
--$as_echo_n "checking for LIBUUID... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for uuid >= 2.20" >&5
-+$as_echo_n "checking for uuid >= 2.20... " >&6; }
-
- if test -n "$LIBUUID_CFLAGS"; then
- pkg_cv_LIBUUID_CFLAGS="$LIBUUID_CFLAGS"
-@@ -11158,7 +11217,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -11301,7 +11360,7 @@
-
-
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- save_CFLAGS=$CFLAGS
-@@ -11952,23 +12011,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"
+- iOS/*)
++ iOS/*|tvOS/*|visionOS/*|watchOS/*)
+ LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)'
+ LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)'
+ BLDSHARED="$LDSHARED"
+@@ -13716,7 +13942,7 @@
+ Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";;
+ Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";;
+ # -u libsys_s pulls in all symbols in libsys
+- Darwin/*|iOS/*)
++ Darwin/*|iOS/*|tvOS/*|visionOS/*|watchOS/*)
+ LINKFORSHARED="$extra_undefs -framework CoreFoundation"
+
+ # Issue #18075: the default maximum stack size (8MBytes) is too
+@@ -13740,7 +13966,7 @@
+ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
+ fi
+ LINKFORSHARED="$LINKFORSHARED"
+- elif test $ac_sys_system = "iOS"; then
++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "visionOS" -o "$ac_sys_system" = "watchOS"; then
+ LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
+ fi
+ ;;
+@@ -15517,7 +15743,7 @@
+
+ ctypes_malloc_closure=yes
+ ;; #(
+- iOS) :
++ iOS|tvOS|visionOS|watchOS) :
+
+ ctypes_malloc_closure=yes
+ ;; #(
+@@ -19287,12 +19513,6 @@
+ then :
+ printf "%s\n" "#define HAVE_DUP3 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv"
+-if test "x$ac_cv_func_execv" = xyes
+-then :
+- printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero"
+ if test "x$ac_cv_func_explicit_bzero" = xyes
+@@ -19353,18 +19573,6 @@
+ then :
+ printf "%s\n" "#define HAVE_FEXECVE 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork"
+-if test "x$ac_cv_func_fork" = xyes
+-then :
+- printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h
+-
+-fi
+-ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1"
+-if test "x$ac_cv_func_fork1" = xyes
+-then :
+- printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "fpathconf" "ac_cv_func_fpathconf"
+ if test "x$ac_cv_func_fpathconf" = xyes
+@@ -19797,24 +20005,6 @@
+ then :
+ printf "%s\n" "#define HAVE_POSIX_OPENPT 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn"
+-if test "x$ac_cv_func_posix_spawn" = xyes
+-then :
+- printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h
+-
+-fi
+-ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp"
+-if test "x$ac_cv_func_posix_spawnp" = xyes
+-then :
+- printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h
+-
+-fi
+-ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np"
+-if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes
+-then :
+- printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h
+-
+ fi
+ ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread"
+ if test "x$ac_cv_func_pread" = xyes
+@@ -20133,12 +20323,6 @@
+ then :
+ printf "%s\n" "#define HAVE_SIGACTION 1" >>confdefs.h
+
+-fi
+-ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack"
+-if test "x$ac_cv_func_sigaltstack" = xyes
+-then :
+- printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h
+-
fi
+ ac_fn_c_check_func "$LINENO" "sigfillset" "ac_cv_func_sigfillset"
+ if test "x$ac_cv_func_sigfillset" = xyes
+@@ -20407,11 +20591,11 @@
- 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
+-# iOS defines some system methods that can be linked (so they are
++# iOS/tvOS/visionOS/watchOS define some system methods that can be linked (so they are
+ # found by configure), but either raise a compilation error (because the
+ # header definition prevents usage - autoconf doesn't use the headers), or
+ # raise an error if used at runtime. Force these symbols off.
+-if test "$ac_sys_system" != "iOS" ; then
++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "visionOS" -a "$ac_sys_system" != "watchOS" ; then
+ ac_fn_c_check_func "$LINENO" "getentropy" "ac_cv_func_getentropy"
+ if test "x$ac_cv_func_getentropy" = xyes
+ then :
+@@ -20433,6 +20617,53 @@
+ fi
+
++# tvOS/watchOS have some additional methods that can be found, but not used.
++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
++ ac_fn_c_check_func "$LINENO" "execv" "ac_cv_func_execv"
++if test "x$ac_cv_func_execv" = xyes
++then :
++ printf "%s\n" "#define HAVE_EXECV 1" >>confdefs.h
+
++fi
++ac_fn_c_check_func "$LINENO" "fork" "ac_cv_func_fork"
++if test "x$ac_cv_func_fork" = xyes
++then :
++ printf "%s\n" "#define HAVE_FORK 1" >>confdefs.h
+
- # 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; }
-@@ -12109,8 +12180,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBNSL" >&5
--$as_echo_n "checking for LIBNSL... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libnsl" >&5
-+$as_echo_n "checking for libnsl... " >&6; }
-
- if test -n "$LIBNSL_CFLAGS"; then
- pkg_cv_LIBNSL_CFLAGS="$LIBNSL_CFLAGS"
-@@ -12150,7 +12221,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -12251,7 +12322,7 @@
- LIBNSL_LIBS=${LIBNSL_LIBS-$libnsl}
-
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- LIBNSL_CFLAGS=${LIBNSL_CFLAGS-""}
-@@ -12399,8 +12470,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSQLITE3" >&5
--$as_echo_n "checking for LIBSQLITE3... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqlite3 >= 3.7.15" >&5
-+$as_echo_n "checking for sqlite3 >= 3.7.15... " >&6; }
-
- if test -n "$LIBSQLITE3_CFLAGS"; then
- pkg_cv_LIBSQLITE3_CFLAGS="$LIBSQLITE3_CFLAGS"
-@@ -12440,7 +12511,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -12462,7 +12533,7 @@
-
-
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- LIBSQLITE3_CFLAGS=${LIBSQLITE3_CFLAGS-""}
-@@ -13231,8 +13302,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TCLTK" >&5
--$as_echo_n "checking for TCLTK... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $_QUERY" >&5
-+$as_echo_n "checking for $_QUERY... " >&6; }
-
- if test -n "$TCLTK_CFLAGS"; then
- pkg_cv_TCLTK_CFLAGS="$TCLTK_CFLAGS"
-@@ -13272,7 +13343,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -13290,7 +13361,7 @@
-
- found_tcltk=no
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
- found_tcltk=no
- else
-@@ -13326,8 +13397,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for X11" >&5
--$as_echo_n "checking for X11... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for x11" >&5
-+$as_echo_n "checking for x11... " >&6; }
-
- if test -n "$X11_CFLAGS"; then
- pkg_cv_X11_CFLAGS="$X11_CFLAGS"
-@@ -13367,7 +13438,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -13394,7 +13465,7 @@
- and X11_LIBS to avoid the need to call pkg-config.
- See the pkg-config man page for more details." "$LINENO" 5
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
- $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-@@ -15969,8 +16040,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ZLIB" >&5
--$as_echo_n "checking for ZLIB... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for zlib >= 1.2.0" >&5
-+$as_echo_n "checking for zlib >= 1.2.0... " >&6; }
-
- if test -n "$ZLIB_CFLAGS"; then
- pkg_cv_ZLIB_CFLAGS="$ZLIB_CFLAGS"
-@@ -16010,7 +16081,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -16154,7 +16225,7 @@
-
-
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- save_CFLAGS=$CFLAGS
-@@ -16317,8 +16388,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BZIP2" >&5
--$as_echo_n "checking for BZIP2... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for bzip2" >&5
-+$as_echo_n "checking for bzip2... " >&6; }
-
- if test -n "$BZIP2_CFLAGS"; then
- pkg_cv_BZIP2_CFLAGS="$BZIP2_CFLAGS"
-@@ -16358,7 +16429,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -16455,7 +16526,7 @@
-
-
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- save_CFLAGS=$CFLAGS
-@@ -16547,8 +16618,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBLZMA" >&5
--$as_echo_n "checking for LIBLZMA... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for liblzma" >&5
-+$as_echo_n "checking for liblzma... " >&6; }
-
- if test -n "$LIBLZMA_CFLAGS"; then
- pkg_cv_LIBLZMA_CFLAGS="$LIBLZMA_CFLAGS"
-@@ -16588,7 +16659,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -16685,7 +16756,7 @@
-
-
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- save_CFLAGS=$CFLAGS
-@@ -17918,8 +17989,8 @@
-
-
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBCRYPT" >&5
--$as_echo_n "checking for LIBCRYPT... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libxcrypt >= 3.1.1" >&5
-+$as_echo_n "checking for libxcrypt >= 3.1.1... " >&6; }
-
- if test -n "$LIBCRYPT_CFLAGS"; then
- pkg_cv_LIBCRYPT_CFLAGS="$LIBCRYPT_CFLAGS"
-@@ -17959,7 +18030,7 @@
-
-
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
-
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -18056,7 +18127,7 @@
-
-
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
++fi
++ac_fn_c_check_func "$LINENO" "fork1" "ac_cv_func_fork1"
++if test "x$ac_cv_func_fork1" = xyes
++then :
++ printf "%s\n" "#define HAVE_FORK1 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn"
++if test "x$ac_cv_func_posix_spawn" = xyes
++then :
++ printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "posix_spawnp" "ac_cv_func_posix_spawnp"
++if test "x$ac_cv_func_posix_spawnp" = xyes
++then :
++ printf "%s\n" "#define HAVE_POSIX_SPAWNP 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "posix_spawn_file_actions_addclosefrom_np" "ac_cv_func_posix_spawn_file_actions_addclosefrom_np"
++if test "x$ac_cv_func_posix_spawn_file_actions_addclosefrom_np" = xyes
++then :
++ printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSEFROM_NP 1" >>confdefs.h
++
++fi
++ac_fn_c_check_func "$LINENO" "sigaltstack" "ac_cv_func_sigaltstack"
++if test "x$ac_cv_func_sigaltstack" = xyes
++then :
++ printf "%s\n" "#define HAVE_SIGALTSTACK 1" >>confdefs.h
++
++fi
++
++fi
++
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
+ printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
+ if test ${ac_cv_c_undeclared_builtin_options+y}
+@@ -23904,7 +24135,8 @@
- save_CFLAGS=$CFLAGS
-@@ -22828,8 +22899,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"
-@@ -23210,8 +23281,8 @@
+ # check for openpty, login_tty, and forkpty
+-
++# tvOS/watchOS have functions for tty, but can't use them
++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
- pkg_failed=no
--{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBB2" >&5
--$as_echo_n "checking for LIBB2... " >&6; }
-+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libb2" >&5
-+$as_echo_n "checking for libb2... " >&6; }
+ for ac_func in openpty
+ do :
+@@ -24018,7 +24250,7 @@
+ fi
- if test -n "$LIBB2_CFLAGS"; then
- pkg_cv_LIBB2_CFLAGS="$LIBB2_CFLAGS"
-@@ -23251,7 +23322,7 @@
+ done
+-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5
++ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5
+ printf %s "checking for library containing login_tty... " >&6; }
+ if test ${ac_cv_search_login_tty+y}
+ then :
+@@ -24201,6 +24433,7 @@
+ fi
+ done
++fi
+
+ # check for long file support functions
+ ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64"
+@@ -24466,10 +24699,10 @@
+
+ done
+
+-# On Android and iOS, clock_settime can be linked (so it is found by
++# On Android, iOS, tvOS, visionOS, and watchOS, clock_settime can be linked (so it is found by
+ # configure), but when used in an unprivileged process, it crashes rather than
+ # returning an error. Force the symbol off.
+-if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS"
++if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "visionOS" -a "$ac_sys_system" != "watchOS"
+ then
+
+ for ac_func in clock_settime
+@@ -24786,7 +25019,7 @@
+ e) if test "$cross_compiling" = yes
+ then :
+
+-if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then
++if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS" || test "$ac_sys_system" = "tvOS" || test "$ac_sys_system" = "visionOS" || test "$ac_sys_system" = "watchOS"; then
+ ac_cv_buggy_getaddrinfo="no"
+ elif test "${enable_ipv6+set}" = set; then
+ ac_cv_buggy_getaddrinfo="no -- configured with --(en|dis)able-ipv6"
+@@ -26808,8 +27041,8 @@
+ LIBPYTHON="\$(BLDLIBRARY)"
+ fi
- if test $pkg_failed = yes; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
+-# On iOS the shared libraries must be linked with the Python framework
+-if test "$ac_sys_system" = "iOS"; then
++# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework
++if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "visionOS" -o $ac_sys_system = "watchOS"; then
+ MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)"
+ fi
- if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-@@ -23269,7 +23340,7 @@
+@@ -29575,7 +29808,7 @@
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for device files" >&5
+ printf "%s\n" "$as_me: checking for device files" >&6;}
- have_libb2=no
- elif test $pkg_failed = untried; then
-- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
- $as_echo "no" >&6; }
- have_libb2=no
+-if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then
++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "visionOS" -o "$ac_sys_system" = "watchOS" ; then
+ ac_cv_file__dev_ptmx=no
+ ac_cv_file__dev_ptc=no
else
-@@ -23340,6 +23411,29 @@
- py_cv_module_ossaudiodev=n/a
- py_cv_module_spwd=n/a
+@@ -30082,7 +30315,7 @@
+ with_ensurepip=no ;; #(
+ WASI) :
+ with_ensurepip=no ;; #(
+- iOS) :
++ iOS|tvOS|visionOS|watchOS) :
+ with_ensurepip=no ;; #(
+ *) :
+ with_ensurepip=upgrade
+@@ -31032,6 +31265,9 @@
+ NetBSD*) _PYTHREAD_NAME_MAXLEN=15;; # gh-131268
+ Darwin) _PYTHREAD_NAME_MAXLEN=63;;
+ iOS) _PYTHREAD_NAME_MAXLEN=63;;
++ tvOS) _PYTHREAD_NAME_MAXLEN=63;;
++ visionOS) _PYTHREAD_NAME_MAXLEN=63;;
++ watchOS) _PYTHREAD_NAME_MAXLEN=63;;
+ FreeBSD*) _PYTHREAD_NAME_MAXLEN=19;; # gh-131268
+ OpenBSD*) _PYTHREAD_NAME_MAXLEN=23;; # gh-131268
+ *) _PYTHREAD_NAME_MAXLEN=;;
+@@ -31063,7 +31299,7 @@
;; #(
-+ iOS|tvOS|watchOS) :
-+
-+
-+
-+ py_cv_module__curses=n/a
-+ py_cv_module__curses_panel=n/a
-+ py_cv_module__gdbm=n/a
-+ py_cv_module__multiprocessing=n/a
-+ py_cv_module__posixshmem=n/a
-+ py_cv_module__posixsubprocess=n/a
-+ py_cv_module__scproxy=n/a
-+ py_cv_module__tkinter=n/a
-+ py_cv_module__xxsubinterpreters=n/a
-+ py_cv_module_grp=n/a
-+ py_cv_module_nis=n/a
-+ py_cv_module_ossaudiodev=n/a
-+ py_cv_module_readline=n/a
-+ py_cv_module_pwd=n/a
-+ py_cv_module_spwd=n/a
-+ py_cv_module_syslog=n/a
-+ py_cv_module_=n/a
-+
-+ ;; #(
- CYGWIN*) :
-
-
+ Darwin) :
+ ;; #(
+- iOS) :
++ iOS|tvOS|visionOS|watchOS) :
+
+
+
+@@ -35231,6 +35467,9 @@
+ "Mac/Resources/framework/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/framework/Info.plist" ;;
+ "Mac/Resources/app/Info.plist") CONFIG_FILES="$CONFIG_FILES Mac/Resources/app/Info.plist" ;;
+ "Apple/iOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES Apple/iOS/Resources/Info.plist" ;;
++ "Apple/tvOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES Apple/tvOS/Resources/Info.plist" ;;
++ "Apple/visionOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES Apple/visionOS/Resources/Info.plist" ;;
++ "Apple/watchOS/Resources/Info.plist") CONFIG_FILES="$CONFIG_FILES Apple/watchOS/Resources/Info.plist" ;;
+ "Makefile.pre") CONFIG_FILES="$CONFIG_FILES Makefile.pre" ;;
+ "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;;
+ "Misc/python-embed.pc") CONFIG_FILES="$CONFIG_FILES Misc/python-embed.pc" ;;
diff --git a/configure.ac b/configure.ac
-index ab5e1de6fa..99d3147959 100644
+index bd4446e9488..6bef5ef8a56 100644
--- a/configure.ac
+++ b/configure.ac
-@@ -545,6 +545,15 @@
- *-*-cygwin*)
- ac_sys_system=Cygwin
+@@ -330,6 +330,15 @@
+ *-apple-ios*)
+ ac_sys_system=iOS
;;
-+ *-apple-ios*)
-+ ac_sys_system=iOS
-+ ;;
+ *-apple-tvos*)
+ ac_sys_system=tvOS
+ ;;
++ *-apple-xros*)
++ ac_sys_system=visionOS
++ ;;
+ *-apple-watchos*)
+ ac_sys_system=watchOS
+ ;;
- *-*-vxworks*)
- ac_sys_system=VxWorks
- ;;
-@@ -600,6 +609,15 @@
- *-*-cygwin*)
- _host_cpu=
+ *-*-darwin*)
+ ac_sys_system=Darwin
+ ;;
+@@ -405,7 +414,7 @@
+ # On cross-compile builds, configure will look for a host-specific compiler by
+ # prepending the user-provided host triple to the required binary name.
+ #
+-# On iOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc",
++# On iOS/tvOS/visionOS/watchOS, this results in binaries like "arm64-apple-ios13.0-simulator-gcc",
+ # which isn't a binary that exists, and isn't very convenient, as it contains the
+ # iOS version. As the default cross-compiler name won't exist, configure falls
+ # back to gcc, which *definitely* won't work. We're providing wrapper scripts for
+@@ -420,6 +429,17 @@
+ aarch64-apple-ios*-simulator) AR=arm64-apple-ios-simulator-ar ;;
+ aarch64-apple-ios*) AR=arm64-apple-ios-ar ;;
+ x86_64-apple-ios*-simulator) AR=x86_64-apple-ios-simulator-ar ;;
++
++ aarch64-apple-tvos*-simulator) AR=arm64-apple-tvos-simulator-ar ;;
++ aarch64-apple-tvos*) AR=arm64-apple-tvos-ar ;;
++ x86_64-apple-tvos*-simulator) AR=x86_64-apple-tvos-simulator-ar ;;
++
++ aarch64-apple-xros*-simulator) AR=arm64-apple-xros-simulator-ar ;;
++ aarch64-apple-xros*) AR=arm64-apple-xros-ar ;;
++
++ aarch64-apple-watchos*-simulator) AR=arm64-apple-watchos-simulator-ar ;;
++ aarch64-apple-watchos*) AR=arm64_32-apple-watchos-ar ;;
++ x86_64-apple-watchos*-simulator) AR=x86_64-apple-watchos-simulator-ar ;;
+ *)
+ esac
+ fi
+@@ -428,6 +448,17 @@
+ aarch64-apple-ios*-simulator) CC=arm64-apple-ios-simulator-clang ;;
+ aarch64-apple-ios*) CC=arm64-apple-ios-clang ;;
+ x86_64-apple-ios*-simulator) CC=x86_64-apple-ios-simulator-clang ;;
++
++ aarch64-apple-tvos*-simulator) CC=arm64-apple-tvos-simulator-clang ;;
++ aarch64-apple-tvos*) CC=arm64-apple-tvos-clang ;;
++ x86_64-apple-tvos*-simulator) CC=x86_64-apple-tvos-simulator-clang ;;
++
++ aarch64-apple-xros*-simulator) CC=arm64-apple-xros-simulator-clang ;;
++ aarch64-apple-xros*) CC=arm64-apple-xros-clang ;;
++
++ aarch64-apple-watchos*-simulator) CC=arm64-apple-watchos-simulator-clang ;;
++ aarch64-apple-watchos*) CC=arm64_32-apple-watchos-clang ;;
++ x86_64-apple-watchos*-simulator) CC=x86_64-apple-watchos-simulator-clang ;;
+ *)
+ esac
+ fi
+@@ -436,6 +467,17 @@
+ aarch64-apple-ios*-simulator) CPP=arm64-apple-ios-simulator-cpp ;;
+ aarch64-apple-ios*) CPP=arm64-apple-ios-cpp ;;
+ x86_64-apple-ios*-simulator) CPP=x86_64-apple-ios-simulator-cpp ;;
++
++ aarch64-apple-tvos*-simulator) CPP=arm64-apple-tvos-simulator-cpp ;;
++ aarch64-apple-tvos*) CPP=arm64-apple-tvos-cpp ;;
++ x86_64-apple-tvos*-simulator) CPP=x86_64-apple-tvos-simulator-cpp ;;
++
++ aarch64-apple-xros*-simulator) CPP=arm64-apple-xros-simulator-cpp ;;
++ aarch64-apple-xros*) CPP=arm64-apple-xros-cpp ;;
++
++ aarch64-apple-watchos*-simulator) CPP=arm64-apple-watchos-simulator-cpp ;;
++ aarch64-apple-watchos*) CPP=arm64_32-apple-watchos-cpp ;;
++ x86_64-apple-watchos*-simulator) CPP=x86_64-apple-watchos-simulator-cpp ;;
+ *)
+ esac
+ fi
+@@ -444,6 +486,17 @@
+ aarch64-apple-ios*-simulator) CXX=arm64-apple-ios-simulator-clang++ ;;
+ aarch64-apple-ios*) CXX=arm64-apple-ios-clang++ ;;
+ x86_64-apple-ios*-simulator) CXX=x86_64-apple-ios-simulator-clang++ ;;
++
++ aarch64-apple-tvos*-simulator) CXX=arm64-apple-tvos-simulator-clang++ ;;
++ aarch64-apple-tvos*) CXX=arm64-apple-tvos-clang++ ;;
++ x86_64-apple-tvos*-simulator) CXX=x86_64-apple-tvos-simulator-clang++ ;;
++
++ aarch64-apple-xros*-simulator) CXX=arm64-apple-xros-simulator-clang++ ;;
++ aarch64-apple-xros*) CXX=arm64-apple-xros-clang++ ;;
++
++ aarch64-apple-watchos*-simulator) CXX=arm64-apple-watchos-simulator-clang++ ;;
++ aarch64-apple-watchos*) CXX=arm64_32-apple-watchos-clang++ ;;
++ x86_64-apple-watchos*-simulator) CXX=x86_64-apple-watchos-simulator-clang++ ;;
+ *)
+ esac
+ fi
+@@ -558,8 +611,11 @@
+ case $enableval in
+ yes)
+ case $ac_sys_system in
+- Darwin) enableval=/Library/Frameworks ;;
+- iOS) enableval=Apple/iOS/Frameworks/\$\(MULTIARCH\) ;;
++ Darwin) enableval=/Library/Frameworks ;;
++ iOS) enableval=Apple/iOS/Frameworks/\$\(MULTIARCH\) ;;
++ tvOS) enableval=Apple/tvOS/Frameworks/\$\(MULTIARCH\) ;;
++ visionOS) enableval=Apple/visionOS/Frameworks/\$\(MULTIARCH\) ;;
++ watchOS) enableval=Apple/watchOS/Frameworks/\$\(MULTIARCH\) ;;
+ *) AC_MSG_ERROR([Unknown platform for framework build])
+ esac
+ esac
+@@ -568,6 +624,9 @@
+ no)
+ case $ac_sys_system in
+ iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;;
++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;;
++ visionOS) AC_MSG_ERROR([visionOS builds must use --enable-framework]) ;;
++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;;
+ *)
+ PYTHONFRAMEWORK=
+ PYTHONFRAMEWORKDIR=no-framework
+@@ -670,6 +729,48 @@
+
+ AC_CONFIG_FILES([Apple/iOS/Resources/Info.plist])
+ ;;
++ tvOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=Apple/tvOS/Resources
++
++ AC_CONFIG_FILES([Apple/tvOS/Resources/Info.plist])
++ ;;
++ visionOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=Apple/visionOS/Resources
++
++ AC_CONFIG_FILES([Apple/visionOS/Resources/Info.plist])
++ ;;
++ watchOS) :
++ FRAMEWORKINSTALLFIRST="frameworkinstallunversionedstructure"
++ FRAMEWORKALTINSTALLFIRST="frameworkinstallunversionedstructure "
++ FRAMEWORKINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKALTINSTALLLAST="frameworkinstallmobileheaders"
++ FRAMEWORKPYTHONW=
++ INSTALLTARGETS="libinstall inclinstall sharedinstall"
++
++ prefix=$PYTHONFRAMEWORKPREFIX
++ PYTHONFRAMEWORKINSTALLNAMEPREFIX="@rpath/$PYTHONFRAMEWORKDIR"
++ RESSRCDIR=Apple/watchOS/Resources
++
++ AC_CONFIG_FILES([Apple/watchOS/Resources/Info.plist])
++ ;;
+ *)
+ AC_MSG_ERROR([Unknown platform for framework build])
+ ;;
+@@ -678,6 +779,9 @@
+ ],[
+ case $ac_sys_system in
+ iOS) AC_MSG_ERROR([iOS builds must use --enable-framework]) ;;
++ tvOS) AC_MSG_ERROR([tvOS builds must use --enable-framework]) ;;
++ visionOS) AC_MSG_ERROR([visionOS builds must use --enable-framework]) ;;
++ watchOS) AC_MSG_ERROR([watchOS builds must use --enable-framework]) ;;
+ *)
+ PYTHONFRAMEWORK=
+ PYTHONFRAMEWORKDIR=no-framework
+@@ -730,8 +834,8 @@
+ case "$withval" in
+ yes)
+ case $ac_sys_system in
+- Darwin|iOS)
+- # iOS is able to share the macOS patch
++ Darwin|iOS|tvOS|visionOS|watchOS)
++ # iOS/tvOS/visionOS/watchOS is able to share the macOS patch
+ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
+ ;;
+ *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;;
+@@ -745,8 +849,8 @@
+ esac
+ ],[
+ case $ac_sys_system in
+- iOS)
+- # Always apply the compliance patch on iOS; we can use the macOS patch
++ iOS|tvOS|visionOS|watchOS)
++ # Always apply the compliance patch on iOS/tvOS/visionOS/watchOS; we can use the macOS patch
+ APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
+ AC_MSG_RESULT([applying default app store compliance patch])
+ ;;
+@@ -759,6 +863,8 @@
+ ])
+ AC_SUBST([APP_STORE_COMPLIANCE_PATCH])
+
++EXPORT_XROS_DEPLOYMENT_TARGET='#'
++
+ AC_SUBST([_PYTHON_HOST_PLATFORM])
+ if test "$cross_compiling" = yes; then
+ case "$host" in
+@@ -794,6 +900,70 @@
+ ;;
+ esac
;;
-+ *-apple-*)
++ *-apple-tvos*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # TVOS_DEPLOYMENT_TARGET is the minimum supported tvOS version
++ AC_MSG_CHECKING([tvOS deployment target])
++ TVOS_DEPLOYMENT_TARGET=${_host_os:4}
++ TVOS_DEPLOYMENT_TARGET=${TVOS_DEPLOYMENT_TARGET:=12.0}
++ AC_MSG_RESULT([$TVOS_DEPLOYMENT_TARGET])
++
+ case "$host_cpu" in
-+ arm*)
-+ _host_cpu=arm
-+ ;;
-+ *)
-+ _host_cpu=$host_cpu
++ aarch64)
++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-arm64-appletv${_host_device}
++ ;;
++ *)
++ _host_ident=${TVOS_DEPLOYMENT_TARGET}-$host_cpu-appletv${_host_device}
++ ;;
+ esac
+ ;;
- *-*-vxworks*)
- _host_cpu=$host_cpu
- ;;
-@@ -675,6 +693,13 @@
++ *-apple-xros*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # XROS_DEPLOYMENT_TARGET is the minimum supported visionOS version
++ AC_MSG_CHECKING([visionOS deployment target])
++ XROS_DEPLOYMENT_TARGET=${_host_os:8}
++ XROS_DEPLOYMENT_TARGET=${XROS_DEPLOYMENT_TARGET:=2.0}
++ AC_MSG_RESULT([$XROS_DEPLOYMENT_TARGET])
++ AC_MSG_CHECKING([exporting flag of visionOS deployment target])
++ export XROS_DEPLOYMENT_TARGET
++ EXPORT_XROS_DEPLOYMENT_TARGET=''
++ AC_MSG_RESULT([$EXPORT_XROS_DEPLOYMENT_TARGET])
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${XROS_DEPLOYMENT_TARGET}-arm64-xr${_host_device}
++ ;;
++ *)
++ _host_ident=${XROS_DEPLOYMENT_TARGET}-$host_cpu-xr${_host_device}
++ ;;
++ esac
++ ;;
++ *-apple-watchos*)
++ _host_os=`echo $host | cut -d '-' -f3`
++ _host_device=`echo $host | cut -d '-' -f4`
++ _host_device=${_host_device:=os}
++
++ # WATCHOS_DEPLOYMENT_TARGET is the minimum supported watchOS version
++ AC_MSG_CHECKING([watchOS deployment target])
++ WATCHOS_DEPLOYMENT_TARGET=${_host_os:7}
++ WATCHOS_DEPLOYMENT_TARGET=${WATCHOS_DEPLOYMENT_TARGET:=4.0}
++ AC_MSG_RESULT([$WATCHOS_DEPLOYMENT_TARGET])
++
++ case "$host_cpu" in
++ aarch64)
++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-arm64-watch${_host_device}
++ ;;
++ *)
++ _host_ident=${WATCHOS_DEPLOYMENT_TARGET}-$host_cpu-watch${_host_device}
++ ;;
++ esac
++ ;;
+ *-*-darwin*)
+ case "$host_cpu" in
+ arm*)
+@@ -883,9 +1053,15 @@
define_xopen_source=no;;
Darwin/@<:@[12]@:>@@<:@0-9@:>@.*)
define_xopen_source=no;;
-+ # On iOS, defining _POSIX_C_SOURCE also disables platform specific features.
-+ iOS/*)
-+ define_xopen_source=no;;
+- # On iOS, defining _POSIX_C_SOURCE also disables platform specific features.
++ # On iOS/tvOS/visionOS/watchOS, defining _POSIX_C_SOURCE also disables platform specific features.
+ iOS/*)
+ define_xopen_source=no;;
+ tvOS/*)
+ define_xopen_source=no;;
++ visionOS/*)
++ define_xopen_source=no;;
+ watchOS/*)
+ define_xopen_source=no;;
# On QNX 6.3.2, defining _XOPEN_SOURCE prevents netdb.h from
# defining NI_NUMERICHOST.
QNX/6.3.2)
-@@ -1044,7 +1069,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
- #elif defined(__wasm32__)
-@@ -1085,6 +1133,9 @@
- AC_MSG_CHECKING([for multiarch])
+@@ -944,8 +1120,15 @@
+ CONFIGURE_MACOSX_DEPLOYMENT_TARGET=
+ EXPORT_MACOSX_DEPLOYMENT_TARGET='#'
+
+-# Record the value of IPHONEOS_DEPLOYMENT_TARGET enforced by the selected host triple.
++# Record the value of IPHONEOS_DEPLOYMENT_TARGET / TVOS_DEPLOYMENT_TARGET /
++# XROS_DEPLOYMENT_TARGET / WATCHOS_DEPLOYMENT_TARGET enforced by the selected host triple.
+ AC_SUBST([IPHONEOS_DEPLOYMENT_TARGET])
++AC_SUBST([TVOS_DEPLOYMENT_TARGET])
++AC_SUBST([XROS_DEPLOYMENT_TARGET])
++AC_SUBST([WATCHOS_DEPLOYMENT_TARGET])
++
++# XROS_DEPLOYMENT_TARGET should get exported
++AC_SUBST([EXPORT_XROS_DEPLOYMENT_TARGET])
+
+ # checks for alternative programs
+
+@@ -979,11 +1162,19 @@
+ ],
+ )
+
+-dnl Add the compiler flag for the iOS minimum supported OS version.
++dnl Add the compiler flag for the iOS/tvOS/watchOS minimum supported OS
++dnl version. visionOS doesn't use an explicit -mxros-version-min option -
++dnl it encodes the min version into the target triple.
+ AS_CASE([$ac_sys_system],
+ [iOS], [
+ AS_VAR_APPEND([CFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"])
+ AS_VAR_APPEND([LDFLAGS], [" -mios-version-min=${IPHONEOS_DEPLOYMENT_TARGET}"])
++ ],[tvOS], [
++ AS_VAR_APPEND([CFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"])
++ AS_VAR_APPEND([LDFLAGS], [" -mtvos-version-min=${TVOS_DEPLOYMENT_TARGET}"])
++ ],[watchOS], [
++ AS_VAR_APPEND([CFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"])
++ AS_VAR_APPEND([LDFLAGS], [" -mwatchos-version-min=${WATCHOS_DEPLOYMENT_TARGET}"])
+ ],
+ )
+
+@@ -1172,6 +1363,9 @@
AS_CASE([$ac_sys_system],
[Darwin*], [MULTIARCH=""],
-+ [iOS*], [MULTIARCH=""],
-+ [tvOS*], [MULTIARCH=""],
-+ [watchOS*], [MULTIARCH=""],
+ [iOS], [MULTIARCH=""],
++ [tvOS], [MULTIARCH=""],
++ [visionOS], [MULTIARCH=""],
++ [watchOS], [MULTIARCH=""],
[FreeBSD*], [MULTIARCH=""],
[MULTIARCH=$($CC --print-multiarch 2>/dev/null)]
)
-@@ -1129,6 +1180,15 @@
- [wasm32-unknown-emscripten/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly Emscripten
- [wasm32-unknown-wasi/clang], [PY_SUPPORT_TIER=3], dnl WebAssembly System Interface
- [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64
-+ dnl [aarch64-apple-ios/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64
-+ dnl [aarch64-apple-ios-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64
-+ dnl [x86_64-apple-ios-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on x86_64
-+ dnl [aarch64-apple-tvos/clang], [PY_SUPPORT_TIER=3], dnl Apple tvOS on ARM64
-+ dnl [aarch64-apple-tvos-simulator/clang], [PY_SUPPORT_TIER=3], dnl Apple tvOS Simulator on ARM64
-+ dnl [x86_64-apple-tvos-simulator/clang], [PY_SUPPORT_TIER=3], dnl Apple tvOS Simulator on x86_64
-+ dnl [arm64_32-apple-watchos/clang], [PY_SUPPORT_TIER=3], dnl Apple watchOS on ARM64_32
-+ dnl [aarch64-apple-watchos-simulator/clang], [PY_SUPPORT_TIER=3], dnl Apple watchOS Simulator on ARM64
-+ dnl [x86_64-apple-watchos-simulator/clang], [PY_SUPPORT_TIER=3], dnl Apple watchOS Simulator on x86_64
- [PY_SUPPORT_TIER=0]
+@@ -1193,7 +1387,7 @@
+ dnl use a single "fat" binary at runtime. SOABI_PLATFORM is the component of
+ dnl the PLATFORM_TRIPLET that will be used in binary module extensions.
+ AS_CASE([$ac_sys_system],
+- [iOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`],
++ [iOS|tvOS|visionOS|watchOS], [SOABI_PLATFORM=`echo "$PLATFORM_TRIPLET" | cut -d '-' -f2`],
+ [SOABI_PLATFORM=$PLATFORM_TRIPLET]
)
-@@ -1591,11 +1651,23 @@
-
- AC_CHECK_TOOLS([READELF], [readelf], [:])
- if test "$cross_compiling" = yes; then
-- case "$READELF" in
-- readelf|:)
-- AC_MSG_ERROR([readelf for the host is required for cross builds])
-- ;;
-- esac
-+ case "$host" in
-+ *-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|:)
-+ AC_MSG_ERROR([readelf for the host is required for cross builds])
-+ ;;
-+ esac
-+ esac
- fi
- AC_SUBST(READELF)
+@@ -1228,16 +1422,22 @@
+ [wasm32-unknown-wasip1/clang], [PY_SUPPORT_TIER=2], dnl WebAssembly System Interface preview1, clang
+ [x86_64-*-linux-gnu/clang], [PY_SUPPORT_TIER=2], dnl Linux on AMD64, any vendor, glibc, clang
+
+- [aarch64-pc-windows-msvc/msvc], [PY_SUPPORT_TIER=3], dnl Windows ARM64, MSVC
+- [armv7l-*-linux-gnueabihf/gcc], [PY_SUPPORT_TIER=3], dnl ARMv7 LE with hardware floats, any vendor, glibc, gcc
+- [powerpc64le-*-linux-gnu/clang], [PY_SUPPORT_TIER=3], dnl Linux on PPC64 little endian, glibc, clang
+- [s390x-*-linux-gnu/gcc], [PY_SUPPORT_TIER=3], dnl Linux on 64bit s390x (big endian), glibc, gcc
+- [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64
+- [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64
+- [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64
+- [aarch64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on ARM64
+- [x86_64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on AMD64
+- [wasm32-*-emscripten/emcc], [PY_SUPPORT_TIER=3], dnl Emscripten
++ [aarch64-pc-windows-msvc/msvc], [PY_SUPPORT_TIER=3], dnl Windows ARM64, MSVC
++ [armv7l-*-linux-gnueabihf/gcc], [PY_SUPPORT_TIER=3], dnl ARMv7 LE with hardware floats, any vendor, glibc, gcc
++ [powerpc64le-*-linux-gnu/clang], [PY_SUPPORT_TIER=3], dnl Linux on PPC64 little endian, glibc, clang
++ [s390x-*-linux-gnu/gcc], [PY_SUPPORT_TIER=3], dnl Linux on 64bit s390x (big endian), glibc, gcc
++ [x86_64-*-freebsd*/clang], [PY_SUPPORT_TIER=3], dnl FreeBSD on AMD64
++ [aarch64-apple-ios*-simulator/clang], [PY_SUPPORT_TIER=3], dnl iOS Simulator on arm64
++ [aarch64-apple-ios*/clang], [PY_SUPPORT_TIER=3], dnl iOS on ARM64
++ [aarch64-apple-tvos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl tvOS Simulator on arm64
++ [aarch64-apple-tvos*/clang], [PY_SUPPORT_TIER=3], dnl tvOS on ARM64
++ [aarch64-apple-xros*-simulator/clang], [PY_SUPPORT_TIER=3], dnl visionOS Simulator on arm64
++ [aarch64-apple-xros*/clang], [PY_SUPPORT_TIER=3], dnl visionOS on ARM64
++ [aarch64-apple-watchos*-simulator/clang], [PY_SUPPORT_TIER=3], dnl watchOS Simulator on arm64
++ [arm64_32-apple-watchos*/clang], [PY_SUPPORT_TIER=3], dnl watchOS on ARM64
++ [aarch64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on ARM64
++ [x86_64-*-linux-android/clang], [PY_SUPPORT_TIER=3], dnl Android on AMD64
++ [wasm32-*-emscripten/emcc], [PY_SUPPORT_TIER=3], dnl Emscripten
-@@ -3129,6 +3201,9 @@
+ [PY_SUPPORT_TIER=0]
+ )
+@@ -1545,7 +1745,7 @@
+ case $ac_sys_system in
+ Darwin)
+ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)';;
+- iOS)
++ iOS|tvOS|visionOS|watchOS)
+ LDLIBRARY='$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)';;
+ *)
+ AC_MSG_ERROR([Unknown platform for framework build]);;
+@@ -1610,7 +1810,7 @@
+ BLDLIBRARY='-L. -lpython$(LDVERSION)'
+ RUNSHARED=DYLD_LIBRARY_PATH=`pwd`${DYLD_LIBRARY_PATH:+:${DYLD_LIBRARY_PATH}}
+ ;;
+- iOS)
++ iOS|tvOS|visionOS|watchOS)
+ LDLIBRARY='libpython$(LDVERSION).dylib'
+ ;;
+ AIX*)
+@@ -3477,7 +3677,7 @@
BLDSHARED="$LDSHARED"
fi
;;
-+ iOS/*|tvOS/*|watchOS/*)
-+ LDSHARED='$(CC) -bundle -undefined dynamic_lookup'
-+ LDCXXSHARED='$(CXX) -bundle -undefined dynamic_lookup';;
- Emscripten|WASI)
- LDSHARED='$(CC) -shared'
- LDCXXSHARED='$(CXX) -shared';;
-@@ -3598,20 +3673,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"
+- iOS/*)
++ iOS/*|tvOS/*|visionOS/*|watchOS/*)
+ LDSHARED='$(CC) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)'
+ LDCXXSHARED='$(CXX) -dynamiclib -F . -framework $(PYTHONFRAMEWORK)'
+ BLDSHARED="$LDSHARED"
+@@ -3601,7 +3801,7 @@
+ Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";;
+ Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";;
+ # -u libsys_s pulls in all symbols in libsys
+- Darwin/*|iOS/*)
++ Darwin/*|iOS/*|tvOS/*|visionOS/*|watchOS/*)
+ LINKFORSHARED="$extra_undefs -framework CoreFoundation"
+
+ # Issue #18075: the default maximum stack size (8MBytes) is too
+@@ -3625,7 +3825,7 @@
+ LINKFORSHARED="$LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/$(PYTHONFRAMEWORK)'
+ fi
+ LINKFORSHARED="$LINKFORSHARED"
+- elif test $ac_sys_system = "iOS"; then
++ elif test "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "visionOS" -o "$ac_sys_system" = "watchOS"; then
+ LINKFORSHARED="-Wl,-stack_size,$stack_size $LINKFORSHARED "'$(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK)'
+ fi
+ ;;
+@@ -4113,7 +4313,7 @@
+ dnl when do we need USING_APPLE_OS_LIBFFI?
+ ctypes_malloc_closure=yes
+ ],
+- [iOS], [
++ [iOS|tvOS|visionOS|watchOS], [
+ ctypes_malloc_closure=yes
+ ],
+ [sunos5], [AS_VAR_APPEND([LIBFFI_LIBS], [" -mimpure-text"])]
+@@ -5239,9 +5439,9 @@
+ # checks for library functions
+ AC_CHECK_FUNCS([ \
+ accept4 alarm bind_textdomain_codeset chmod chown clock closefrom close_range confstr \
+- copy_file_range ctermid dladdr dup dup3 execv explicit_bzero explicit_memset \
++ copy_file_range ctermid dladdr dup dup3 explicit_bzero explicit_memset \
+ faccessat fchmod fchmodat fchown fchownat fdopendir fdwalk fexecve \
+- fork fork1 fpathconf fstatat ftime ftruncate futimens futimes futimesat \
++ fpathconf fstatat ftime ftruncate futimens futimes futimesat \
+ gai_strerror getegid geteuid getgid getgrent getgrgid getgrgid_r \
+ getgrnam_r getgrouplist gethostname getitimer getloadavg getlogin getlogin_r \
+ getpeername getpgid getpid getppid getpriority _getpty \
+@@ -5249,8 +5449,7 @@
+ getspnam getuid getwd grantpt if_nameindex initgroups kill killpg lchown linkat \
+ lockf lstat lutimes madvise mbrtowc memrchr mkdirat mkfifo mkfifoat \
+ mknod mknodat mktime mmap mremap nice openat opendir pathconf pause pipe \
+- pipe2 plock poll posix_fadvise posix_fallocate posix_openpt posix_spawn posix_spawnp \
+- posix_spawn_file_actions_addclosefrom_np \
++ pipe2 plock poll posix_fadvise posix_fallocate posix_openpt \
+ pread preadv preadv2 process_vm_readv \
+ pthread_cond_timedwait_relative_np pthread_condattr_setclock pthread_init \
+ pthread_kill pthread_get_name_np pthread_getname_np pthread_set_name_np \
+@@ -5260,7 +5459,7 @@
+ sched_setparam sched_setscheduler sem_clockwait sem_getvalue sem_open \
+ sem_timedwait sem_unlink sendfile setegid seteuid setgid sethostname \
+ setitimer setlocale setpgid setpgrp setpriority setregid setresgid \
+- setresuid setreuid setsid setuid setvbuf shutdown sigaction sigaltstack \
++ setresuid setreuid setsid setuid setvbuf shutdown sigaction \
+ sigfillset siginterrupt sigpending sigrelse sigtimedwait sigwait \
+ sigwaitinfo snprintf splice strftime strlcpy strsignal symlinkat sync \
+ sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile \
+@@ -5275,12 +5474,20 @@
+ AC_CHECK_FUNCS([lchmod])
fi
- 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}"
+-# iOS defines some system methods that can be linked (so they are
++# iOS/tvOS/visionOS/watchOS define some system methods that can be linked (so they are
+ # found by configure), but either raise a compilation error (because the
+ # header definition prevents usage - autoconf doesn't use the headers), or
+ # raise an error if used at runtime. Force these symbols off.
+-if test "$ac_sys_system" != "iOS" ; then
+- AC_CHECK_FUNCS([getentropy getgroups system])
++if test "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "visionOS" -a "$ac_sys_system" != "watchOS" ; then
++ AC_CHECK_FUNCS([ getentropy getgroups system ])
++fi
++
++# tvOS/watchOS have some additional methods that can be found, but not used.
++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
++ AC_CHECK_FUNCS([ \
++ execv fork fork1 posix_spawn posix_spawnp posix_spawn_file_actions_addclosefrom_np \
++ sigaltstack \
++ ])
fi
- AC_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)
-@@ -6788,6 +6873,30 @@
- [AIX], [PY_STDLIB_MOD_SET_NA([_scproxy], [spwd])],
- [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [_crypt], [termios], [grp])],
- [Darwin], [PY_STDLIB_MOD_SET_NA([ossaudiodev], [spwd])],
-+ [iOS|tvOS|watchOS], [
-+ dnl subprocess and multiprocessing are not supported (no fork syscall).
-+ dnl curses and tkinter user interface are not available.
-+ dnl gdbm, and nis aren't available
-+ dnl Stub implementations are provided for pwd, grp etc APIs
-+ PY_STDLIB_MOD_SET_NA(
-+ [_curses],
-+ [_curses_panel],
-+ [_gdbm],
-+ [_multiprocessing],
-+ [_posixshmem],
-+ [_posixsubprocess],
-+ [_scproxy],
-+ [_tkinter],
-+ [_xxsubinterpreters],
-+ [grp],
-+ [nis],
-+ [ossaudiodev],
-+ [readline],
-+ [pwd],
-+ [spwd],
-+ [syslog],
-+ )
-+ ],
- [CYGWIN*], [PY_STDLIB_MOD_SET_NA([_scproxy], [nis])],
- [QNX*], [PY_STDLIB_MOD_SET_NA([_scproxy], [nis])],
- [FreeBSD*], [PY_STDLIB_MOD_SET_NA([_scproxy], [spwd])],
-diff --git a/setup.py b/setup.py
-index 15d0d4576a..a080c69d1f 100644
---- a/setup.py
-+++ b/setup.py
-@@ -82,6 +82,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)
- EMSCRIPTEN = HOST_PLATFORM == 'emscripten-wasm32'
-@@ -166,16 +169,20 @@
- for var_name in make_vars:
- var = sysconfig.get_config_var(var_name)
- if var is not None:
-- m = re.search(r'--sysroot=([^"]\S*|"[^"]+")', var)
-- if m is not None:
-- sysroot = m.group(1).strip('"')
-- for subdir in subdirs:
-- if os.path.isabs(subdir):
-- subdir = subdir[1:]
-- path = os.path.join(sysroot, subdir)
-- if os.path.isdir(path):
-- dirs.append(path)
-- break
-+ for pattern in [
-+ r'-isysroot\s*([^"]\S*|"[^"]+")',
-+ r'--sysroot=([^"]\S*|"[^"]+")',
-+ ]:
-+ m = re.search(pattern, var)
-+ if m is not None:
-+ sysroot = m.group(1).strip('"')
-+ for subdir in subdirs:
-+ if os.path.isabs(subdir):
-+ subdir = subdir[1:]
-+ path = os.path.join(sysroot, subdir)
-+ if os.path.isdir(path):
-+ dirs.append(path)
-+ break
- return dirs
-
-
-@@ -1396,6 +1403,11 @@
- extra_compile_args.append('-DMACOSX')
- include_dirs.append('_ctypes/darwin')
-
-+ elif IOS or TVOS or WATCHOS:
-+ sources.append('_ctypes/malloc_closure.c')
-+ extra_compile_args.append('-DUSING_MALLOC_CLOSURE_DOT_C')
-+ 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
-@@ -1418,7 +1430,8 @@
- self.addext(Extension('_ctypes_test', ['_ctypes/_ctypes_test.c']))
-
- 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:
-@@ -1447,6 +1460,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:
-@@ -1460,7 +1474,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
+
+ AC_CHECK_DECL([dirfd],
+@@ -5575,20 +5782,22 @@
+ [@%:@include ])
+
+ # check for openpty, login_tty, and forkpty
+-
+-AC_CHECK_FUNCS([openpty], [],
+- [AC_CHECK_LIB([util], [openpty],
+- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"],
+- [AC_CHECK_LIB([bsd], [openpty],
+- [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])])
+-AC_SEARCH_LIBS([login_tty], [util],
+- [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])]
+-)
+-AC_CHECK_FUNCS([forkpty], [],
+- [AC_CHECK_LIB([util], [forkpty],
+- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"],
+- [AC_CHECK_LIB([bsd], [forkpty],
+- [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])])
++# tvOS/watchOS have functions for tty, but can't use them
++if test "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "watchOS" ; then
++ AC_CHECK_FUNCS([openpty], [],
++ [AC_CHECK_LIB([util], [openpty],
++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lutil"],
++ [AC_CHECK_LIB([bsd], [openpty],
++ [AC_DEFINE([HAVE_OPENPTY]) LIBS="$LIBS -lbsd"])])])
++ AC_SEARCH_LIBS([login_tty], [util],
++ [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])]
++ )
++ AC_CHECK_FUNCS([forkpty], [],
++ [AC_CHECK_LIB([util], [forkpty],
++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lutil"],
++ [AC_CHECK_LIB([bsd], [forkpty],
++ [AC_DEFINE([HAVE_FORKPTY]) LIBS="$LIBS -lbsd"])])])
++fi
+
+ # check for long file support functions
+ AC_CHECK_FUNCS([fseek64 fseeko fstatvfs ftell64 ftello statvfs])
+@@ -5627,10 +5836,10 @@
+ ])
+ ])
+
+-# On Android and iOS, clock_settime can be linked (so it is found by
++# On Android, iOS, tvOS, visionOS, and watchOS, clock_settime can be linked (so it is found by
+ # configure), but when used in an unprivileged process, it crashes rather than
+ # returning an error. Force the symbol off.
+-if test "$ac_sys_system" != "Linux-android" && test "$ac_sys_system" != "iOS"
++if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "iOS" -a "$ac_sys_system" != "tvOS" -a "$ac_sys_system" != "visionOS" -a "$ac_sys_system" != "watchOS"
+ then
+ AC_CHECK_FUNCS([clock_settime], [], [
+ AC_CHECK_LIB([rt], [clock_settime], [
+@@ -5788,7 +5997,7 @@
+ [ac_cv_buggy_getaddrinfo=no],
+ [ac_cv_buggy_getaddrinfo=yes],
+ [
+-if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then
++if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS" || test "$ac_sys_system" = "tvOS" || test "$ac_sys_system" = "visionOS" || test "$ac_sys_system" = "watchOS"; then
+ ac_cv_buggy_getaddrinfo="no"
+ elif test "${enable_ipv6+set}" = set; then
+ ac_cv_buggy_getaddrinfo="no -- configured with --(en|dis)able-ipv6"
+@@ -6381,8 +6590,8 @@
+ LIBPYTHON="\$(BLDLIBRARY)"
+ fi
+
+-# On iOS the shared libraries must be linked with the Python framework
+-if test "$ac_sys_system" = "iOS"; then
++# On iOS/tvOS/watchOS the shared libraries must be linked with the Python framework
++if test "$ac_sys_system" = "iOS" -o $ac_sys_system = "tvOS" -o $ac_sys_system = "visionOS" -o $ac_sys_system = "watchOS"; then
+ MODULE_DEPS_SHARED="$MODULE_DEPS_SHARED \$(PYTHONFRAMEWORKDIR)/\$(PYTHONFRAMEWORK)"
+ fi
+
+@@ -6990,7 +7199,7 @@
+ dnl NOTE: Inform user how to proceed with files when cross compiling.
+ dnl Some cross-compile builds are predictable; they won't ever
+ dnl have /dev/ptmx or /dev/ptc, so we can set them explicitly.
+-if test "$ac_sys_system" = "Linux-android" || test "$ac_sys_system" = "iOS"; then
++if test "$ac_sys_system" = "Linux-android" -o "$ac_sys_system" = "iOS" -o "$ac_sys_system" = "tvOS" -o "$ac_sys_system" = "visionOS" -o "$ac_sys_system" = "watchOS" ; then
+ ac_cv_file__dev_ptmx=no
+ ac_cv_file__dev_ptc=no
+ else
+@@ -7290,7 +7499,7 @@
+ AS_CASE([$ac_sys_system],
+ [Emscripten], [with_ensurepip=no],
+ [WASI], [with_ensurepip=no],
+- [iOS], [with_ensurepip=no],
++ [iOS|tvOS|visionOS|watchOS], [with_ensurepip=no],
+ [with_ensurepip=upgrade]
+ )
+ ])
+@@ -7678,6 +7887,9 @@
+ NetBSD*) _PYTHREAD_NAME_MAXLEN=15;; # gh-131268
+ Darwin) _PYTHREAD_NAME_MAXLEN=63;;
+ iOS) _PYTHREAD_NAME_MAXLEN=63;;
++ tvOS) _PYTHREAD_NAME_MAXLEN=63;;
++ visionOS) _PYTHREAD_NAME_MAXLEN=63;;
++ watchOS) _PYTHREAD_NAME_MAXLEN=63;;
+ FreeBSD*) _PYTHREAD_NAME_MAXLEN=19;; # gh-131268
+ OpenBSD*) _PYTHREAD_NAME_MAXLEN=23;; # gh-131268
+ *) _PYTHREAD_NAME_MAXLEN=;;
+@@ -7702,7 +7914,7 @@
+ [VxWorks*], [PY_STDLIB_MOD_SET_NA([_scproxy], [termios], [grp])],
+ dnl The _scproxy module is available on macOS
+ [Darwin], [],
+- [iOS], [
++ [iOS|tvOS|visionOS|watchOS], [
+ dnl subprocess and multiprocessing are not supported (no fork syscall).
+ dnl curses and tkinter user interface are not available.
+ dnl gdbm and nis aren't available
diff --git a/patch/Python/_cross_target.py.tmpl b/patch/Python/_cross_target.py.tmpl
new file mode 100644
index 00000000..06303350
--- /dev/null
+++ b/patch/Python/_cross_target.py.tmpl
@@ -0,0 +1,77 @@
+# A site package that turns a macOS virtual environment
+# into an {{arch}} {{sdk}} cross-platform virtual environment
+import platform
+import subprocess
+import sys
+import sysconfig
+
+###########################################################################
+# sys module patches
+###########################################################################
+sys.cross_compiling = True
+sys.platform = "{{platform}}"
+sys.implementation._multiarch = "{{arch}}-{{sdk}}"
+sys.base_prefix = sysconfig._get_sysconfigdata()["prefix"]
+sys.base_exec_prefix = sysconfig._get_sysconfigdata()["prefix"]
+
+###########################################################################
+# subprocess module patches
+###########################################################################
+subprocess._can_fork_exec = True
+
+
+###########################################################################
+# platform module patches
+###########################################################################
+
+def cross_system():
+ return "{{os}}"
+
+
+def cross_uname():
+ return platform.uname_result(
+ system="{{os}}",
+ node="build",
+ release="{{version_min}}",
+ version="",
+ machine="{{arch}}",
+ )
+
+
+def cross_ios_ver(system="", release="", model="", is_simulator=False):
+ if system == "":
+ system = "{{os}}"
+ if release == "":
+ release = "{{version_min}}"
+ if model == "":
+ model = "{{sdk}}"
+
+ return platform.IOSVersionInfo(system, release, model, {{is_simulator}})
+
+
+platform.system = cross_system
+platform.uname = cross_uname
+platform.ios_ver = cross_ios_ver
+
+
+###########################################################################
+# sysconfig module patches
+###########################################################################
+
+def cross_get_platform():
+ return "{{platform}}-{{version_min}}-{{arch}}-{{sdk}}"
+
+
+def cross_get_sysconfigdata_name():
+ return "_sysconfigdata__{{platform}}_{{arch}}-{{sdk}}"
+
+
+sysconfig.get_platform = cross_get_platform
+sysconfig._get_sysconfigdata_name = cross_get_sysconfigdata_name
+
+# Ensure module-level values cached at time of import are updated.
+sysconfig._BASE_PREFIX = sys.base_prefix
+sysconfig._BASE_EXEC_PREFIX = sys.base_exec_prefix
+
+# Force sysconfig data to be loaded (and cached).
+sysconfig._init_config_vars()
diff --git a/patch/Python/_cross_venv.py b/patch/Python/_cross_venv.py
new file mode 100644
index 00000000..9caddf60
--- /dev/null
+++ b/patch/Python/_cross_venv.py
@@ -0,0 +1,105 @@
+import shutil
+import sys
+import sysconfig
+from pathlib import Path
+
+SITE_PACKAGE_PATH = Path(__file__).parent
+
+###########################################################################
+# importlib module patches
+###########################################################################
+
+
+def patch_env_create(env):
+ """
+ Patch the process of creating virtual environments to ensure that the cross
+ environment modification files are also copied as part of environment
+ creation.
+ """
+ old_pip_env_create = env._PipBackend.create
+
+ def pip_env_create(self, path, *args, **kwargs):
+ result = old_pip_env_create(self, path, *args, **kwargs)
+ # Copy any _cross_*.pth or _cross_*.py file, plus the cross-platform
+ # sysconfigdata module and sysconfig_vars JSON to the new environment.
+ data_name = sysconfig._get_sysconfigdata_name()
+ json_name = data_name.replace("_sysconfigdata", "_sysconfig_vars")
+ for filename in [
+ "_cross_venv.pth",
+ "_cross_venv.py",
+ f"_cross_{sys.implementation._multiarch.replace('-', '_')}.py",
+ f"{data_name}.py",
+ f"{json_name}.json",
+ ]:
+ src = SITE_PACKAGE_PATH / filename
+ target = Path(path) / src.relative_to(
+ SITE_PACKAGE_PATH.parent.parent.parent
+ )
+ if not target.exists():
+ shutil.copy(src, target)
+ return result
+
+ env._PipBackend.create = pip_env_create
+
+
+# Import hook that patches the creation of virtual environments by `build`
+#
+# The approach used here is the same as the one used by virtualenv to patch
+# distutils (but without support for the older load_module API).
+# https://docs.python.org/3/library/importlib.html#setting-up-an-importer
+_BUILD_PATCH = ("build.env",)
+
+
+class _Finder:
+ """A meta path finder that allows patching the imported build modules."""
+
+ fullname = None
+
+ # lock[0] is threading.Lock(), but initialized lazily to avoid importing
+ # threading very early at startup, because there are gevent-based
+ # applications that need to be first to import threading by themselves.
+ # See https://github.com/pypa/virtualenv/issues/1895 for details.
+ lock = [] # noqa: RUF012
+
+ def find_spec(self, fullname, path, target=None):
+ if fullname in _BUILD_PATCH and self.fullname is None:
+ # initialize lock[0] lazily
+ if len(self.lock) == 0:
+ import threading
+
+ lock = threading.Lock()
+ # there is possibility that two threads T1 and T2 are
+ # simultaneously running into find_spec, observing .lock as
+ # empty, and further going into hereby initialization. However
+ # due to the GIL, list.append() operation is atomic and this
+ # way only one of the threads will "win" to put the lock
+ # - that every thread will use - into .lock[0].
+ # https://docs.python.org/3/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe
+ self.lock.append(lock)
+
+ from functools import partial
+ from importlib.util import find_spec
+
+ with self.lock[0]:
+ self.fullname = fullname
+ try:
+ spec = find_spec(fullname, path)
+ if spec is not None:
+ # https://www.python.org/dev/peps/pep-0451/#how-loading-will-work
+ old = spec.loader.exec_module
+ func = self.exec_module
+ if old is not func:
+ spec.loader.exec_module = partial(func, old)
+ return spec
+ finally:
+ self.fullname = None
+ return None
+
+ @staticmethod
+ def exec_module(old, module):
+ old(module)
+ if module.__name__ in _BUILD_PATCH:
+ patch_env_create(module)
+
+
+sys.meta_path.insert(0, _Finder())
diff --git a/patch/Python/_sysconfigdata__ios_iphoneos.py b/patch/Python/_sysconfigdata__ios_iphoneos.py
deleted file mode 100644
index 780bf883..00000000
--- a/patch/Python/_sysconfigdata__ios_iphoneos.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# 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
deleted file mode 100644
index 1bede110..00000000
--- a/patch/Python/_sysconfigdata__ios_iphonesimulator.py
+++ /dev/null
@@ -1,11 +0,0 @@
-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
deleted file mode 100644
index eb7ac9cc..00000000
--- a/patch/Python/_sysconfigdata__tvos_appletvos.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# 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
deleted file mode 100644
index 29f8a67b..00000000
--- a/patch/Python/_sysconfigdata__tvos_appletvsimulator.py
+++ /dev/null
@@ -1,11 +0,0 @@
-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
deleted file mode 100644
index c1872dfc..00000000
--- a/patch/Python/_sysconfigdata__watchos_watchos.py
+++ /dev/null
@@ -1,2 +0,0 @@
-# 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
deleted file mode 100644
index c34bd97b..00000000
--- a/patch/Python/_sysconfigdata__watchos_watchsimulator.py
+++ /dev/null
@@ -1,11 +0,0 @@
-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/app-store-compliance.patch b/patch/Python/app-store-compliance.patch
new file mode 100644
index 00000000..f4b7decc
--- /dev/null
+++ b/patch/Python/app-store-compliance.patch
@@ -0,0 +1,29 @@
+diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
+index d6c83a75c1c..19ed4e01091 100644
+--- a/Lib/test/test_urlparse.py
++++ b/Lib/test/test_urlparse.py
+@@ -237,11 +237,6 @@ def test_roundtrips(self):
+ '','',''),
+ ('git+ssh', 'git@github.com','/user/project.git',
+ '', '')),
+- ('itms-services://?action=download-manifest&url=https://example.com/app',
+- ('itms-services', '', '', '',
+- 'action=download-manifest&url=https://example.com/app', ''),
+- ('itms-services', '', '',
+- 'action=download-manifest&url=https://example.com/app', '')),
+ ('+scheme:path/to/file',
+ ('', '', '+scheme:path/to/file', '', '', ''),
+ ('', '', '+scheme:path/to/file', '', '')),
+diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py
+index 8f724f907d4..148caf742c9 100644
+--- a/Lib/urllib/parse.py
++++ b/Lib/urllib/parse.py
+@@ -59,7 +59,7 @@
+ 'imap', 'wais', 'file', 'mms', 'https', 'shttp',
+ 'snews', 'prospero', 'rtsp', 'rtsps', 'rtspu', 'rsync',
+ 'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh',
+- 'ws', 'wss', 'itms-services']
++ 'ws', 'wss']
+
+ uses_params = ['', 'ftp', 'hdl', 'prospero', 'http', 'imap',
+ 'https', 'shttp', 'rtsp', 'rtsps', 'rtspu', 'sip',
diff --git a/patch/Python/make_cross_venv.py b/patch/Python/make_cross_venv.py
new file mode 100644
index 00000000..f8dad270
--- /dev/null
+++ b/patch/Python/make_cross_venv.py
@@ -0,0 +1,144 @@
+import json
+import pprint
+import shutil
+import sys
+from pathlib import Path
+from importlib import util as importlib_util
+
+
+def localized_vars(orig_vars, slice_path):
+ """Update (where possible) any references to build-time variables with the
+ best guess of the installed location.
+ """
+ # The host's sysconfigdata will include references to build-time variables.
+ # Update these to refer to the current known install location.
+ orig_prefix = orig_vars["prefix"]
+ localized_vars = {}
+ for key, value in orig_vars.items():
+ final = value
+ if isinstance(value, str):
+ # Replace any reference to the build installation prefix
+ final = final.replace(orig_prefix, str(slice_path))
+ # Replace any reference to the build-time Framework location
+ final = final.replace("-F .", f"-F {slice_path}")
+ localized_vars[key] = final
+
+ return localized_vars
+
+
+def localize_sysconfigdata(platform_config_path, venv_site_packages):
+ """Localize a sysconfigdata python module.
+
+ :param platform_config_path: The platform config that contains the
+ sysconfigdata module to localize.
+ :param venv_site_packages: The site packages folder where the localized
+ sysconfigdata module should be output.
+ """
+ # Find the "_sysconfigdata_*.py" file in the platform config
+ sysconfigdata_path = next(platform_config_path.glob("_sysconfigdata_*.py"))
+
+ # Import the sysconfigdata module
+ spec = importlib_util.spec_from_file_location(
+ sysconfigdata_path.stem,
+ sysconfigdata_path
+ )
+ if spec is None:
+ msg = f"Unable to load spec for {sysconfigdata_path}"
+ raise ValueError(msg)
+ if spec.loader is None:
+ msg = f"Spec for {sysconfigdata_path} does not define a loader"
+ raise ValueError(msg)
+ sysconfigdata = importlib_util.module_from_spec(spec)
+ spec.loader.exec_module(sysconfigdata)
+
+ # Write the updated sysconfigdata module into the cross-platform site.
+ slice_path = sysconfigdata_path.parent.parent.parent
+ with (venv_site_packages / sysconfigdata_path.name).open("w") as f:
+ f.write(f"# Generated from {sysconfigdata_path}\n")
+ f.write("build_time_vars = ")
+ pprint.pprint(
+ localized_vars(sysconfigdata.build_time_vars, slice_path),
+ stream=f,
+ compact=True
+ )
+
+
+def localize_sysconfig_vars(platform_config_path, venv_site_packages):
+ """Localize a sysconfig_vars.json file.
+
+ :param platform_config_path: The platform config that contains the
+ sysconfigdata module to localize.
+ :param venv_site_packages: The site-packages folder where the localized
+ sysconfig_vars.json file should be output.
+ """
+ # Find the "_sysconfig_vars_*.json" file in the platform config
+ sysconfig_vars_path = next(platform_config_path.glob("_sysconfig_vars_*.json"))
+
+ with sysconfig_vars_path.open("rb") as f:
+ build_time_vars = json.load(f)
+
+ slice_path = sysconfig_vars_path.parent.parent.parent
+ with (venv_site_packages / sysconfig_vars_path.name).open("w") as f:
+ json.dump(localized_vars(build_time_vars, slice_path), f, indent=2)
+
+
+def make_cross_venv(venv_path: Path, platform_config_path: Path):
+ """Convert a virtual environment into a cross-platform environment.
+
+ :param venv_path: The path to the root of the venv.
+ :param platform_config_path: The path containing the platform config.
+ """
+ if not venv_path.exists():
+ raise ValueError(f"Virtual environment {venv_path} does not exist.")
+ if not (venv_path / "bin/python3").exists():
+ raise ValueError(f"{venv_path} does not appear to be a virtual environment.")
+
+ print(
+ f"Converting {venv_path} into a {platform_config_path.name} environment... ",
+ end="",
+ )
+
+ LIB_PATH = f"lib/python{sys.version_info[0]}.{sys.version_info[1]}"
+
+ # Update path references in the sysconfigdata to reflect local conditions.
+ venv_site_packages = venv_path / LIB_PATH / "site-packages"
+ localize_sysconfigdata(platform_config_path, venv_site_packages)
+ localize_sysconfig_vars(platform_config_path, venv_site_packages)
+
+ # Copy in the site-package environment modifications.
+ cross_multiarch = f"_cross_{platform_config_path.name.replace('-', '_')}"
+ shutil.copy(
+ platform_config_path / f"{cross_multiarch}.py",
+ venv_site_packages / f"{cross_multiarch}.py",
+ )
+ shutil.copy(
+ platform_config_path / "_cross_venv.py",
+ venv_site_packages / "_cross_venv.py",
+ )
+ # Write the .pth file that will enable the cross-env modifications
+ (venv_site_packages / "_cross_venv.pth").write_text(
+ f"import {cross_multiarch}; import _cross_venv\n"
+ )
+
+ print("done.")
+
+
+if __name__ == "__main__":
+ try:
+ platform_config_path = Path(sys.argv[2]).resolve()
+ except IndexError:
+ platform_config_path = Path(__file__).parent
+
+ try:
+ venv_path = Path(sys.argv[1]).resolve()
+ make_cross_venv(venv_path, platform_config_path)
+ except IndexError:
+ print("""
+Convert a virtual environment in to a cross-platform environment.
+
+Usage:
+ make_cross_venv ()
+
+If an explicit platform config isn't provided, it is assumed the directory
+containing the make_cross_venv script *is* a platform config.
+""")
diff --git a/patch/Python/module.modulemap.prefix b/patch/Python/module.modulemap.prefix
new file mode 100644
index 00000000..e3b3aafb
--- /dev/null
+++ b/patch/Python/module.modulemap.prefix
@@ -0,0 +1,20 @@
+module Python {
+ umbrella header "Python.h"
+ export *
+ link "Python"
+
+ exclude header "datetime.h"
+ exclude header "dynamic_annotations.h"
+ exclude header "errcode.h"
+ exclude header "frameobject.h"
+ exclude header "marshal.h"
+ exclude header "opcode_ids.h"
+ exclude header "opcode.h"
+ exclude header "osdefs.h"
+ exclude header "py_curses.h"
+ exclude header "pyconfig-arm32_64.h"
+ exclude header "pyconfig-arm64.h"
+ exclude header "pyconfig-x86_64.h"
+ exclude header "pydtrace.h"
+ exclude header "pyexpat.h"
+ exclude header "structmember.h"
diff --git a/patch/Python/pyconfig-iOS.h b/patch/Python/pyconfig-iOS.h
deleted file mode 100644
index 4acff2c6..00000000
--- a/patch/Python/pyconfig-iOS.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifdef __arm64__
-#include "pyconfig-arm64.h"
-#endif
-
-#ifdef __x86_64__
-#include "pyconfig-x86_64.h"
-#endif
diff --git a/patch/Python/pyconfig-tvOS.h b/patch/Python/pyconfig-tvOS.h
deleted file mode 100644
index d4afe05b..00000000
--- a/patch/Python/pyconfig-tvOS.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifdef __arm64__
-#include "pyconfig-arm64.h"
-#endif
-
-#ifdef __x86_64__
-#include "pyconfig-x86_64.h"
-#endif
\ No newline at end of file
diff --git a/patch/Python/pyconfig-watchOS.h b/patch/Python/pyconfig-watchOS.h
deleted file mode 100644
index ae4563f1..00000000
--- a/patch/Python/pyconfig-watchOS.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifdef __arm__
-#include "pyconfig-armv7k.h"
-#endif
-
-#ifdef __arm64__
-# ifdef __LP64__
-#include "pyconfig-arm64.h"
-# else
-#include "pyconfig-arm64_32.h"
-# endif
-#endif
-
-#ifdef __x86_64__
-#include "pyconfig-x86_64.h"
-#endif
\ No newline at end of file
diff --git a/patch/Python/release.common.exclude b/patch/Python/release.common.exclude
deleted file mode 100644
index 8f11eac5..00000000
--- a/patch/Python/release.common.exclude
+++ /dev/null
@@ -1,30 +0,0 @@
-# This is a list of support package path patterns that we exclude
-# from all Python-Apple-support tarballs.
-# It is used by `tar -X` during the Makefile build.
-# Remove standard library test suites.
-python-stdlib/ctypes/test
-python-stdlib/distutils/tests
-python-stdlib/lib2to3/tests
-python-stdlib/sqlite3/test
-python-stdlib/test
-# Remove config-* directory, which is used for compiling C extension modules.
-python-stdlib/config-*
-# Remove ensurepip. If user code needs pip, it can add it to
-python-stdlib/ensurepip
-# Remove libraries supporting IDLE. We don't need to ship an IDE
-python-stdlib/idlelib
-# Remove Tcl/Tk GUI code. We don't build against Tcl/Tk at the moment, so this
-# will not work.
-python-stdlib/tkinter
-python-stdlib/turtle.py
-python-stdlib/turtledemo
-# Remove 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-stdlib/site-packages
-# Remove pyc files. These take up space, but since most stdlib modules are
-# never imported by user code, they mostly have no value.
-*/__pycache__
\ No newline at end of file
diff --git a/patch/Python/release.iOS.exclude b/patch/Python/release.iOS.exclude
index 471b1907..f1d0f75e 100644
--- a/patch/Python/release.iOS.exclude
+++ b/patch/Python/release.iOS.exclude
@@ -1,6 +1,6 @@
# This is a list of support package path patterns that we exclude
-# from iOS Python-Apple-support tarballs.
+# from all Python-Apple-support tarballs.
# It is used by `tar -X` during the Makefile build.
-#
-# Remove command-line curses toolkit.
-python-stdlib/curses
+# Remove pyc files. These take up space, but since most stdlib modules are
+# never imported by user code, they mostly have no value.
+*/__pycache__
diff --git a/patch/Python/release.macOS.exclude b/patch/Python/release.macOS.exclude
index 20009bb2..3bc247c1 100644
--- a/patch/Python/release.macOS.exclude
+++ b/patch/Python/release.macOS.exclude
@@ -1,4 +1,28 @@
-# This is a list of support package path patterns that we exclude
-# from macOS Python-Apple-support tarballs.
+# This is a list of Framework path patterns that we exclude
+# when building macOS Python-Apple-support tarballs from the official Framework
# It is used by `tar -X` during the Makefile build.
#
+._Headers
+._Python
+._Resources
+Resources/._Python.app
+Resources/Python.app
+Versions/._Current
+Versions/*/.__CodeSignature
+Versions/*/._bin
+Versions/*/._etc
+Versions/*/._Frameworks
+Versions/*/._Headers
+Versions/*/._include
+Versions/*/._lib
+Versions/*/._Resources
+Versions/*/._share
+Versions/*/bin
+Versions/*/etc
+Versions/*/Frameworks
+Versions/*/lib/python*/idlelib
+Versions/*/lib/python*/lib-dynload/_tkinter.*
+Versions/*/lib/python*/tkinter
+Versions/*/lib/python*/turtle.py
+Versions/*/lib/python*/turtledemo
+Versions/*/share
diff --git a/patch/Python/release.tvOS.exclude b/patch/Python/release.tvOS.exclude
index 0aeb4300..f1d0f75e 100644
--- a/patch/Python/release.tvOS.exclude
+++ b/patch/Python/release.tvOS.exclude
@@ -1,6 +1,6 @@
# This is a list of support package path patterns that we exclude
-# from tvOS Python-Apple-support tarballs.
+# from all Python-Apple-support tarballs.
# It is used by `tar -X` during the Makefile build.
-#
-# Remove command-line curses toolkit.
-Python/Resources/lib/python*/curses
+# Remove pyc files. These take up space, but since most stdlib modules are
+# never imported by user code, they mostly have no value.
+*/__pycache__
diff --git a/patch/Python/test.exclude b/patch/Python/release.visionOS.exclude
similarity index 55%
rename from patch/Python/test.exclude
rename to patch/Python/release.visionOS.exclude
index add994a7..f1d0f75e 100644
--- a/patch/Python/test.exclude
+++ b/patch/Python/release.visionOS.exclude
@@ -1,7 +1,6 @@
-# This is a list of Python standard library path patterns
-# we exclude from the embedded device Python-Apple-support test tarballs.
+# 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 pyc files. These take up space, but since most stdlib modules are
# never imported by user code, they mostly have no value.
-*/__pycache__
\ No newline at end of file
+*/__pycache__
diff --git a/patch/Python/release.watchOS.exclude b/patch/Python/release.watchOS.exclude
index e41e7a41..f1d0f75e 100644
--- a/patch/Python/release.watchOS.exclude
+++ b/patch/Python/release.watchOS.exclude
@@ -1,6 +1,6 @@
# This is a list of support package path patterns that we exclude
-# from watchOS Python-Apple-support tarballs.
+# from all Python-Apple-support tarballs.
# It is used by `tar -X` during the Makefile build.
-#
-# Remove command-line curses toolkit.
-Python/Resources/lib/python*/curses
+# Remove pyc files. These take up space, but since most stdlib modules are
+# never imported by user code, they mostly have no value.
+*/__pycache__
diff --git a/patch/Python/sitecustomize.py b/patch/Python/sitecustomize.py
deleted file mode 100644
index d7d86e36..00000000
--- a/patch/Python/sitecustomize.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# 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/sitecustomize.py.tmpl b/patch/Python/sitecustomize.py.tmpl
new file mode 100644
index 00000000..0330575a
--- /dev/null
+++ b/patch/Python/sitecustomize.py.tmpl
@@ -0,0 +1,22 @@
+# 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 python, the interpreter will behave as if it were running on
+# {{arch}} {{sdk}}.
+import sys
+import os
+
+# Apply the cross-platform patch
+import _cross_{{arch}}_{{sdk}}
+import _cross_venv
+
+
+# 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/libffi-3.4.2.patch b/patch/libffi-3.4.2.patch
deleted file mode 100644
index 7e3d9a26..00000000
--- a/patch/libffi-3.4.2.patch
+++ /dev/null
@@ -1,320 +0,0 @@
-diff --git a/generate-darwin-source-and-headers.py b/generate-darwin-source-and-headers.py
-index 9921b0d..5b60ccc 100755
---- a/generate-darwin-source-and-headers.py
-+++ b/generate-darwin-source-and-headers.py
-@@ -11,9 +11,8 @@ class Platform(object):
- pass
-
-
--class simulator_platform(Platform):
-+class i386_platform(Platform):
- arch = 'i386'
-- triple = 'i386-apple-darwin11'
-
- prefix = "#ifdef __i386__\n\n"
- suffix = "\n\n#endif"
-@@ -21,9 +20,8 @@ class simulator_platform(Platform):
- src_files = ['sysv.S', 'ffi.c', 'internal.h']
-
-
--class simulator64_platform(Platform):
-+class x86_64_platform(Platform):
- arch = 'x86_64'
-- triple = 'x86_64-apple-darwin13'
-
- prefix = "#ifdef __x86_64__\n\n"
- suffix = "\n\n#endif"
-@@ -31,101 +29,146 @@ class simulator64_platform(Platform):
- src_files = ['unix64.S', 'ffi64.c', 'ffiw64.c', 'win64.S', 'internal64.h', 'asmnames.h']
-
-
--class device_platform(Platform):
-- arch = 'armv7'
-- triple = 'arm-apple-darwin11'
-+class arm64_platform(Platform):
-+ arch = 'arm64'
-
-- prefix = "#ifdef __arm__\n\n"
-+ prefix = "#ifdef __arm64__\n\n"
- suffix = "\n\n#endif"
-- src_dir = 'arm'
-+ src_dir = 'aarch64'
- src_files = ['sysv.S', 'ffi.c', 'internal.h']
-
-
--class device64_platform(Platform):
-- arch = 'arm64'
-- triple = 'aarch64-apple-darwin13'
-+class armv7_platform(Platform):
-+ arch = 'armv7'
-
-- prefix = "#ifdef __arm64__\n\n"
-+ prefix = "#ifdef __arm__\n\n"
- suffix = "\n\n#endif"
-- src_dir = 'aarch64'
-+ src_dir = 'arm'
- src_files = ['sysv.S', 'ffi.c', 'internal.h']
-
-
--class ios_simulator_platform(simulator_platform):
-+class ios_simulator_i386_platform(i386_platform):
-+ triple = 'i386-apple-darwin11'
-+ target = 'i386-apple-ios-simulator'
-+ directory = 'darwin_ios'
-+ sdk = 'iphonesimulator'
-+ version_min = '-miphoneos-version-min=7.0'
-+
-+
-+class ios_simulator_x86_64_platform(x86_64_platform):
-+ triple = 'x86_64-apple-darwin13'
-+ target = 'x86_64-apple-ios-simulator'
- directory = 'darwin_ios'
- sdk = 'iphonesimulator'
- version_min = '-miphoneos-version-min=7.0'
-
-
--class ios_simulator64_platform(simulator64_platform):
-+class ios_simulator_arm64_platform(arm64_platform):
-+ triple = 'aarch64-apple-darwin20'
-+ target = 'arm64-apple-ios-simulator'
- directory = 'darwin_ios'
- sdk = 'iphonesimulator'
- version_min = '-miphoneos-version-min=7.0'
-
-
--class ios_device_platform(device_platform):
-+class ios_device_armv7_platform(armv7_platform):
-+ triple = 'arm-apple-darwin11'
-+ target = 'armv7-apple-ios'
- directory = 'darwin_ios'
- sdk = 'iphoneos'
- version_min = '-miphoneos-version-min=7.0'
-
-
--class ios_device64_platform(device64_platform):
-+class ios_device_arm64_platform(arm64_platform):
-+ triple = 'aarch64-apple-darwin13'
-+ target = 'arm64-apple-ios'
- directory = 'darwin_ios'
- sdk = 'iphoneos'
- version_min = '-miphoneos-version-min=7.0'
-
-
--class desktop32_platform(Platform):
-+class desktop_x86_64_platform(x86_64_platform):
-+ triple = 'x86_64-apple-darwin10'
-+ target = 'x86_64-apple-macos'
- directory = 'darwin_osx'
- sdk = 'macosx'
-- arch = 'i386'
-- triple = 'i386-apple-darwin10'
- version_min = '-mmacosx-version-min=10.6'
-- src_dir = 'x86'
-- src_files = ['sysv.S', 'ffi.c', 'internal.h']
--
-- prefix = "#ifdef __i386__\n\n"
-- suffix = "\n\n#endif"
-
-
--class desktop64_platform(Platform):
-+class desktop_arm64_platform(arm64_platform):
-+ triple = 'aarch64-apple-darwin20'
-+ target = 'arm64-apple-macos'
- directory = 'darwin_osx'
- sdk = 'macosx'
-- arch = 'x86_64'
-- triple = 'x86_64-apple-darwin10'
-- version_min = '-mmacosx-version-min=10.6'
-+ version_min = '-mmacosx-version-min=11.0'
-
-- prefix = "#ifdef __x86_64__\n\n"
-- suffix = "\n\n#endif"
-- src_dir = 'x86'
-- src_files = ['unix64.S', 'ffi64.c', 'ffiw64.c', 'win64.S', 'internal64.h', 'asmnames.h']
-+
-+class tvos_simulator_x86_64_platform(x86_64_platform):
-+ triple = 'x86_64-apple-darwin13'
-+ target = 'x86_64-apple-tvos-simulator'
-+ directory = 'darwin_tvos'
-+ sdk = 'appletvsimulator'
-+ version_min = '-mtvos-version-min=9.0'
-
-
--class tvos_simulator64_platform(simulator64_platform):
-+class tvos_simulator_arm64_platform(arm64_platform):
-+ triple = 'aarch64-apple-darwin20'
-+ target = 'arm64-apple-tvos-simulator'
- directory = 'darwin_tvos'
- sdk = 'appletvsimulator'
- version_min = '-mtvos-version-min=9.0'
-
-
--class tvos_device64_platform(device64_platform):
-+class tvos_device_arm64_platform(arm64_platform):
-+ triple = 'aarch64-apple-darwin13'
-+ target = 'arm64-apple-tvos'
- directory = 'darwin_tvos'
- sdk = 'appletvos'
- version_min = '-mtvos-version-min=9.0'
-
-
--class watchos_simulator_platform(simulator_platform):
-+class watchos_simulator_i386_platform(i386_platform):
-+ triple = 'i386-apple-darwin11'
-+ target = 'i386-apple-watchos-simulator'
-+ directory = 'darwin_watchos'
-+ sdk = 'watchsimulator'
-+ version_min = '-mwatchos-version-min=4.0'
-+
-+
-+class watchos_simulator_x86_64_platform(x86_64_platform):
-+ triple = 'x86_64-apple-darwin13'
-+ target = 'x86_64-apple-watchos-simulator'
-+ directory = 'darwin_watchos'
-+ sdk = 'watchsimulator'
-+ version_min = '-mwatchos-version-min=4.0'
-+
-+
-+class watchos_simulator_arm64_platform(arm64_platform):
-+ triple = 'aarch64-apple-darwin20'
-+ target = 'arm64-apple-watchos-simulator'
- directory = 'darwin_watchos'
- sdk = 'watchsimulator'
- version_min = '-mwatchos-version-min=4.0'
-
-
--class watchos_device_platform(device_platform):
-+class watchos_device_armv7k_platform(armv7_platform):
-+ triple = 'arm-apple-darwin11'
-+ target = 'armv7k-apple-watchos'
- directory = 'darwin_watchos'
- sdk = 'watchos'
- arch = 'armv7k'
- version_min = '-mwatchos-version-min=4.0'
-
-
-+class watchos_device_arm64_32_platform(arm64_platform):
-+ triple = 'aarch64-apple-darwin13'
-+ target = 'arm64_32-apple-watchos'
-+ directory = 'darwin_watchos'
-+ sdk = 'watchos'
-+ arch = 'arm64_32'
-+ version_min = '-mwatchos-version-min=4.0'
-+
-+
- def mkdir_p(path):
- try:
- os.makedirs(path)
-@@ -175,7 +218,7 @@ def copy_src_platform_files(platform):
-
- def build_target(platform, platform_headers):
- def xcrun_cmd(cmd):
-- return 'xcrun -sdk %s %s -arch %s' % (platform.sdk, cmd, platform.arch)
-+ return 'xcrun -sdk %s %s -target %s' % (platform.sdk, cmd, platform.target)
-
- tag='%s-%s' % (platform.sdk, platform.arch)
- build_dir = 'build_%s' % tag
-@@ -212,34 +255,46 @@ def generate_source_and_headers(
- copy_files('include', 'darwin_common/include', pattern='*.h')
-
- if generate_ios:
-- copy_src_platform_files(ios_simulator_platform)
-- copy_src_platform_files(ios_simulator64_platform)
-- copy_src_platform_files(ios_device_platform)
-- copy_src_platform_files(ios_device64_platform)
-+ # copy_src_platform_files(ios_simulator_i386_platform)
-+ copy_src_platform_files(ios_simulator_x86_64_platform)
-+ copy_src_platform_files(ios_simulator_arm64_platform)
-+ # copy_src_platform_files(ios_device_armv7_platform)
-+ copy_src_platform_files(ios_device_arm64_platform)
- if generate_osx:
-- copy_src_platform_files(desktop64_platform)
-+ copy_src_platform_files(desktop_x86_64_platform)
-+ copy_src_platform_files(desktop_arm64_platform)
- if generate_tvos:
-- copy_src_platform_files(tvos_simulator64_platform)
-- copy_src_platform_files(tvos_device64_platform)
-+ copy_src_platform_files(tvos_simulator_x86_64_platform)
-+ copy_src_platform_files(tvos_simulator_arm64_platform)
-+ copy_src_platform_files(tvos_device_arm64_platform)
- if generate_watchos:
-- copy_src_platform_files(watchos_simulator_platform)
-- copy_src_platform_files(watchos_device_platform)
-+ # copy_src_platform_files(watchos_simulator_i386_platform)
-+ copy_src_platform_files(watchos_simulator_x86_64_platform)
-+ # copy_src_platform_files(watchos_simulator_arm64_platform)
-+ copy_src_platform_files(watchos_device_armv7k_platform)
-+ copy_src_platform_files(watchos_device_arm64_32_platform)
-
- platform_headers = collections.defaultdict(set)
-
- if generate_ios:
-- build_target(ios_simulator_platform, platform_headers)
-- build_target(ios_simulator64_platform, platform_headers)
-- build_target(ios_device_platform, platform_headers)
-- build_target(ios_device64_platform, platform_headers)
-+ # build_target(ios_simulator_i386_platform, platform_headers)
-+ build_target(ios_simulator_x86_64_platform, platform_headers)
-+ build_target(ios_simulator_arm64_platform, platform_headers)
-+ # build_target(ios_device_armv7_platform, platform_headers)
-+ build_target(ios_device_arm64_platform, platform_headers)
- if generate_osx:
-- build_target(desktop64_platform, platform_headers)
-+ build_target(desktop_x86_64_platform, platform_headers)
-+ build_target(desktop_arm64_platform, platform_headers)
- if generate_tvos:
-- build_target(tvos_simulator64_platform, platform_headers)
-- build_target(tvos_device64_platform, platform_headers)
-+ build_target(tvos_simulator_x86_64_platform, platform_headers)
-+ build_target(tvos_simulator_arm64_platform, platform_headers)
-+ build_target(tvos_device_arm64_platform, platform_headers)
- if generate_watchos:
-- build_target(watchos_simulator_platform, platform_headers)
-- build_target(watchos_device_platform, platform_headers)
-+ # build_target(watchos_simulator_i386_platform, platform_headers)
-+ build_target(watchos_simulator_x86_64_platform, platform_headers)
-+ build_target(watchos_simulator_arm64_platform, platform_headers)
-+ # build_target(watchos_device_armv7k_platform, platform_headers)
-+ build_target(watchos_device_arm64_32_platform, platform_headers)
-
- mkdir_p('darwin_common/include')
- for header_name, tag_tuples in platform_headers.items():
-diff --git a/src/closures.c b/src/closures.c
-index f7bead6..db7ec94 100644
---- a/src/closures.c
-+++ b/src/closures.c
-@@ -134,7 +134,7 @@ ffi_tramp_is_present (__attribute__((unused)) void *ptr)
- # define HAVE_MNTENT 1
- # endif
- # if defined(_WIN32) || defined(__OS2__)
--/* Windows systems may have Data Execution Protection (DEP) enabled,
-+/* Windows systems may have Data Execution Protection (DEP) enabled,
- which requires the use of VirtualMalloc/VirtualFree to alloc/free
- executable memory. */
- # define FFI_MMAP_EXEC_WRIT 1
-@@ -230,12 +230,24 @@ ffi_trampoline_table_alloc (void)
- kt = vm_remap (mach_task_self (), &trampoline_page, PAGE_MAX_SIZE, 0x0,
- VM_FLAGS_OVERWRITE, mach_task_self (), trampoline_page_template,
- FALSE, &cur_prot, &max_prot, VM_INHERIT_SHARE);
-- if (kt != KERN_SUCCESS || !(cur_prot & VM_PROT_EXECUTE))
-+ if (kt != KERN_SUCCESS)
- {
- vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2);
- return NULL;
- }
-
-+ if (!(cur_prot & VM_PROT_EXECUTE))
-+ {
-+ /* If VM_PROT_EXECUTE isn't set on the remapped trampoline page, set it */
-+ kt = vm_protect (mach_task_self (), trampoline_page, PAGE_MAX_SIZE,
-+ FALSE, cur_prot | VM_PROT_EXECUTE);
-+ if (kt != KERN_SUCCESS)
-+ {
-+ vm_deallocate (mach_task_self (), config_page, PAGE_MAX_SIZE * 2);
-+ return NULL;
-+ }
-+ }
-+
- /* We have valid trampoline and config pages */
- table = calloc (1, sizeof (ffi_trampoline_table));
- table->free_count = FFI_TRAMPOLINE_COUNT;
diff --git a/patch/make-relocatable.sh b/patch/make-relocatable.sh
new file mode 100755
index 00000000..f268cd70
--- /dev/null
+++ b/patch/make-relocatable.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+FRAMEWORK_BASEDIR=$1
+echo "Making $1 relocatable"
+PYTHON_VER=${FRAMEWORK_BASEDIR##*/}
+echo "Python version ${PYTHON_VER}"
+
+pushd ${FRAMEWORK_BASEDIR}
+
+echo "Rewrite ID of Python library"
+install_name_tool -id @rpath/Python.framework/Versions/${PYTHON_VER}/Python Python > /dev/null
+for dylib in `ls lib/*.*.dylib`; do
+ # lib
+ if [ "${dylib}" != "lib/libpython${PYTHON_VER}.dylib" ] ; then
+ echo Rewrite ID of ${dylib}
+ install_name_tool -id @rpath/Python.framework/Versions/${PYTHON_VER}/${dylib} ${FRAMEWORK_BASEDIR}/${dylib}
+ fi
+done
+for module in `find . -name "*.dylib" -type f -o -name "*.so" -type f`; do
+ if [ "$(otool -L ${module} | grep -c /Library/Frameworks/Python.framework)" != "0" ]; then
+ for dylib in `ls lib/*.*.dylib`; do
+ echo Rewrite references to ${dylib} in ${module}
+ install_name_tool -change /Library/Frameworks/Python.framework/Versions/${PYTHON_VER}/${dylib} @rpath/Python.framework/Versions/${PYTHON_VER}/${dylib} ${module}
+ done
+ fi
+done
+popd
diff --git a/patch/xz-5.2.6.patch b/patch/xz-5.2.6.patch
deleted file mode 100644
index 6876e0d5..00000000
--- a/patch/xz-5.2.6.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-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/test_cross_env.py b/tests/test_cross_env.py
new file mode 100644
index 00000000..34e8c5eb
--- /dev/null
+++ b/tests/test_cross_env.py
@@ -0,0 +1,93 @@
+import os
+import platform
+import sys
+import sysconfig
+from pathlib import Path
+
+import pytest
+
+# To run these tests, the following three environment variables must be set,
+# reflecting the cross-platform environment that is in effect.'
+PYTHON_CROSS_PLATFORM = os.getenv("PYTHON_CROSS_PLATFORM", "unknown")
+PYTHON_CROSS_SLICE = os.getenv("PYTHON_CROSS_SLICE", "unknown")
+PYTHON_CROSS_MULTIARCH = os.getenv("PYTHON_CROSS_MULTIARCH", "unknown")
+
+# Determine some file system anchor points for the tests
+# Assumes that the tests are run in a virtual environment named
+# `cross-venv`,
+VENV_PREFIX = Path(__file__).parent.parent / "cross-venv"
+default_support_base = f"support/{sys.version_info.major}.{sys.version_info.minor}/{PYTHON_CROSS_PLATFORM}"
+SUPPORT_PREFIX = (
+ Path(__file__).parent.parent
+ / os.getenv("PYTHON_SUPPORT_BASE", default_support_base)
+ / "Python.xcframework"
+ / PYTHON_CROSS_SLICE
+)
+
+
+###########################################################################
+# sys
+###########################################################################
+
+def test_sys_platform():
+ assert sys.platform == PYTHON_CROSS_PLATFORM.lower()
+
+
+def test_sys_cross_compiling():
+ assert sys.cross_compiling
+
+
+def test_sys_multiarch():
+ assert sys.implementation._multiarch == PYTHON_CROSS_MULTIARCH
+
+
+def test_sys_base_prefix():
+ assert Path(sys.base_prefix) == SUPPORT_PREFIX
+
+
+def test_sys_base_exec_prefix():
+ assert Path(sys.base_exec_prefix) == SUPPORT_PREFIX
+
+
+###########################################################################
+# platform
+###########################################################################
+
+def test_platform_system():
+ assert platform.system() == PYTHON_CROSS_PLATFORM
+
+
+###########################################################################
+# sysconfig
+###########################################################################
+
+def test_sysconfig_get_platform():
+ parts = sysconfig.get_platform().split("-", 2)
+ assert parts[0] == PYTHON_CROSS_PLATFORM.lower()
+ assert parts[2] == PYTHON_CROSS_MULTIARCH
+
+
+def test_sysconfig_get_sysconfigdata_name():
+ parts = sysconfig._get_sysconfigdata_name().split("_", 4)
+ assert parts[3] == PYTHON_CROSS_PLATFORM.lower()
+ assert parts[4] == PYTHON_CROSS_MULTIARCH
+
+
+@pytest.mark.parametrize(
+ "name, prefix",
+ [
+ # Paths that should be relative to the support folder
+ ("stdlib", SUPPORT_PREFIX),
+ ("include", SUPPORT_PREFIX),
+ ("platinclude", SUPPORT_PREFIX),
+ ("stdlib", SUPPORT_PREFIX),
+ # paths that should be relative to the venv
+ ("platstdlib", VENV_PREFIX),
+ ("purelib", VENV_PREFIX),
+ ("platlib", VENV_PREFIX),
+ ("scripts", VENV_PREFIX),
+ ("data", VENV_PREFIX),
+ ]
+)
+def test_sysconfig_get_paths(name, prefix):
+ assert sysconfig.get_paths()[name].startswith(str(prefix))