Skip to content

Commit 4be7726

Browse files
committed
Support Python 3.13 Android builds and packaging
Bump CI to Python 3.13.12 and add logic to handle CPython 3.13+ changes: only arm64-v8a and x86_64 ABIs are supported by the official Android/android.py flow, so build scripts and the GitHub workflow now compute a version_int and conditionally skip armeabi-v7a for 3.13+. build.sh was updated to use CPython's Android tooling for >=3.13, set ANDROID_HOME/ANDROID_API_LEVEL/NDK linkage as needed, and enforce supported ABIs. The legacy 3.13_pending patch was removed. Packaging scripts for Android, iOS and macOS now require a host pythonX.Y to compile stdlib bytecode with an isolated interpreter (-I -m compileall -b) to avoid importing from target dirs. README updated to note the new CPython Android build flow and ABI support.
1 parent 9c1f9d6 commit 4be7726

File tree

8 files changed

+85
-59
lines changed

8 files changed

+85
-59
lines changed

.github/workflows/build-python.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ on:
77
workflow_dispatch:
88

99
env:
10-
PYTHON_VERSION: 3.12.12
11-
PYTHON_VERSION_SHORT: 3.12
10+
PYTHON_VERSION: 3.13.12
11+
PYTHON_VERSION_SHORT: 3.13
1212
PYTHON_DIST_RELEASE: 20260203
1313

1414
jobs:
@@ -71,8 +71,12 @@ jobs:
7171
mkdir -p dist
7272
tar -czf dist/python-android-mobile-forge-$PYTHON_VERSION_SHORT.tar.gz install support
7373
bash ./package-for-dart.sh install "$PYTHON_VERSION" arm64-v8a
74-
bash ./package-for-dart.sh install "$PYTHON_VERSION" armeabi-v7a
7574
bash ./package-for-dart.sh install "$PYTHON_VERSION" x86_64
75+
read version_major version_minor < <(echo "$PYTHON_VERSION" | sed -E 's/^([0-9]+)\.([0-9]+).*/\1 \2/')
76+
version_int=$((version_major * 100 + version_minor))
77+
if [ $version_int -lt 313 ]; then
78+
bash ./package-for-dart.sh install "$PYTHON_VERSION" armeabi-v7a
79+
fi
7680
- uses: actions/upload-artifact@v4
7781
with:
7882
name: python-android

android/README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,27 @@
33
Scripts and CI jobs for building Python 3 for Android.
44

55
* Can be run on both Linux and macOS.
6-
* Build Python 3.12 - specific or the last minor version.
6+
* Build Python 3.x - specific or the last minor version.
77
* Installs NDK r29 or use pre-installed one with path configured by `NDK_HOME` variable.
88
* Creates Python installation with a structure suitable for https://github.com/flet-dev/mobile-forge
9+
* Python 3.13+ uses CPython's official `Android/android.py` build flow.
910

1011
## Usage
1112

12-
To build the latest minor version of Python 3.12 for selected Android API:
13+
To build Python for a specific ABI:
1314

1415
```
15-
./build.sh 3.12 arm64-v8a
16+
./build.sh 3.13.12 arm64-v8a
1617
```
1718

1819
To build all ABIs:
1920

2021
```
21-
./build-all.sh 3.12
22+
./build-all.sh 3.13.12
2223
```
2324

25+
For Python 3.13+, official CPython Android tooling currently supports `arm64-v8a` and `x86_64`.
26+
2427
## Credits
2528

2629
Build process depends on:

android/build-all.sh

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@
22
set -euo pipefail
33

44
python_version=${1:?}
5-
abis="arm64-v8a armeabi-v7a x86_64 x86"
5+
read version_major version_minor < <(
6+
echo "$python_version" | sed -E 's/^([0-9]+)\.([0-9]+).*/\1 \2/'
7+
)
8+
version_int=$((version_major * 100 + version_minor))
9+
10+
if [ $version_int -ge 313 ]; then
11+
abis="arm64-v8a x86_64"
12+
else
13+
abis="arm64-v8a armeabi-v7a x86_64 x86"
14+
fi
615

716
for abi in $abis; do
817
bash ./build.sh $python_version $abi

android/build.sh

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ mkdir -p $downloads
2020

2121
cd $script_dir
2222
. abi-to-host.sh
23-
. android-env.sh
23+
: ${api_level:=24}
24+
25+
if [ $version_int -le 312 ]; then
26+
. android-env.sh
27+
fi
2428

2529
# Download and unpack Python source code.
2630
version_dir=$script_dir/build/$version
@@ -49,10 +53,6 @@ fi
4953
if [ $version_int -eq 312 ]; then
5054
patches+=" bldlibrary grp"
5155
fi
52-
if [ $version_int -eq 313 ]; then
53-
# TODO: remove this once it's merged upstream.
54-
patches+=" 3.13_pending"
55-
fi
5656
for name in $patches; do
5757
patch_file="$script_dir/patches/$name.patch"
5858
echo "$patch_file"
@@ -145,9 +145,43 @@ if [ $version_int -le 312 ]; then
145145

146146
# Python 3.13 and later comes with an official Android build script.
147147
else
148-
mkdir -p cross-build/build
149-
ln -s "$(which python$version_short)" cross-build/build/python
148+
case "$abi" in
149+
arm64-v8a|x86_64)
150+
;;
151+
*)
152+
echo "Python $version_short official Android build supports only: arm64-v8a, x86_64"
153+
exit 1
154+
;;
155+
esac
156+
157+
# CPython's Android tooling expects ANDROID_HOME and ANDROID_API_LEVEL.
158+
export ANDROID_API_LEVEL="$api_level"
159+
if [ -z "${ANDROID_HOME:-}" ]; then
160+
if [ -d "$HOME/Library/Android/sdk" ]; then
161+
export ANDROID_HOME="$HOME/Library/Android/sdk"
162+
elif [ -d "$HOME/Android/Sdk" ]; then
163+
export ANDROID_HOME="$HOME/Android/Sdk"
164+
else
165+
export ANDROID_HOME="$script_dir/android-sdk"
166+
mkdir -p "$ANDROID_HOME"
167+
fi
168+
fi
169+
170+
# Reuse NDK installed by this repo's older workflow by exposing it
171+
# at the path expected by CPython's Android/android-env.sh.
172+
if [ -z "${NDK_HOME:-}" ] && [ -d "$HOME/ndk/r29" ]; then
173+
export NDK_HOME="$HOME/ndk/r29"
174+
fi
175+
cpython_ndk_version=$(sed -n 's/^ndk_version=//p' Android/android-env.sh | head -n1)
176+
if [ -n "${NDK_HOME:-}" ] && [ -d "$NDK_HOME" ] && [ -n "${cpython_ndk_version:-}" ]; then
177+
mkdir -p "$ANDROID_HOME/ndk"
178+
if [ ! -e "$ANDROID_HOME/ndk/$cpython_ndk_version" ]; then
179+
ln -s "$NDK_HOME" "$ANDROID_HOME/ndk/$cpython_ndk_version"
180+
fi
181+
fi
150182

183+
Android/android.py configure-build
184+
Android/android.py make-build
151185
Android/android.py configure-host "$HOST"
152186
Android/android.py make-host "$HOST"
153187
cp -a "cross-build/$HOST/prefix/"* "$PREFIX"

android/package-for-dart.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ script_dir=$(dirname $(realpath $0))
1313
# build short Python version
1414
read python_version_major python_version_minor < <(echo $python_version | sed -E 's/^([0-9]+)\.([0-9]+).*/\1 \2/')
1515
python_version_short=$python_version_major.$python_version_minor
16+
python_bin=$(command -v "python$python_version_short" || true)
17+
if [ -z "$python_bin" ]; then
18+
echo "python$python_version_short is required to compile stdlib bytecode"
19+
exit 1
20+
fi
1621

1722
# create build dir
1823
build_dir=build/python-$python_version/$abi
@@ -39,8 +44,8 @@ mv $build_dir/lib/python$python_version_short/lib-dynload $bundle_dir/modules
3944

4045
# stdlib
4146
# stdlib_zip=$bundle_dir/stdlib.zip
47+
"$python_bin" -I -m compileall -b "$build_dir/lib/python$python_version_short"
4248
cd $build_dir/lib/python$python_version_short
43-
python -m compileall -b .
4449
find . \( -name '*.so' -or -name '*.py' -or -name '*.typed' \) -type f -delete
4550
rm -rf __pycache__
4651
rm -rf **/__pycache__

android/patches/3.13_pending.patch

Lines changed: 0 additions & 39 deletions
This file was deleted.

darwin/package-ios-for-dart.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ script_dir=$(dirname $(realpath $0))
1111
# build short Python version
1212
read python_version_major python_version_minor < <(echo $python_version | sed -E 's/^([0-9]+)\.([0-9]+).*/\1 \2/')
1313
python_version_short=$python_version_major.$python_version_minor
14+
python_bin=$(command -v "python$python_version_short" || true)
15+
if [ -z "$python_bin" ]; then
16+
echo "python$python_version_short is required to compile stdlib bytecode"
17+
exit 1
18+
fi
1419

1520
# create build directory
1621
build_dir=build/python-$python_version
@@ -63,9 +68,9 @@ for arch in "${archs[@]}"; do
6368
rm -rf $stdlib_dir/$arch
6469
done
6570

66-
# compile stdlib
71+
# compile stdlib with an isolated interpreter, without importing from target stdlib dir.
72+
"$python_bin" -I -m compileall -b "$stdlib_dir"
6773
cd $stdlib_dir
68-
python -m compileall -b .
6974
find . \( -name '*.so' -or -name "*.$dylib_ext" -or -name '*.py' -or -name '*.typed' \) -type f -delete
7075
rm -rf __pycache__
7176
rm -rf **/__pycache__

darwin/package-macos-for-dart.sh

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ script_dir=$(dirname $(realpath $0))
99
# build short Python version
1010
read python_version_major python_version_minor < <(echo $python_version | sed -E 's/^([0-9]+)\.([0-9]+).*/\1 \2/')
1111
python_version_short=$python_version_major.$python_version_minor
12+
python_bin=$(command -v "python$python_version_short" || true)
13+
if [ -z "$python_bin" ]; then
14+
echo "python$python_version_short is required to compile stdlib bytecode"
15+
exit 1
16+
fi
1217

1318
# create build directory
1419
build_dir=build/python-$python_version
@@ -34,9 +39,9 @@ rm $frameworks_dir/Python.xcframework/macos-arm64_x86_64/Python.framework/Header
3439
# copy stdlibs
3540
rsync -av --exclude-from=$script_dir/python-darwin-stdlib.exclude $python_apple_support_root/install/macOS/macosx/python-*/Python.framework/Versions/Current/lib/python$python_version_short/* $stdlib_dir
3641

37-
# compile stdlib
42+
# compile stdlib with an isolated interpreter, without importing from target stdlib dir.
43+
"$python_bin" -I -m compileall -b "$stdlib_dir"
3844
cd $stdlib_dir
39-
python -m compileall -b .
4045
find . \( -name '*.py' -or -name '*.typed' \) -type f -delete
4146
rm -rf __pycache__
4247
rm -rf **/__pycache__

0 commit comments

Comments
 (0)