#!/usr/bin/env python3 # file: scripts/build_android_rust.py # version: 1 """Build one Android Rust game entrypoint and stage it as Gradle jniLibs.""" from __future__ import annotations import argparse import os import pathlib import subprocess import sys import zipfile ABI_TO_TRIPLE = { "arm64-v8a": "aarch64-linux-android", "armeabi-v7a": "armv7-linux-androideabi", "x86_64": "x86_64-linux-android", "x86": "i686-linux-android", } GAME_TO_MODULE = {"reflex": "game-reflex-poc", "snake": "game-snake-poc"} def read_sdl3_aar_name(properties_path: pathlib.Path) -> str: """Read the configured SDL3 AAR filename.""" for raw_line in properties_path.read_text(encoding="utf-8").splitlines(): line = raw_line.strip() if line.startswith("sdl3AarName="): return line.split("=", 1)[1].strip() raise RuntimeError("sdl3AarName is missing from Android/gradle.properties") def extract_sdl3_link_library(aar_path: pathlib.Path, abi: str, output_dir: pathlib.Path) -> pathlib.Path: """Extract the SDL3 shared library used only for the Rust linker search path.""" expected = f"jni/{abi}/libSDL3.so" output_dir.mkdir(parents=True, exist_ok=True) with zipfile.ZipFile(aar_path) as archive: if expected not in archive.namelist(): raise RuntimeError(f"{expected} is missing from {aar_path}") target = output_dir / "libSDL3.so" target.write_bytes(archive.read(expected)) return target def main() -> int: """Build the requested game entrypoint for one Android ABI.""" parser = argparse.ArgumentParser() parser.add_argument("game", choices=sorted(GAME_TO_MODULE)) parser.add_argument("--abi", choices=sorted(ABI_TO_TRIPLE), default="arm64-v8a") parser.add_argument("--release", action="store_true") arguments = parser.parse_args() root = pathlib.Path(__file__).resolve().parent.parent aar_name = read_sdl3_aar_name(root / "Android" / "gradle.properties") aar_path = root / "Android" / "libs" / aar_name if not aar_path.is_file(): print(f"missing SDL3 AAR: {aar_path}", file=sys.stderr) return 2 link_dir = root / "Android" / "build" / "rust-link" / arguments.abi try: extract_sdl3_link_library(aar_path, arguments.abi, link_dir) except (OSError, RuntimeError, zipfile.BadZipFile) as error: print(str(error), file=sys.stderr) return 2 module = GAME_TO_MODULE[arguments.game] output = root / "Android" / module / "src" / "main" / "jniLibs" environment = os.environ.copy() rustflags = environment.get("RUSTFLAGS", "").strip() link_flag = f"-L native={link_dir}" environment["RUSTFLAGS"] = f"{rustflags} {link_flag}".strip() environment["CARGO_NDK_PLATFORM"] = "21" command = [ "cargo", "ndk", "-t", arguments.abi, "-o", str(output), "build", "-p", "game-android-entrypoint", "--no-default-features", "--features", arguments.game, ] if arguments.release: command.append("--release") completed = subprocess.run(command, cwd=root, env=environment, check=False) return completed.returncode if __name__ == "__main__": raise SystemExit(main())