Skip to content

Commit

Permalink
Build Python for Android
Browse files Browse the repository at this point in the history
  • Loading branch information
FeodorFitsner committed Sep 27, 2024
1 parent 9499a64 commit 3961917
Show file tree
Hide file tree
Showing 15 changed files with 656 additions and 9 deletions.
44 changes: 35 additions & 9 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ skip_branch_with_pr: true
environment:
python_stack: python 3.12
PYTHON_VERSION: 3.12.6
GITHUB_TOKEN:
secure: 9SKIwc3VSfYJ5IChvNR74rlTF9BMbAfhCGu1/TmYJBMtC6lkY+UDDkZNK7rC9xnQFUxMrNgoo9kNcNAbKbU8XAcrSwkP2H4mX04FI7P+YbxfiWC8nVHhGNxR4LzO+GO0

matrix:
# - job_name: Build Python for Linux
# APPVEYOR_BUILD_WORKER_IMAGE: ubuntu
- job_name: Build Python for Android
APPVEYOR_BUILD_WORKER_IMAGE: ubuntu-gce-c
NDK_VERSION: r27

- job_name: Build Python for Windows
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
# - job_name: Build Python for Windows
# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022

matrix:
fast_finish: true
Expand All @@ -19,19 +22,42 @@ stack: $python_stack

for:
# ======================================
# Build Python for Linux
# Build Python for Android
# ======================================

- matrix:
only:
- job_name: Build Python for Linux
- job_name: Build Python for Android

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

build_script:
- sh: |
echo build
- cd android

# Build all Python ABIs
- ./build-all.sh $PYTHON_VERSION

# Package support package for use with mobile-forge
- mkdir -p dist
- tar -czf dist/python-android-mobile-forge-$PYTHON_VERSION_SHORT.tar.gz install support

# Package individual ABIs for use with serious_python Flutter package
- ./package-for-dart.sh install $PYTHON_VERSION arm64-v8a
- ./package-for-dart.sh install $PYTHON_VERSION armeabi-v7a
- ./package-for-dart.sh install $PYTHON_VERSION x86_64

# Push all archives to artifacts
- find dist -maxdepth 1 -type f -iname python-android-*.tar.gz -exec appveyor PushArtifact -DeploymentName python-android {} \;

test: off

deploy:
provider: GitHub
auth_token: $(GITHUB_TOKEN)
release: v$(PYTHON_VERSION_SHORT)
artifact: python-android

# ======================================
# Build Python for Windows
Expand Down
13 changes: 13 additions & 0 deletions android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.envrc
.vscode/
build
dist
downloads
install
local
support
*.dist-info
__pycache__
*.log
*.gz
*.DS_Store
33 changes: 33 additions & 0 deletions android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Python for Android

Scripts and CI jobs for building Python 3 for Android.

* Can be run on both Linux and macOS.
* Build Python 3.12 - specific or the last minor version.
* Installs NDK r26d or use pre-installed one with path configured by `NDK_HOME` variable.
* Creates Python installation with a structure suitable for https://github.com/flet-dev/mobile-forge

## Usage

To build the latest minor version of Python 3.12 for selected Android API:

```
./build.sh 3.12 arm64-v8a
```

To build all ABIs:

```
./build-all.sh 3.12
```

## Credits

Build process depends on:
* https://github.com/beeware/cpython-android-source-deps

Based on the work from:
* https://github.com/chaquo/chaquopy/tree/master/target
* https://github.com/beeware/Python-Android-support
* https://github.com/beeware/cpython-android-source-deps
* https://github.com/GRRedWings/python3-android
107 changes: 107 additions & 0 deletions android/android-env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
fail() {
echo "$1" >&2
exit 1
}

if [[ -z "${NDK_HOME-}" ]]; then
NDK_HOME=$HOME/ndk/$NDK_VERSION
echo "NDK_HOME environment variable is not set."
if [ ! -d $NDK_HOME ]; then
echo "Installing NDK $NDK_VERSION to $NDK_HOME"

if [ $(uname) = "Darwin" ]; then
seven_zip=$downloads/7zip/7zz
if ! test -f $seven_zip; then
echo "Installing 7-zip"
mkdir -p $(dirname $seven_zip)
cd $(dirname $seven_zip)
curl -#OL https://www.7-zip.org/a/7z2301-mac.tar.xz
tar -xf 7z2301-mac.tar.xz
cd -
fi

ndk_dmg=android-ndk-$NDK_VERSION-darwin.dmg
if ! test -f $downloads/$ndk_dmg; then
echo ">>> Downloading $ndk_dmg"
curl -#L -o $downloads/$ndk_dmg https://dl.google.com/android/repository/$ndk_dmg
fi

cd $downloads
$seven_zip x -snld $ndk_dmg
mkdir -p $(dirname $NDK_HOME)
mv Android\ NDK\ */AndroidNDK*.app/Contents/NDK $NDK_HOME
rm -rf Android\ NDK\ *
cd -
else
ndk_zip=android-ndk-$NDK_VERSION-linux.zip
if ! test -f $downloads/$ndk_zip; then
echo ">>> Downloading $ndk_zip"
curl -#L -o $downloads/$ndk_zip https://dl.google.com/android/repository/$ndk_zip
fi
cd $downloads
unzip -oq $ndk_zip
mkdir -p $(dirname $NDK_HOME)
mv android-ndk-$NDK_VERSION $NDK_HOME
cd -
echo "NDK installed to $NDK_HOME"
fi
else
echo "NDK $NDK_VERSION is already installed in $NDK_HOME"
fi
else
echo "NDK home: $NDK_HOME"
fi

if [ $host_triplet = "arm-linux-androideabi" ]; then
clang_triplet=armv7a-linux-androideabi
else
clang_triplet=$host_triplet
fi

# These variables are based on BuildSystemMaintainers.md above, and
# $NDK_HOME/build/cmake/android.toolchain.cmake.
toolchain=$(echo $NDK_HOME/toolchains/llvm/prebuilt/*)
export AR="$toolchain/bin/llvm-ar"
export AS="$toolchain/bin/llvm-as"
export CC="$toolchain/bin/${clang_triplet}$api_level-clang"
export CXX="${CC}++"
export LD="$toolchain/bin/ld"
export NM="$toolchain/bin/llvm-nm"
export RANLIB="$toolchain/bin/llvm-ranlib"
export READELF="$toolchain/bin/llvm-readelf"
export STRIP="$toolchain/bin/llvm-strip"

# The quotes make sure the wildcard in the `toolchain` assignment has been expanded.
for path in "$AR" "$AS" "$CC" "$CXX" "$LD" "$NM" "$RANLIB" "$READELF" "$STRIP"; do
if ! [ -e "$path" ]; then
fail "$path does not exist"
fi
done

# Use -idirafter so that package-specified -I directories take priority. For example,
# grpcio provides its own BoringSSL headers which must be used rather than our OpenSSL.
export CFLAGS="-idirafter ${prefix:?}/include"
export LDFLAGS="-L${prefix:?}/lib -Wl,--build-id=sha1 -Wl,--no-rosegment"

# Many packages get away with omitting this on standard Linux, but Android is stricter.
LDFLAGS+=" -lm"

case $abi in
armeabi-v7a)
CFLAGS+=" -march=armv7-a -mthumb"
;;
x86)
# -mstackrealign is unnecessary because it's included in the clang launcher script
# which is pointed to by $CC.
;;
esac

export PKG_CONFIG="pkg-config --define-prefix"
export PKG_CONFIG_LIBDIR="$prefix/lib/pkgconfig"

# conda-build variable name
if [ $(uname) = "Darwin" ]; then
export CPU_COUNT=$(sysctl -n hw.ncpu)
else
export CPU_COUNT=$(nproc)
fi
9 changes: 9 additions & 0 deletions android/build-all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash
set -eu

python_version=${1:?}
abis="arm64-v8a armeabi-v7a x86_64 x86"

for abi in $abis; do
./build.sh $python_version $abi
done
Loading

0 comments on commit 3961917

Please sign in to comment.