1 #!/usr/bin/env bash
2 # build-android.sh
3 #
4 # Builds the Onde Rust crate as an Android shared library (.so) for all ABIs
5 # and copies the outputs into lib/src/main/jniLibs/ for the Gradle build.
6 #
7 # Why this script uses plain indexed arrays instead of associative arrays:
8 # some environments still ship older Bash versions, and associative arrays can
9 # fail there. Indexed arrays are much more portable.
10 #
11 # Prerequisites
12 # -------------
13 # 1. Rust Android targets installed:
14 # rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android i686-linux-android
15 #
16 # 2. Android NDK installed and ANDROID_NDK_HOME set:
17 # export ANDROID_NDK_HOME=$HOME/Library/Android/sdk/ndk/26.1.10909125
18 #
19 # 3. cargo-ndk installed:
20 # cargo install cargo-ndk
21 #
22 # Usage
23 # -----
24 # ./scripts/build-android.sh
25 # ./scripts/build-android.sh --debug
26 # FILTER_ABI=arm64-v8a ./scripts/build-android.sh
27
28 set -euo pipefail
29
30 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
31 SDK_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
32 REPO_ROOT="$(cd "$SDK_DIR/../.." && pwd)"
33 JNILIBS_DIR="$SDK_DIR/lib/src/androidMain/jniLibs"
34
35 PROFILE="release"
36 for arg in "$@"; do
37 if [[ "$arg" == "--debug" ]]; then
38 PROFILE="debug"
39 fi
40 done
41
42 # Keep these arrays in the same order.
43 ABIS=(
44 "arm64-v8a"
45 "armeabi-v7a"
46 "x86_64"
47 "x86"
48 )
49
50 RUST_TARGETS=(
51 "aarch64-linux-android"
52 "armv7-linux-androideabi"
53 "x86_64-linux-android"
54 "i686-linux-android"
55 )
56
57 if [[ "${#ABIS[@]}" -ne "${#RUST_TARGETS[@]}" ]]; then
58 echo "Error: ABI and Rust target arrays are out of sync."
59 exit 1
60 fi
61
62 if [[ -z "${ANDROID_NDK_HOME:-}" ]]; then
63 echo "Error: ANDROID_NDK_HOME is not set."
64 echo "Example: export ANDROID_NDK_HOME=\$HOME/Library/Android/sdk/ndk/26.1.10909125"
65 exit 1
66 fi
67
68 if ! command -v cargo-ndk >/dev/null 2>&1; then
69 echo "Error: cargo-ndk not found."
70 echo "Install with: cargo install cargo-ndk"
71 exit 1
72 fi
73
74 SELECTED_ABIS=()
75 SELECTED_TARGETS=()
76
77 if [[ -n "${FILTER_ABI:-}" ]]; then
78 FOUND="false"
79 for i in "${!ABIS[@]}"; do
80 if [[ "${ABIS[$i]}" == "$FILTER_ABI" ]]; then
81 SELECTED_ABIS+=("${ABIS[$i]}")
82 SELECTED_TARGETS+=("${RUST_TARGETS[$i]}")
83 FOUND="true"
84 break
85 fi
86 done
87
88 if [[ "$FOUND" != "true" ]]; then
89 echo "Error: FILTER_ABI='$FILTER_ABI' is not supported."
90 echo "Supported ABIs: ${ABIS[*]}"
91 exit 1
92 fi
93 else
94 SELECTED_ABIS=("${ABIS[@]}")
95 SELECTED_TARGETS=("${RUST_TARGETS[@]}")
96 fi
97
98 echo "=== Building Onde for Android (profile: $PROFILE) ==="
99 echo "Repository root: $REPO_ROOT"
100 echo "Output jniLibs: $JNILIBS_DIR"
101
102 cd "$REPO_ROOT"
103
104 CARGO_NDK_ARGS=(--manifest-path Cargo.toml)
105 if [[ "$PROFILE" == "release" ]]; then
106 CARGO_NDK_ARGS+=(--release)
107 fi
108
109 ABI_FLAGS=()
110 for abi in "${SELECTED_ABIS[@]}"; do
111 ABI_FLAGS+=(-t "$abi")
112 done
113
114 echo "→ cargo ndk ${ABI_FLAGS[*]} build ${CARGO_NDK_ARGS[*]}"
115 cargo ndk "${ABI_FLAGS[@]}" build "${CARGO_NDK_ARGS[@]}"
116
117 for i in "${!SELECTED_ABIS[@]}"; do
118 abi="${SELECTED_ABIS[$i]}"
119 rust_target="${SELECTED_TARGETS[$i]}"
120 src="$REPO_ROOT/target/$rust_target/$PROFILE/libonde.so"
121 dst="$JNILIBS_DIR/$abi/libonde.so"
122
123 if [[ ! -f "$src" ]]; then
124 echo "Error: expected output not found: $src"
125 exit 1
126 fi
127
128 mkdir -p "$(dirname "$dst")"
129 cp "$src" "$dst"
130 echo "✓ $abi -> $dst"
131 done
132
133 echo
134 echo "Android build complete."
135 echo "Shared libraries copied to: $JNILIBS_DIR"