Skip to content

Build armeabi-v7a (32-bit ARM) for Python 3.13/3.14#25

Merged
FeodorFitsner merged 1 commit into
mainfrom
android-armeabi-v7a-313-314
Jun 29, 2026
Merged

Build armeabi-v7a (32-bit ARM) for Python 3.13/3.14#25
FeodorFitsner merged 1 commit into
mainfrom
android-armeabi-v7a-313-314

Conversation

@FeodorFitsner

Copy link
Copy Markdown
Contributor

What & why

Adds armeabi-v7a (32-bit ARM) Android builds for Python 3.13 and 3.14, so all three minors now carry the same ABI set.

The repo previously treated 3.13+ as 64-bit-only, citing PEP 738. That's inaccurate: PEP 738 makes 64-bit Android the tested Tier-3 configuration, but CPython's official Android/android.py still lists arm-linux-androideabi in its supported HOSTS (verified on both v3.13.14 and v3.14.6), and beeware's cpython-android-source-deps publishes the matching *-arm-linux-androideabi.tar.gz dependency assets for every version 3.13/3.14 pin. The only real blocker was a self-imposed ABI gate in build.sh.

Changes

  • android/build.sh — allow armeabi-v7a through the 3.13+ official-build ABI case (the one blocker). Everything downstream (abi-to-host.sharm-linux-androideabi, extract_mobile_forge_deps.py, normalize_mobile_forge_install.py, package-for-dart.sh) was already ABI-agnostic and handled armeabi-v7a for 3.12.
  • android/build-all.sh — read android_abis from manifest.json (the same source the CI packaging loop uses) instead of a separate hardcoded 3.13+ → 64-bit gate. Required for correctness: CI builds via build-all.sh but packages from the manifest, so the two must agree or CI would try to package an ABI it never built. Now the ABI set lives in exactly one place.
  • manifest.json — add armeabi-v7a to 3.13 and 3.14.
  • README.md / android/README.md — correct the "3.13+ are 64-bit-only" note.

Validation

Built and packaged locally via the official tooling — both green:

Version Build Binaries Dart tarball
3.14.6 android-arm, 0 import failures ELF32 / ARM 11.5 MB
3.13.14 android-arm, 0 import failures ELF32 / ARM 10.3 MB

Modules compiled with armv7a-linux-androideabi24-clang -march=armv7-a; deps (openssl/libffi/sqlite/xz/bzip2) downloaded as *-arm-linux-androideabi.tar.gz; normalize + packaging clean. libpython3.{13,14}.so and extension modules confirmed ELF32 / Machine: ARM.

Note for reviewers

This repo only produces the runtime tarball. Shipping 32-bit apps also requires the downstream consumers (serious_python, flet, the Dart bridge) to accept and bundle the armeabi-v7a artifact — separate repos, out of scope here.

CPython's official Android/android.py lists arm-linux-androideabi in its
supported HOSTS for both 3.13 and 3.14, and beeware's cpython-android-source-deps
publishes the matching 32-bit dependency tarballs. PEP 738 makes 64-bit Android
the *tested* Tier-3 configuration; it does not prevent building 32-bit ARM. So
the only blocker was a self-imposed ABI gate in build.sh.

- build.sh: allow armeabi-v7a through the 3.13+ official-build ABI case.
- build-all.sh: read android_abis from manifest.json (same source the CI
  packaging step uses) instead of a separate hardcoded version gate, so the
  build set and package set stay in lockstep.
- manifest.json: add armeabi-v7a to 3.13 and 3.14.
- README/android/README: correct the "3.13+ are 64-bit-only" note.

Validated locally: 3.14.6 and 3.13.14 both build via android.py and package
into Dart tarballs; libpython and extension modules are ELF32/ARM with no
import failures.
@FeodorFitsner FeodorFitsner merged commit ef3c293 into main Jun 29, 2026
16 of 29 checks passed
@FeodorFitsner FeodorFitsner deleted the android-armeabi-v7a-313-314 branch June 29, 2026 19:12
ndonkoHenri added a commit to flet-dev/mobile-forge that referenced this pull request Jun 29, 2026
Companion to flet-dev/python-build#25, which added `armeabi-v7a` (32-bit ARM) runtimes for Python 3.13/3.14. That release (**20260629**) now ships `["arm64-v8a", "x86_64", "armeabi-v7a"]` for **all three** minors, and drops `x86` (32-bit Intel) everywhere.

This PR teaches mobile-forge to consume that: it makes the Android ABI set **manifest-driven** here too, so the same single source of truth flows across both repos and a future ABI change upstream needs only a release-pin bump here — no hardcoded list to keep in sync.

Net effect: forge now builds **armeabi-v7a wheels for 3.13/3.14** (it already did for 3.12), and stops building the now-unshipped **x86**.

## Changes

- **`setup.sh`**
  - Bump `PYTHON_BUILD_RELEASE` `20260614` → `20260629`.
  - New `resolve_android_abis()` — reads `pythons.<minor>.android_abis` from the pinned release's manifest using the same 3-tier parser as `resolve_full_version` (jq → python3 → scoped sed, cached under `downloads/`). Exports **`ANDROID_ABIS`** (env-overridable for the `PYTHON_BUILD_RUN_ID` branch-validation path; also pushed to `GITHUB_ENV`).
  - Android support-tree verification now **loops `$ANDROID_ABIS`** instead of the  hardcoded `minor < 13 → check armeabi+x86` gate.
- **`src/forge/cross.py`** — `ANDROID_HOST_ARCHS` reads `$ANDROID_ABIS` (falls back to
  `("arm64-v8a", "armeabi-v7a", "x86_64")` when forge runs without sourcing setup.sh), replacing the `>=3.13 → 64-bit-only` version gate.
- **`make_dep_wheels.py`** — `get_targets("android")` reads `$ANDROID_ABIS` too, so the support-tree dep wheels (openssl/libffi/sqlite/xz/…) get produced for armeabi-v7a on 3.13/3.14.
- **`.github/workflows/build-wheels-version.yml`** — drop the now-dead `i686-linux-android` Rust target (`arm-linux-androideabi` for armeabi was already present).

No change needed elsewhere: `cross.py` already maps armeabi-v7a → `android-arm` (3.13+ official-build naming) and the wheel tag is the version-independent `android_24_armeabi_v7a`; the CI matrix keys on `android`/`iOS` (per-ABI fan-out happens inside forge); the support-tree dep-wheel drop step is ABI-agnostic.

## Behavioral note: x86 is dropped

`20260629` ships no `x86` runtime for any minor (the mobile-forge tarball is `tar install support` right after `build-all.sh`, which builds only the manifest's ABIs). So bumping the pin necessarily stops x86 wheel production for 3.12 too. Already-published 3.12 x86 wheels become orphaned on the index — harmless, since flet/serious_python don't ship 32-bit Intel.

## Validation

Verified locally:
- All three manifest-parser tiers (jq / python3 / sed) return `arm64-v8a x86_64 armeabi-v7a` for 3.12/3.13/3.14 against the real 20260629 manifest.
- `ANDROID_HOST_ARCHS` / `get_targets` honor `$ANDROID_ABIS` and fall back correctly.
- armeabi-v7a → `_platform_identifier` `android-arm`, tag `android_24_armeabi_v7a`.
- The support-tree binary path the verify loop checks (`install/android/<abi>/python-<full>/bin/python<minor>`) matches the tarball layout.
- `bash -n` + `py_compile` clean; no new lint/format findings.

Full validation comes via the follow-up `packages=ALL` build across python versions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant