Skip to content

Commit 3961917

Browse files
committed
Build Python for Android
1 parent 9499a64 commit 3961917

15 files changed

+656
-9
lines changed

.appveyor.yml

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ skip_branch_with_pr: true
44
environment:
55
python_stack: python 3.12
66
PYTHON_VERSION: 3.12.6
7+
GITHUB_TOKEN:
8+
secure: 9SKIwc3VSfYJ5IChvNR74rlTF9BMbAfhCGu1/TmYJBMtC6lkY+UDDkZNK7rC9xnQFUxMrNgoo9kNcNAbKbU8XAcrSwkP2H4mX04FI7P+YbxfiWC8nVHhGNxR4LzO+GO0
79

810
matrix:
9-
# - job_name: Build Python for Linux
10-
# APPVEYOR_BUILD_WORKER_IMAGE: ubuntu
11+
- job_name: Build Python for Android
12+
APPVEYOR_BUILD_WORKER_IMAGE: ubuntu-gce-c
13+
NDK_VERSION: r27
1114

12-
- job_name: Build Python for Windows
13-
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
15+
# - job_name: Build Python for Windows
16+
# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
1417

1518
matrix:
1619
fast_finish: true
@@ -19,19 +22,42 @@ stack: $python_stack
1922

2023
for:
2124
# ======================================
22-
# Build Python for Linux
25+
# Build Python for Android
2326
# ======================================
2427

2528
- matrix:
2629
only:
27-
- job_name: Build Python for Linux
30+
- job_name: Build Python for Android
2831

2932
install:
30-
- echo install
33+
- read ver_maj ver_min < <(echo $PYTHON_VERSION | sed -E 's/^([0-9]+)\.([0-9]+).*/\1 \2/')
34+
- export PYTHON_VERSION_SHORT="$ver_maj.$ver_min"
3135

3236
build_script:
33-
- sh: |
34-
echo build
37+
- cd android
38+
39+
# Build all Python ABIs
40+
- ./build-all.sh $PYTHON_VERSION
41+
42+
# Package support package for use with mobile-forge
43+
- mkdir -p dist
44+
- tar -czf dist/python-android-mobile-forge-$PYTHON_VERSION_SHORT.tar.gz install support
45+
46+
# Package individual ABIs for use with serious_python Flutter package
47+
- ./package-for-dart.sh install $PYTHON_VERSION arm64-v8a
48+
- ./package-for-dart.sh install $PYTHON_VERSION armeabi-v7a
49+
- ./package-for-dart.sh install $PYTHON_VERSION x86_64
50+
51+
# Push all archives to artifacts
52+
- find dist -maxdepth 1 -type f -iname python-android-*.tar.gz -exec appveyor PushArtifact -DeploymentName python-android {} \;
53+
54+
test: off
55+
56+
deploy:
57+
provider: GitHub
58+
auth_token: $(GITHUB_TOKEN)
59+
release: v$(PYTHON_VERSION_SHORT)
60+
artifact: python-android
3561

3662
# ======================================
3763
# Build Python for Windows

android/.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.envrc
2+
.vscode/
3+
build
4+
dist
5+
downloads
6+
install
7+
local
8+
support
9+
*.dist-info
10+
__pycache__
11+
*.log
12+
*.gz
13+
*.DS_Store

android/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Python for Android
2+
3+
Scripts and CI jobs for building Python 3 for Android.
4+
5+
* Can be run on both Linux and macOS.
6+
* Build Python 3.12 - specific or the last minor version.
7+
* Installs NDK r26d or use pre-installed one with path configured by `NDK_HOME` variable.
8+
* Creates Python installation with a structure suitable for https://github.com/flet-dev/mobile-forge
9+
10+
## Usage
11+
12+
To build the latest minor version of Python 3.12 for selected Android API:
13+
14+
```
15+
./build.sh 3.12 arm64-v8a
16+
```
17+
18+
To build all ABIs:
19+
20+
```
21+
./build-all.sh 3.12
22+
```
23+
24+
## Credits
25+
26+
Build process depends on:
27+
* https://github.com/beeware/cpython-android-source-deps
28+
29+
Based on the work from:
30+
* https://github.com/chaquo/chaquopy/tree/master/target
31+
* https://github.com/beeware/Python-Android-support
32+
* https://github.com/beeware/cpython-android-source-deps
33+
* https://github.com/GRRedWings/python3-android

android/android-env.sh

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
fail() {
2+
echo "$1" >&2
3+
exit 1
4+
}
5+
6+
if [[ -z "${NDK_HOME-}" ]]; then
7+
NDK_HOME=$HOME/ndk/$NDK_VERSION
8+
echo "NDK_HOME environment variable is not set."
9+
if [ ! -d $NDK_HOME ]; then
10+
echo "Installing NDK $NDK_VERSION to $NDK_HOME"
11+
12+
if [ $(uname) = "Darwin" ]; then
13+
seven_zip=$downloads/7zip/7zz
14+
if ! test -f $seven_zip; then
15+
echo "Installing 7-zip"
16+
mkdir -p $(dirname $seven_zip)
17+
cd $(dirname $seven_zip)
18+
curl -#OL https://www.7-zip.org/a/7z2301-mac.tar.xz
19+
tar -xf 7z2301-mac.tar.xz
20+
cd -
21+
fi
22+
23+
ndk_dmg=android-ndk-$NDK_VERSION-darwin.dmg
24+
if ! test -f $downloads/$ndk_dmg; then
25+
echo ">>> Downloading $ndk_dmg"
26+
curl -#L -o $downloads/$ndk_dmg https://dl.google.com/android/repository/$ndk_dmg
27+
fi
28+
29+
cd $downloads
30+
$seven_zip x -snld $ndk_dmg
31+
mkdir -p $(dirname $NDK_HOME)
32+
mv Android\ NDK\ */AndroidNDK*.app/Contents/NDK $NDK_HOME
33+
rm -rf Android\ NDK\ *
34+
cd -
35+
else
36+
ndk_zip=android-ndk-$NDK_VERSION-linux.zip
37+
if ! test -f $downloads/$ndk_zip; then
38+
echo ">>> Downloading $ndk_zip"
39+
curl -#L -o $downloads/$ndk_zip https://dl.google.com/android/repository/$ndk_zip
40+
fi
41+
cd $downloads
42+
unzip -oq $ndk_zip
43+
mkdir -p $(dirname $NDK_HOME)
44+
mv android-ndk-$NDK_VERSION $NDK_HOME
45+
cd -
46+
echo "NDK installed to $NDK_HOME"
47+
fi
48+
else
49+
echo "NDK $NDK_VERSION is already installed in $NDK_HOME"
50+
fi
51+
else
52+
echo "NDK home: $NDK_HOME"
53+
fi
54+
55+
if [ $host_triplet = "arm-linux-androideabi" ]; then
56+
clang_triplet=armv7a-linux-androideabi
57+
else
58+
clang_triplet=$host_triplet
59+
fi
60+
61+
# These variables are based on BuildSystemMaintainers.md above, and
62+
# $NDK_HOME/build/cmake/android.toolchain.cmake.
63+
toolchain=$(echo $NDK_HOME/toolchains/llvm/prebuilt/*)
64+
export AR="$toolchain/bin/llvm-ar"
65+
export AS="$toolchain/bin/llvm-as"
66+
export CC="$toolchain/bin/${clang_triplet}$api_level-clang"
67+
export CXX="${CC}++"
68+
export LD="$toolchain/bin/ld"
69+
export NM="$toolchain/bin/llvm-nm"
70+
export RANLIB="$toolchain/bin/llvm-ranlib"
71+
export READELF="$toolchain/bin/llvm-readelf"
72+
export STRIP="$toolchain/bin/llvm-strip"
73+
74+
# The quotes make sure the wildcard in the `toolchain` assignment has been expanded.
75+
for path in "$AR" "$AS" "$CC" "$CXX" "$LD" "$NM" "$RANLIB" "$READELF" "$STRIP"; do
76+
if ! [ -e "$path" ]; then
77+
fail "$path does not exist"
78+
fi
79+
done
80+
81+
# Use -idirafter so that package-specified -I directories take priority. For example,
82+
# grpcio provides its own BoringSSL headers which must be used rather than our OpenSSL.
83+
export CFLAGS="-idirafter ${prefix:?}/include"
84+
export LDFLAGS="-L${prefix:?}/lib -Wl,--build-id=sha1 -Wl,--no-rosegment"
85+
86+
# Many packages get away with omitting this on standard Linux, but Android is stricter.
87+
LDFLAGS+=" -lm"
88+
89+
case $abi in
90+
armeabi-v7a)
91+
CFLAGS+=" -march=armv7-a -mthumb"
92+
;;
93+
x86)
94+
# -mstackrealign is unnecessary because it's included in the clang launcher script
95+
# which is pointed to by $CC.
96+
;;
97+
esac
98+
99+
export PKG_CONFIG="pkg-config --define-prefix"
100+
export PKG_CONFIG_LIBDIR="$prefix/lib/pkgconfig"
101+
102+
# conda-build variable name
103+
if [ $(uname) = "Darwin" ]; then
104+
export CPU_COUNT=$(sysctl -n hw.ncpu)
105+
else
106+
export CPU_COUNT=$(nproc)
107+
fi

android/build-all.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
set -eu
3+
4+
python_version=${1:?}
5+
abis="arm64-v8a armeabi-v7a x86_64 x86"
6+
7+
for abi in $abis; do
8+
./build.sh $python_version $abi
9+
done

0 commit comments

Comments
 (0)