android_ndk_sysroot.sh (6730B)
1 #!/usr/bin/env bash 2 # Download and cache the Android NDK, exposing its sysroot for kit's aarch64 3 # Android hosted profile. 4 # 5 # usage: 6 # scripts/android_ndk_sysroot.sh prepare [aa64] 7 # scripts/android_ndk_sysroot.sh path [aa64] 8 # scripts/android_ndk_sysroot.sh root 9 # scripts/android_ndk_sysroot.sh env [aa64] 10 11 set -eu 12 13 RELEASE="${KIT_ANDROID_NDK_RELEASE:-r27d}" 14 REPO_XML="${KIT_ANDROID_NDK_REPOSITORY_XML:-https://dl.google.com/android/repository/repository2-1.xml}" 15 BASE_URL="${KIT_ANDROID_NDK_BASE_URL:-https://dl.google.com/android/repository}" 16 XDG_CACHE_HOME="${XDG_CACHE_HOME:-${HOME:-}/.cache}" 17 CACHE="${KIT_ANDROID_NDK_CACHE:-$XDG_CACHE_HOME/kit/android-ndk/$RELEASE}" 18 19 die() { printf 'android-ndk-sysroot: %s\n' "$*" >&2; exit 1; } 20 21 canon_arch() { 22 case "${1:-aa64}" in 23 aa64|aarch64|arm64|"") echo aarch64 ;; 24 all) echo all ;; 25 *) die "unknown arch '${1:-}' (Android support is aarch64 only)" ;; 26 esac 27 } 28 29 host_asset() { 30 case "$(uname -s 2>/dev/null || echo unknown)" in 31 Darwin) echo "android-ndk-$RELEASE-darwin.zip" ;; 32 Linux) echo "android-ndk-$RELEASE-linux.zip" ;; 33 MINGW*|MSYS*|CYGWIN*) echo "android-ndk-$RELEASE-windows.zip" ;; 34 *) die "unsupported host OS: $(uname -s 2>/dev/null || echo unknown)" ;; 35 esac 36 } 37 38 sha1_file() { 39 if command -v shasum >/dev/null 2>&1; then 40 shasum -a 1 "$1" | awk '{ print $1 }' 41 return 0 42 fi 43 if command -v sha1sum >/dev/null 2>&1; then 44 sha1sum "$1" | awk '{ print $1 }' 45 return 0 46 fi 47 die "missing shasum or sha1sum" 48 } 49 50 metadata_field() { 51 local asset="$1" field="$2" xml="$CACHE/repository2-1.xml" 52 mkdir -p "$CACHE" 53 if [ "${FORCE:-0}" = 1 ] || [ ! -f "$xml" ]; then 54 command -v curl >/dev/null 2>&1 || die "curl not found" 55 curl -fsSL "$REPO_XML" -o "$xml.tmp" 56 mv "$xml.tmp" "$xml" 57 fi 58 case "$field" in 59 checksum) 60 awk -v want="$asset" ' 61 /<checksum>/ { c=$0; sub(/^.*<checksum>/, "", c); sub(/<\/checksum>.*$/, "", c) } 62 /<url>/ { u=$0; sub(/^.*<url>/, "", u); sub(/<\/url>.*$/, "", u); if (u == want) { print c; exit } } 63 ' "$xml" 64 ;; 65 url) 66 awk -v want="$asset" ' 67 /<url>/ { u=$0; sub(/^.*<url>/, "", u); sub(/<\/url>.*$/, "", u); if (u == want) { print u; exit } } 68 ' "$xml" 69 ;; 70 *) die "internal bad metadata field: $field" ;; 71 esac 72 } 73 74 archive_path() { printf '%s/%s\n' "$CACHE" "$(host_asset)"; } 75 install_root() { printf '%s/android-ndk-%s\n' "$CACHE" "$RELEASE"; } 76 77 verify_archive() { 78 local path="$1" want="$2" got 79 [ -n "$want" ] || die "no repository checksum found for $(basename "$path")" 80 got="$(sha1_file "$path")" 81 [ "$got" = "$want" ] || 82 die "checksum mismatch for $(basename "$path"): got $got want $want" 83 } 84 85 fetch_archive() { 86 local asset full_url path want url 87 asset="$(host_asset)" 88 path="$(archive_path)" 89 want="$(metadata_field "$asset" checksum)" 90 [ -n "$want" ] || die "no repository checksum found for $asset" 91 url="$(metadata_field "$asset" url)" 92 [ -n "$url" ] || die "no repository URL found for $asset" 93 mkdir -p "$CACHE" 94 if [ -f "$path" ]; then 95 verify_archive "$path" "$want" 96 printf 'archive already verified: %s\n' "$path" 97 return 0 98 fi 99 command -v curl >/dev/null 2>&1 || die "curl not found" 100 full_url="$BASE_URL/$url" 101 printf 'download: %s\n' "$full_url" 102 curl -fL --retry 3 --retry-delay 2 --continue-at - -o "$path.part" "$full_url" 103 mv "$path.part" "$path" 104 verify_archive "$path" "$want" 105 printf 'verified: %s\n' "$path" 106 } 107 108 prebuilt_dir() { 109 local root="$1" d 110 for d in "$root"/toolchains/llvm/prebuilt/*; do 111 [ -d "$d" ] || continue 112 printf '%s\n' "$d" 113 return 0 114 done 115 return 1 116 } 117 118 sysroot_path() { 119 local root d 120 canon_arch "${1:-aa64}" >/dev/null 121 root="$(install_root)" 122 if d="$(prebuilt_dir "$root" 2>/dev/null)"; then 123 printf '%s/sysroot\n' "$d" 124 return 0 125 fi 126 case "$(uname -s 2>/dev/null || echo unknown)" in 127 Darwin) printf '%s/toolchains/llvm/prebuilt/darwin-x86_64/sysroot\n' "$root" ;; 128 Linux) printf '%s/toolchains/llvm/prebuilt/linux-x86_64/sysroot\n' "$root" ;; 129 MINGW*|MSYS*|CYGWIN*) printf '%s/toolchains/llvm/prebuilt/windows-x86_64/sysroot\n' "$root" ;; 130 *) die "unsupported host OS: $(uname -s 2>/dev/null || echo unknown)" ;; 131 esac 132 } 133 134 prepare() { 135 local arch root path sr 136 arch="$(canon_arch "${1:-aa64}")" 137 [ "$arch" = aarch64 ] || die "prepare requires aa64/aarch64" 138 root="$(install_root)" 139 if [ "${FORCE:-0}" != 1 ] && [ -r "$(sysroot_path "$arch")/usr/include/android/native_activity.h" ]; then 140 printf 'sysroot cached: %s\n' "$(sysroot_path "$arch")" 141 return 0 142 fi 143 fetch_archive 144 path="$(archive_path)" 145 rm -rf "$root.tmp" 146 mkdir -p "$CACHE" 147 command -v unzip >/dev/null 2>&1 || die "unzip not found" 148 unzip -q "$path" -d "$root.tmp" 149 if [ -d "$root.tmp/android-ndk-$RELEASE" ]; then 150 rm -rf "$root" 151 mv "$root.tmp/android-ndk-$RELEASE" "$root" 152 rm -rf "$root.tmp" 153 else 154 rm -rf "$root.tmp" 155 die "archive did not contain android-ndk-$RELEASE" 156 fi 157 sr="$(sysroot_path "$arch")" 158 [ -r "$sr/usr/include/android/native_activity.h" ] || 159 die "NDK sysroot missing android/native_activity.h" 160 [ -d "$sr/usr/lib/aarch64-linux-android" ] || 161 die "NDK sysroot missing aarch64 Android libraries" 162 { 163 printf 'release=%s\n' "$RELEASE" 164 printf 'asset=%s\n' "$(basename "$path")" 165 printf 'url=%s/%s\n' "$BASE_URL" "$(metadata_field "$(basename "$path")" url)" 166 printf 'sha1=%s\n' "$(metadata_field "$(basename "$path")" checksum)" 167 printf 'target=aarch64-linux-android\n' 168 } > "$root/PROVENANCE" 169 printf 'sysroot ready: %s\n' "$sr" 170 } 171 172 doctor() { 173 local asset root sr 174 asset="$(host_asset)" 175 root="$(install_root)" 176 sr="$(sysroot_path aa64)" 177 printf 'host: %s/%s\n' "$(uname -s 2>/dev/null)" "$(uname -m 2>/dev/null)" 178 printf 'release: %s\n' "$RELEASE" 179 printf 'asset: %s\n' "$asset" 180 printf 'download cache: %s\n' "$CACHE" 181 printf 'ndk root: %s%s\n' "$root" "$([ -d "$root" ] && echo '' || echo ' (missing)')" 182 printf 'sysroot: %s%s\n' "$sr" "$([ -d "$sr" ] && echo '' || echo ' (missing)')" 183 for tool in curl unzip shasum sha1sum; do 184 if command -v "$tool" >/dev/null 2>&1; then 185 printf ' OK %s (%s)\n' "$tool" "$(command -v "$tool")" 186 else 187 printf ' MISSING %s\n' "$tool" 188 fi 189 done 190 } 191 192 cmd="${1:-}" 193 case "$cmd" in 194 doctor) doctor ;; 195 fetch) fetch_archive ;; 196 prepare) shift; prepare "${1:-aa64}" ;; 197 path) shift; sysroot_path "${1:-aa64}" ;; 198 root) install_root ;; 199 env) 200 shift 201 printf 'export KIT_SYSROOT=%s\n' "$(sysroot_path "${1:-aa64}")" 202 ;; 203 -h|--help|help|"") 204 sed -n '2,12p' "$0" | sed 's/^# \{0,1\}//' 205 ;; 206 *) die "unknown command '$cmd' (try: doctor fetch prepare path root env)" ;; 207 esac