Skip to content

Commit bf4a907

Browse files
authored
Merge recent changes from main. (#311)
Includes adding a cross-env ci check, and converting the README to markdown.
1 parent 0c0096f commit bf4a907

File tree

8 files changed

+344
-174
lines changed

8 files changed

+344
-174
lines changed

.github/workflows/ci.yaml

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ jobs:
8989
strategy:
9090
fail-fast: false
9191
matrix:
92-
target: ['macOS', 'iOS', 'tvOS', 'watchOS']
92+
platform: ['macOS', 'iOS', 'tvOS', 'watchOS']
9393

9494
steps:
9595
- uses: actions/[email protected]
@@ -104,29 +104,29 @@ jobs:
104104
# It's an edge case, but when a new alpha is released, we need to use it ASAP.
105105
check-latest: true
106106

107-
- name: Build ${{ matrix.target }}
107+
- name: Build ${{ matrix.platform }}
108108
run: |
109-
# Do the build for the requested target.
110-
make ${{ matrix.target }} BUILD_NUMBER=${{ needs.config.outputs.BUILD_NUMBER }}
109+
# Do the build for the requested platform.
110+
make ${{ matrix.platform }} BUILD_NUMBER=${{ needs.config.outputs.BUILD_NUMBER }}
111111
112112
- name: Upload build artefacts
113113
uses: actions/[email protected]
114114
with:
115-
name: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
116-
path: dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
115+
name: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
116+
path: dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
117117

118118
briefcase-testbed:
119-
name: Briefcase testbed (${{ matrix.target }})
119+
name: Briefcase testbed (${{ matrix.platform }})
120120
runs-on: macOS-latest
121121
needs: [ config, build ]
122122
strategy:
123123
fail-fast: false
124124
matrix:
125-
target: ["macOS", "iOS"]
125+
platform: ["macOS", "iOS"]
126126
include:
127127
- briefcase-run-args:
128128

129-
- target: iOS
129+
- platform: iOS
130130
briefcase-run-args: ' -d "iPhone SE (3rd generation)"'
131131

132132
steps:
@@ -135,7 +135,7 @@ jobs:
135135
- name: Get build artifact
136136
uses: actions/[email protected]
137137
with:
138-
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
138+
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
139139
path: dist
140140
merge-multiple: true
141141

@@ -162,24 +162,24 @@ jobs:
162162
- name: Run support testbed check
163163
timeout-minutes: 10
164164
working-directory: Python-support-testbed
165-
run: briefcase run ${{ matrix.target }} Xcode --test ${{ matrix.briefcase-run-args }} -C support_package=\'../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz\'
165+
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\'
166166

167167
cpython-testbed:
168-
name: CPython testbed (${{ matrix.target }})
168+
name: CPython testbed (${{ matrix.platform }})
169169
runs-on: macOS-latest
170170
needs: [ config, build ]
171171
strategy:
172172
fail-fast: false
173173
matrix:
174-
target: ["iOS"]
174+
platform: ["iOS"]
175175

176176
steps:
177177
- uses: actions/[email protected]
178178

179179
- name: Get build artifact
180180
uses: actions/[email protected]
181181
with:
182-
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
182+
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
183183
path: dist
184184
merge-multiple: true
185185

@@ -195,13 +195,13 @@ jobs:
195195

196196
- name: Unpack support package
197197
run: |
198-
mkdir support
199-
cd support
200-
tar zxvf ../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.target }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
198+
mkdir -p support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
199+
cd support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
200+
tar zxvf ../../../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
201201
202202
- name: Run CPython testbed
203203
timeout-minutes: 10
204-
working-directory: support
204+
working-directory: support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
205205
run: |
206206
# Run a representative subset of CPython core tests:
207207
# - test_builtin as a test of core language tools
@@ -210,3 +210,66 @@ jobs:
210210
# - test_bz2 as a simple test of third party libraries
211211
# - test_ctypes as a test of FFI
212212
python -m testbed run -- test --single-process --rerun -W test_builtin test_grammar test_os test_bz2 test_ctypes
213+
214+
crossenv-test:
215+
name: Cross-platform env test (${{ matrix.multiarch }})
216+
runs-on: macOS-latest
217+
needs: [ config, build ]
218+
strategy:
219+
fail-fast: false
220+
matrix:
221+
include:
222+
- platform: iOS
223+
slice: ios-arm64_x86_64-simulator
224+
multiarch: arm64-iphonesimulator
225+
- platform: iOS
226+
slice: ios-arm64_x86_64-simulator
227+
multiarch: x86_64-iphonesimulator
228+
- platform: iOS
229+
slice: ios-arm64
230+
multiarch: arm64-iphoneos
231+
232+
steps:
233+
- uses: actions/[email protected]
234+
235+
- name: Get build artifact
236+
uses: actions/[email protected]
237+
with:
238+
pattern: Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
239+
path: dist
240+
merge-multiple: true
241+
242+
- name: Set up Python
243+
uses: actions/[email protected]
244+
with:
245+
# Appending -dev ensures that we can always build the dev release.
246+
# It's a no-op for versions that have been published.
247+
python-version: ${{ needs.config.outputs.PYTHON_VER }}-dev
248+
# Ensure that we *always* use the latest build, not a cached version.
249+
# It's an edge case, but when a new alpha is released, we need to use it ASAP.
250+
check-latest: true
251+
252+
- name: Unpack support package
253+
run: |
254+
mkdir -p support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
255+
cd support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}
256+
tar zxvf ../../../dist/Python-${{ needs.config.outputs.PYTHON_VER }}-${{ matrix.platform }}-support.${{ needs.config.outputs.BUILD_NUMBER }}.tar.gz
257+
258+
- name: Run cross-platform environment test
259+
env:
260+
PYTHON_CROSS_PLATFORM: ${{ matrix.platform }}
261+
PYTHON_CROSS_SLICE: ${{ matrix.slice }}
262+
PYTHON_CROSS_MULTIARCH: ${{ matrix.multiarch }}
263+
run: |
264+
# Create and activate a native virtual environment
265+
python${{ needs.config.outputs.PYTHON_VER }} -m venv cross-venv
266+
source cross-venv/bin/activate
267+
268+
# Install pytest
269+
python -m pip install pytest
270+
271+
# Convert venv into cross-venv
272+
python support/${{ needs.config.outputs.PYTHON_VER }}/${{ matrix.platform }}/Python.xcframework/${{ matrix.slice }}/platform-config/${{ matrix.multiarch }}/make_cross_venv.py cross-venv
273+
274+
# Run the test suite
275+
python -m pytest tests

.github/workflows/release.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
merge-multiple: true
4848

4949
- name: Create Release
50-
uses: ncipollo/release-action@v1.16.0
50+
uses: ncipollo/release-action@v1.18.0
5151
with:
5252
name: ${{ needs.ci.outputs.PYTHON_VER }}-${{ needs.config.outputs.BUILD_NUMBER }}
5353
tag: ${{ needs.ci.outputs.PYTHON_VER }}-${{ needs.config.outputs.BUILD_NUMBER }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ tests/testbed/iOS
1515
*.log
1616
*.gz
1717
*.DS_Store
18+
cross-venv/
19+
temp

Makefile

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
# - iOS - build everything for iOS
66
# - tvOS - build everything for tvOS
77
# - watchOS - build everything for watchOS
8-
# - visionOS - build everything for visionOS
98

109
# Current directory
1110
PROJECT_DIR=$(shell pwd)
@@ -34,7 +33,7 @@ OPENSSL_VERSION=3.0.16-2
3433
XZ_VERSION=5.6.4-2
3534

3635
# Supported OS
37-
OS_LIST=macOS iOS tvOS watchOS visionOS
36+
OS_LIST=macOS iOS tvOS watchOS
3837

3938
CURL_FLAGS=--disable --fail --location --create-dirs --progress-bar
4039

@@ -89,7 +88,7 @@ update-patch:
8988
# comparing between the current state of the 3.X branch against the v3.X.Y
9089
# tag associated with the release being built. This allows you to
9190
# maintain a branch that contains custom patches against the default Python.
92-
# The patch archived in this respository is based on github.com/freakboy3742/cpython
91+
# The patch archived in this repository is based on github.com/freakboy3742/cpython
9392
# Requires patchutils (installable via `brew install patchutils`); this
9493
# also means we need to re-introduce homebrew to the path for the filterdiff
9594
# call
@@ -333,7 +332,7 @@ $$(PYTHON_LIB-$(target)): $$(PYTHON_SRCDIR-$(target))/python.exe
333332

334333

335334
$$(PYTHON_PLATFORM_SITECUSTOMIZE-$(target)):
336-
@echo ">>> Create cross-plaform config for $(target)"
335+
@echo ">>> Create cross-platform config for $(target)"
337336
mkdir -p $$(PYTHON_PLATFORM_CONFIG-$(target))
338337
# Create the cross-platform site definition
339338
echo "import _cross_$$(ARCH-$(target))_$$(SDK-$(target)); import _cross_venv;" \

README.md

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Python Apple Support
2+
3+
This is a meta-package for building a version of Python that can be
4+
embedded into a macOS, iOS, tvOS, or watchOS project.
5+
6+
**This branch builds a packaged version of Python 3.13**. Other Python
7+
versions are available by cloning other branches of the main repository:
8+
9+
- [Python 3.9](https://github.com/beeware/Python-Apple-support/tree/3.9)
10+
- [Python
11+
3.10](https://github.com/beeware/Python-Apple-support/tree/3.10)
12+
- [Python
13+
3.11](https://github.com/beeware/Python-Apple-support/tree/3.11)
14+
- [Python
15+
3.12](https://github.com/beeware/Python-Apple-support/tree/3.12)
16+
- [Python
17+
3.14](https://github.com/beeware/Python-Apple-support/tree/3.14)
18+
19+
It works by downloading, patching, and building a fat binary of Python
20+
and selected pre-requisites, and packaging them as frameworks that can
21+
be incorporated into an Xcode project. The binary modules in the Python
22+
standard library are distributed as binaries that can be dynamically
23+
loaded at runtime.
24+
25+
The macOS package is a re-bundling of the official macOS binary,
26+
modified so that it is relocatable, with the IDLE, Tkinter and turtle
27+
packages removed, and the App Store compliance patch applied.
28+
29+
The iOS, tvOS, and watchOS packages compiled by this project
30+
use the official [PEP 730](https://peps.python.org/pep-0730/) code that
31+
is part of Python 3.13 to provide iOS support; the relevant patches have
32+
been backported to 3.9-3.12. Additional patches have been applied to add
33+
tvOS, and watchOS support.
34+
35+
The binaries support x86_64 and arm64 for macOS; arm64 for iOS and
36+
appleTV devices; and arm64_32 for watchOS devices.
37+
It also supports device simulators on both x86_64 and M1
38+
hardware. This should enable the code to run on:
39+
40+
- macOS 11 (Big Sur) or later, on:
41+
- MacBook (including MacBooks using Apple Silicon)
42+
- iMac (including iMacs using Apple Silicon)
43+
- Mac Mini (including Apple Silicon Mac minis)
44+
- Mac Studio (all models)
45+
- Mac Pro (all models)
46+
47+
- iOS 13.0 or later, on:
48+
- iPhone (6s or later)
49+
- iPad (5th gen or later)
50+
- iPad Air (all models)
51+
- iPad Mini (2 or later)
52+
- iPad Pro (all models)
53+
- iPod Touch (7th gen or later)
54+
55+
- tvOS 12.0 or later, on:
56+
- Apple TV (4th gen or later)
57+
58+
- watchOS 4.0 or later, on:
59+
- Apple Watch (4th gen or later)
60+
61+
## Quickstart
62+
63+
The easist way to use these packages is by creating a project with
64+
[Briefcase](https://github.com/beeware/briefcase). Briefcase will
65+
download pre-compiled versions of these support packages, and add them
66+
to an Xcode project (or pre-build stub application, in the case of
67+
macOS).
68+
69+
Pre-built versions of the frameworks can be downloaded from the [Github
70+
releases page](https://github.com/beeware/Python-Apple-support/releases)
71+
and added to your project.
72+
73+
Alternatively, to build the frameworks on your own, download/clone this
74+
repository, and then in the root directory, and run:
75+
76+
- `make` (or `make all`) to build everything.
77+
- `make macOS` to build everything for macOS.
78+
- `make iOS` to build everything for iOS.
79+
- `make tvOS` to build everything for tvOS.
80+
- `make watchOS` to build everything for watchOS.
81+
82+
This should:
83+
84+
1. Download the original source packages
85+
2. Patch them as required for compatibility with the selected OS
86+
3. Build the packages as Xcode-compatible XCFrameworks.
87+
88+
The resulting support packages will be packaged as `.tar.gz` files in
89+
the `dist` folder.
90+
91+
Each support package contains:
92+
93+
- `VERSIONS`, a text file describing the specific versions of code used
94+
to build the support package;
95+
- `Python.xcframework`, a multi-architecture build of the Python runtime
96+
library.
97+
98+
On iOS/tvOS/watchOS, the `Python.xcframework` contains a slice
99+
for each supported ABI (device and simulator). The folder containing the
100+
slice can also be used as a `PYTHONHOME`, as it contains a `bin`,
101+
`include` and `lib` directory.
102+
103+
The `bin` folder does not contain Python executables (as they can't be
104+
invoked). However, it *does* contain shell aliases for the compilers
105+
that are needed to build packages. This is required because Xcode uses
106+
the `xcrun` alias to dynamically generate the name of binaries, but a
107+
lot of C tooling expects that `CC` will not contain spaces.
108+
109+
Each slice of an iOS/tvOS/watchOS XCframework also contains a
110+
`platform-config` folder with a subfolder for each supported
111+
architecture in that slice. These subfolders can be used to make a macOS
112+
Python environment behave as if it were on an iOS/tvOS/watchOS
113+
device. This works in one of two ways:
114+
115+
1. **A sitecustomize.py script**. If the `platform-config` subfolder is
116+
on your `PYTHONPATH` when a Python interpreter is started, a site
117+
customization will be applied that patches methods in `sys`,
118+
`sysconfig` and `platform` that are used to identify the system.
119+
2. **A make_cross_venv.py script**. If you call `make_cross_venv.py`,
120+
providing the location of a virtual environment, the script will add
121+
some files to the `site-packages` folder of that environment that
122+
will automatically apply the same set of patches as the
123+
`sitecustomize.py` script whenever the environment is activated,
124+
without any need to modify `PYTHONPATH`. If you use `build` to
125+
create an isolated PEP 517 environment to build a wheel, these
126+
patches will also be applied to the isolated build environment that
127+
is created.
128+
129+
iOS distributions also contain a copy of the iOS
130+
`testbed` project - an Xcode project that can be used to run
131+
test suites of Python code. See the [CPython documentation on testing
132+
packages](https://docs.python.org/3/using/ios.html#testing-a-python-package)
133+
for details on how to use this testbed.
134+
135+
For a detailed instructions on using the support package in your own
136+
project, see the [usage guide](./USAGE.md)
137+
138+
## Building binary wheels
139+
140+
This project packages the Python standard library, but does not address
141+
building binary wheels. Binary wheels for macOS can be obtained from
142+
PyPI. [Mobile Forge](https://github.com/beeware/mobile-forge) is a
143+
project that provides the tooling to build build binary wheels for iOS
144+
(and potentially for tvOS, and watchOS, although that hasn't
145+
been tested).
146+
147+
## Historical support
148+
149+
The following versions were supported in the past, but are no longer
150+
maintained:
151+
152+
- [Python 2.7](https://github.com/beeware/Python-Apple-support/tree/2.7)
153+
(EOL January 2020)
154+
- [Python 3.4](https://github.com/beeware/Python-Apple-support/tree/3.4)
155+
(EOL March 2019)
156+
- [Python 3.5](https://github.com/beeware/Python-Apple-support/tree/3.5)
157+
(EOL February 2021)
158+
- [Python 3.6](https://github.com/beeware/Python-Apple-support/tree/3.6)
159+
(EOL December 2021)
160+
- [Python 3.7](https://github.com/beeware/Python-Apple-support/tree/3.7)
161+
(EOL September 2022)
162+
- [Python 3.8](https://github.com/beeware/Python-Apple-support/tree/3.8)
163+
(EOL October 2024)

0 commit comments

Comments
 (0)