Skip to content

Commit fc5bf32

Browse files
committed
Build CPython 3.15 (3.15.2) for every platform
Adds a "3.15" row to manifest.json (CPython 3.15.2, PBS 20261026, Pyodide 315.0.0a2 / pyemscripten-2026.5-wasm32, all three Android ABIs), which pulls 3.15.2 into the CI build matrix. The row is marked `prerelease: true`: CPython 3.15 is final, but Pyodide only has an alpha and pypi.flet.dev has no cp315 mobile wheels yet, so downstream tools offer it only when it is named explicitly. Flip it to false once those catch up. Build fixes needed for 3.15: * Android: CPython 3.15 moved its tooling from `Android/android.py` to the `Platforms/Android` package (`python3 Platforms/Android <cmd>`). The build now picks the tool and its `android-env.sh` (for the NDK version probe) by minor, and fails loudly if the NDK version cannot be read instead of silently skipping the NDK relocation. * iOS: `Apple/` likewise moved to `Platforms/Apple/`; `build_ios.py` runs `python Platforms/Apple build iOS` for 3.15+. Slice names, the cross-build layout and the configure lines build_ios.py rewrites are unchanged, so `reshape()` needs no change. * _decimal: 3.15 removed configure's implicit fallback to the bundled libmpdec. Without a system libmpdec it now skips _decimal entirely (python.org's own 3.15.2 Android tarball ships no _decimal). Android 3.15 passes `--with-system-libmpdec=no` to `configure-host`; the macOS build passes it for every minor, which matches what 3.12-3.14 already produced (bundled, statically linked) and keeps a runner's single-arch Homebrew mpdecimal out of the universal2 framework. iOS already gets mpdecimal from CPython's Apple tool. * Windows: 3.15 bundles Tcl/Tk 9, whose DLLs are `tcl90.dll`, `tcl9tk90.dll` and `libtommath.dll`; the 8.6 `tcl86t`/`tk86t` excludes no longer matched them, so they would ship next to the already-pruned _tkinter. Also adds 3.15.2 to the build-python-version dispatch choices, runs the Android build-details.json checks on 3.15 shards, and refreshes the comments and READMEs that named the old tool paths. README documents what `prerelease` means for consumers.
1 parent c3a79e1 commit fc5bf32

11 files changed

Lines changed: 76 additions & 20 deletions

File tree

‎.github/workflows/build-python-version.yml‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ on:
1717
- 3.12.16
1818
- 3.13.18
1919
- 3.14.10
20+
- 3.15.2
2021

2122
env:
2223
PYTHON_VERSION: ${{ inputs.python_version || github.event.inputs.python_version }}
@@ -54,8 +55,9 @@ jobs:
5455
run: |
5556
mkdir -p dist
5657
57-
# iOS: 3.14+ uses CPython's in-tree Apple tooling, 3.13 builds from source per
58-
# iOS/README.rst, 3.12 uses beeware. Emits normalized ./install + ./support.
58+
# iOS: every minor runs CPython's in-tree Apple tooling (3.14 `Apple/`, 3.15+
59+
# `Platforms/Apple/`; 3.12/3.13 back-port it via ios_patches/). Emits normalized
60+
# ./install + ./support.
5961
python build_ios.py "$PYTHON_VERSION"
6062
6163
# build_ios.py mutates the CPython-created Python.xcframework after assembly
@@ -127,7 +129,7 @@ jobs:
127129
tar -czf dist/python-android-mobile-forge-$PYTHON_VERSION.tar.gz install support
128130
# ABIs come from the manifest (`pythons.<short>.android_abis`) so a
129131
# future minor only needs a one-line edit there — not a workflow
130-
# bump. 3.12 ships armeabi-v7a; 3.13+ are 64-bit only (PEP 738).
132+
# bump.
131133
short="$PYTHON_VERSION_SHORT"
132134
abis=$(jq -r --arg s "$short" '.pythons[$s].android_abis[]' "$GITHUB_WORKSPACE/manifest.json")
133135
if [ -z "$abis" ]; then

‎README.md‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,17 @@ Schema:
3838
`android_abis` lists the ABIs `package-for-dart.sh` builds for this minor —
3939
64-bit (`arm64-v8a`, `x86_64`) plus 32-bit `armeabi-v7a`. [PEP 738](https://peps.python.org/pep-0738/)
4040
makes 64-bit Android the *tested* Tier-3 configuration, but CPython's official
41-
`Android/android.py` still builds 32-bit ARM (it's in its supported `HOSTS`), so
42-
all three minors carry `armeabi-v7a`. Drop an ABI from a minor's list to stop
43-
building it.
41+
Android tooling (`Android/android.py`, `Platforms/Android` from 3.15) still builds
42+
32-bit ARM (it's in its supported `HOSTS`), so every minor carries `armeabi-v7a`.
43+
Drop an ABI from a minor's list to stop building it.
44+
45+
`prerelease: true` marks a minor that downstream tools offer only on request:
46+
serious_python and flet never pick it as the default or for an open-ended
47+
`requires-python` that a stable minor also satisfies. It must be named with
48+
`--python-version X.Y` or `requires-python = "==X.Y.*"`. Use it while a minor's
49+
ecosystem is still catching up (e.g. 3.15: CPython is final, but Pyodide is still
50+
`315.0.0a2` and the mobile wheel index has no cp315 builds yet). This repo builds and
51+
publishes pre-release minors like any other.
4452

4553
The committed file omits `release`; the publish step injects it.
4654

‎android/README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ Scripts and CI jobs for building Python for Android.
44

55
* Can be run on both Linux and macOS.
66
* Python 3.12 uses the legacy patched cross-build flow.
7-
* Python 3.13+ uses CPython's official `Android/android.py` build flow.
7+
* Python 3.13+ uses CPython's official Android build flow (`Android/android.py`;
8+
3.15 moved it to `Platforms/Android`, run as `python3 Platforms/Android`).
89
* Creates Python installation with a structure suitable for https://github.com/flet-dev/mobile-forge.
910

1011
## Usage

‎android/build.sh‎

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,23 +177,46 @@ else
177177
fi
178178
fi
179179

180+
# CPython 3.15 moved its Android tooling from Android/android.py to the
181+
# Platforms/Android package (run as `python3 Platforms/Android <cmd>`);
182+
# the subcommands and the cross-build/<HOST>/prefix output are unchanged.
183+
if [ $version_int -ge 315 ]; then
184+
cpython_android_dir=Platforms/Android
185+
cpython_android_tool=(python3 Platforms/Android)
186+
else
187+
cpython_android_dir=Android
188+
cpython_android_tool=(Android/android.py)
189+
fi
190+
180191
# Reuse already-installed NDK by exposing it at the location expected by
181-
# CPython's Android/android-env.sh.
192+
# CPython's android-env.sh.
182193
if [ -z "${NDK_HOME:-}" ] && [ -d "$HOME/ndk/r27d" ]; then
183194
export NDK_HOME="$HOME/ndk/r27d"
184195
fi
185-
cpython_ndk_version=$(sed -n 's/^ndk_version=//p' Android/android-env.sh | head -n1)
196+
cpython_ndk_version=$(sed -n 's/^ndk_version=//p' "$cpython_android_dir/android-env.sh" | head -n1)
197+
if [ -z "$cpython_ndk_version" ]; then
198+
echo "Could not read ndk_version from $cpython_android_dir/android-env.sh"
199+
exit 1
200+
fi
186201
if [ -n "${NDK_HOME:-}" ] && [ -d "$NDK_HOME" ] && [ -n "${cpython_ndk_version:-}" ]; then
187202
mkdir -p "$ANDROID_HOME/ndk"
188203
if [ ! -e "$ANDROID_HOME/ndk/$cpython_ndk_version" ]; then
189204
ln -s "$NDK_HOME" "$ANDROID_HOME/ndk/$cpython_ndk_version"
190205
fi
191206
fi
192207

193-
Android/android.py configure-build
194-
Android/android.py make-build
195-
Android/android.py configure-host "$HOST"
196-
Android/android.py make-host "$HOST"
208+
"${cpython_android_tool[@]}" configure-build
209+
"${cpython_android_tool[@]}" make-build
210+
# configure defaults to a system libmpdec, which the Android sysroot doesn't
211+
# have. 3.13/3.14 fell back to CPython's bundled copy; 3.15 dropped that
212+
# fallback and builds no _decimal at all (python.org's own 3.15 Android
213+
# release lacks it), so ask for the bundled copy explicitly.
214+
configure_host_args=()
215+
if [ $version_int -ge 315 ]; then
216+
configure_host_args+=(-- --with-system-libmpdec=no)
217+
fi
218+
"${cpython_android_tool[@]}" configure-host "$HOST" ${configure_host_args[@]+"${configure_host_args[@]}"}
219+
"${cpython_android_tool[@]}" make-host "$HOST"
197220
cp -a "cross-build/$HOST/prefix/"* "$PREFIX"
198221

199222
# CPython's official Android tooling builds OpenSSL/bzip2/libffi/xz/sqlite

‎android/tests/test_built_build_details_json.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
1717
3.13 and 3.12 don't emit a `build-details.json` (it's a 3.14 addition),
1818
so the relevant `@post_build` class is gated on `PYTHON_VERSION_SHORT`
19-
via `@requires_python("3.14")` and degrades to a skip on the older
19+
via `@requires_python("3.14", "3.15")` and degrades to a skip on the older
2020
matrix shards.
2121
"""
2222

@@ -77,11 +77,11 @@ def _resolve(data: dict, path: tuple[str, ...]):
7777

7878

7979
@post_build
80-
@requires_python("3.14")
80+
@requires_python("3.14", "3.15")
8181
class BuiltBuildDetailsJsonShape(unittest.TestCase):
8282
"""The shipped `build-details.json` must carry re-anchored paths.
8383
84-
Gated on 3.14: CPython didn't ship this file pre-3.14, so on 3.12/3.13
84+
Gated on 3.14+: CPython didn't ship this file pre-3.14, so on 3.12/3.13
8585
shards there's nothing to inspect and the class skips wholesale.
8686
"""
8787

‎darwin/README.rst‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ iOS — ``build_ios.py <full-version>``
2121
Every version is built with the **same** mechanism — CPython's in-tree ``Apple`` build
2222
tool (``python Apple build iOS``) — then ``cross-build/`` is reshaped into the layout above:
2323

24-
* **3.14+** — the ``Apple/`` tooling is native; build straight from the source tarball.
24+
* **3.14+** — the ``Apple/`` tooling is native; build straight from the source tarball
25+
(3.15 moved it to ``Platforms/Apple/``, run as ``python Platforms/Apple build iOS``).
2526
* **3.13 / 3.12** — the tooling (and, for 3.12, the PEP 730 iOS runtime) isn't upstream
2627
yet, so a vendored back-port patch (``ios_patches/<short>/Python.patch``, see that
2728
directory's README) is applied first to add it. No dependency on beeware's

‎darwin/build_ios.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
``Apple`` build package (``python Apple build iOS``):
66
77
* **3.14+** — the ``Apple/`` tooling is native; build straight from the source tarball.
8+
3.15 moved it to ``Platforms/Apple/`` (``python Platforms/Apple build iOS``); same
9+
subcommands and the same ``cross-build/`` output.
810
* **3.13 / 3.12** — the tooling (and, for 3.12, the PEP 730 iOS runtime) isn't upstream yet,
911
so we first apply a vendored back-port patch (``ios_patches/<short>/Python.patch``) that
1012
adds it, then run the identical ``python Apple build iOS``. No dependency on beeware's
@@ -188,7 +190,8 @@ def build(
188190
# own C deps, and emits cross-build/iOS/Python.xcframework. `build` does not run the
189191
# (device/simulator) testbed.
190192
host_python = shutil.which("python3") or sys.executable
191-
run([host_python, "Apple", "build", "iOS"], cwd=src, env=env)
193+
apple_tool = "Platforms/Apple" if minor >= 15 else "Apple"
194+
run([host_python, apple_tool, "build", "iOS"], cwd=src, env=env)
192195

193196
reshape(version, short, src, root)
194197

‎darwin/build_macos.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
``.pkg``) for *all* versions (3.12 / 3.13 / 3.14). Building from source means we get the
66
exact micro version even when python.org never published a macOS installer for it.
77
8-
macOS provides bz2/lzma/sqlite/libffi via the SDK and CPython bundles libmpdec, so the
8+
macOS provides bz2/lzma/sqlite/libffi via the SDK and CPython bundles libmpdec (selected
9+
explicitly with ``--with-system-libmpdec=no``, since 3.15 dropped the implicit fallback), so the
910
only third-party dependency we must supply is **OpenSSL** — and since no prebuilt
1011
universal2 macOS OpenSSL exists (cpython-apple-source-deps only ships iOS-family slices,
1112
Homebrew is single-arch), we build it universal2 from source here.
@@ -352,6 +353,11 @@ def build_python_framework(
352353
# the _lzma extension builds (the SDK provides no lzma.h).
353354
f"LIBLZMA_CFLAGS=-I{xz_prefix}/include",
354355
f"LIBLZMA_LIBS=-L{xz_prefix}/lib -llzma",
356+
# Build _decimal against CPython's bundled libmpdec. configure defaults to a
357+
# system libmpdec (3.13+); 3.13/3.14 fell back to the bundled copy when none was
358+
# found, 3.15 skips _decimal instead (and a runner's single-arch Homebrew
359+
# mpdecimal must never be linked into the universal2 framework either).
360+
"--with-system-libmpdec=no",
355361
]
356362
if zstd_prefix is not None:
357363
# _zstd (CPython 3.14+) — SDK provides no zstd.h, so feed the from-source build.

‎darwin/ios_patches/README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ the **same** standard mechanism for every version instead of bespoke build code.
99
| `3.13/Python.patch` | `Apple/` build tooling + `iOS/Resources/bin` shims | iOS *runtime* (PEP 730) is already upstream in 3.13 |
1010
| `3.12/Python.patch` | `Apple/` build tooling **+ the PEP 730 runtime** (`_ios_support.py`, `getpath.c`, `pylifecycle.c`, …) | 3.12 has no iOS support at all upstream |
1111

12-
3.14+ needs **no** patch — the `Apple/` tooling is native there.
12+
3.14+ needs **no** patch — the `Apple/` tooling is native there (3.15 moved it to
13+
`Platforms/Apple/`; `build_ios.py` picks the path by minor).
1314

1415
## Provenance
1516

‎manifest.json‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
"pyodide_platform_tag": "pyemscripten-2026.0-wasm32",
2626
"android_abis": ["arm64-v8a", "x86_64", "armeabi-v7a"],
2727
"prerelease": false
28+
},
29+
"3.15": {
30+
"full_version": "3.15.2",
31+
"standalone_release_date": "20261026",
32+
"pyodide_version": "315.0.0a2",
33+
"pyodide_platform_tag": "pyemscripten-2026.5-wasm32",
34+
"android_abis": ["arm64-v8a", "x86_64", "armeabi-v7a"],
35+
"prerelease": true
2836
}
2937
}
3038
}

0 commit comments

Comments
 (0)