#!/usr/bin/env bash # # Cross-compile pydantic-core for Android ARM64. # # Prerequisites: # - Rust toolchain (rustup) # - Android NDK (set ANDROID_NDK_HOME or let this script find it) # - maturin (pip install maturin) # - Python 3.11 (matching Chaquopy's embedded version) # # Output: ../wheels/pydantic_core-*.whl # set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" WHEELS_DIR="$SCRIPT_DIR/../wheels" BUILD_DIR="$SCRIPT_DIR/../.build-cache" # ── Pydantic-core version (must match pydantic>=2.9.2 requirement) ── PYDANTIC_CORE_VERSION="2.27.2" # ── Find Android NDK ──────────────────────────────────────────────── if [ -z "${ANDROID_NDK_HOME:-}" ]; then # Try common locations for candidate in \ "$HOME/Library/Android/sdk/ndk"/* \ "$HOME/Android/Sdk/ndk"/* \ "$LOCALAPPDATA/Android/Sdk/ndk"/* \ "/usr/local/lib/android/sdk/ndk"/*; do if [ -d "$candidate" ]; then ANDROID_NDK_HOME="$candidate" break fi done fi if [ -z "${ANDROID_NDK_HOME:-}" ]; then echo "ERROR: Android NDK not found. Set ANDROID_NDK_HOME or install via Android Studio." exit 1 fi echo "Using Android NDK: $ANDROID_NDK_HOME" # ── Determine NDK API level and toolchain ─────────────────────────── API_LEVEL=24 HOST_TAG="" case "$(uname -s)" in Linux*) HOST_TAG="linux-x86_64" ;; Darwin*) HOST_TAG="darwin-x86_64" ;; MINGW*|MSYS*|CYGWIN*) HOST_TAG="windows-x86_64" ;; *) echo "Unsupported host OS"; exit 1 ;; esac TOOLCHAIN="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG" CC="$TOOLCHAIN/bin/aarch64-linux-android${API_LEVEL}-clang" AR="$TOOLCHAIN/bin/llvm-ar" if [ ! -f "$CC" ] && [ ! -f "${CC}.cmd" ]; then echo "ERROR: NDK compiler not found at $CC" echo "Check your NDK installation." exit 1 fi # ── Install Rust Android target ───────────────────────────────────── echo "Adding Rust target aarch64-linux-android..." rustup target add aarch64-linux-android # ── Configure Cargo for cross-compilation ─────────────────────────── mkdir -p "$BUILD_DIR" export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$CC" export CC_aarch64_linux_android="$CC" export AR_aarch64_linux_android="$AR" # ── Clone pydantic-core ───────────────────────────────────────────── REPO_DIR="$BUILD_DIR/pydantic-core" if [ -d "$REPO_DIR" ]; then echo "Updating existing pydantic-core checkout..." cd "$REPO_DIR" git fetch --tags git checkout "v$PYDANTIC_CORE_VERSION" else echo "Cloning pydantic-core v$PYDANTIC_CORE_VERSION..." git clone --depth 1 --branch "v$PYDANTIC_CORE_VERSION" \ https://github.com/pydantic/pydantic-core.git "$REPO_DIR" cd "$REPO_DIR" fi # ── Build with maturin ────────────────────────────────────────────── echo "Building pydantic-core for aarch64-linux-android..." maturin build \ --release \ --target aarch64-linux-android \ --interpreter python3.11 \ --out "$WHEELS_DIR" echo "" echo "=== Build complete ===" echo "Wheels:" ls -la "$WHEELS_DIR"/pydantic_core-*.whl 2>/dev/null || echo "WARNING: No wheel found!"