From 48de4bcb08d63aff3e2c0cb560d37b1e8b6d287f Mon Sep 17 00:00:00 2001 From: Irastris Date: Wed, 29 Jul 2026 01:47:13 -0400 Subject: [PATCH] Gradle build revisions (#2229) * Gradle build revisions * Update platforms/android/README.md --- .github/workflows/build.yml | 3 - platforms/android/README.md | 19 +--- platforms/android/app/build.gradle | 111 +++++++++++++++++-- platforms/android/scripts/stage-jni-libs.sh | 115 -------------------- 4 files changed, 101 insertions(+), 147 deletions(-) delete mode 100755 platforms/android/scripts/stage-jni-libs.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4712b36439..f7abef73e5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -208,9 +208,6 @@ jobs: - name: Build bundled mods run: cmake --build --preset ${{matrix.preset}} --target dusklight_mods - - name: Stage stripped JNI library - run: ANDROID_STAGE_ABIS="${{matrix.abi}}" platforms/android/scripts/stage-jni-libs.sh - - name: Build APK working-directory: platforms/android run: ./gradlew :app:assembleRelease --rerun-tasks diff --git a/platforms/android/README.md b/platforms/android/README.md index f478871392..7a5d01ee44 100644 --- a/platforms/android/README.md +++ b/platforms/android/README.md @@ -21,26 +21,9 @@ export JAVA_HOME="/usr/lib/jvm/java-17-openjdk" ```bash cmake --preset android-arm64 cmake --build --preset android-arm64 - -cmake --preset android-x86_64 -cmake --build --preset android-x86_64 ``` -These builds produce: - -- `build/android-arm64/Binaries/libmain.so` -- `build/android-x86_64/Binaries/libmain.so` - -## Stage Libraries Into APK Project - -```bash -./android/scripts/stage-jni-libs.sh -``` - -This copies: - -- `libmain.so` -> `android/app/src/main/jniLibs/arm64-v8a/` -- `libmain.so` -> `android/app/src/main/jniLibs/x86_64/` +This build produces `build/android-arm64/libmain.so` ## Refresh SDL Java Shim (Optional) diff --git a/platforms/android/app/build.gradle b/platforms/android/app/build.gradle index c7a25e732b..08d04bf35f 100644 --- a/platforms/android/app/build.gradle +++ b/platforms/android/app/build.gradle @@ -6,23 +6,107 @@ def versionNameStr = (System.getenv("DUSK_VERSION") ?: "v0.1.0").replaceFirst("^ def versionCodeInt = (System.getenv("DUSK_VERSION_CODE") ?: "100000").toInteger() def duskRepoDir = rootProject.projectDir.parentFile.parentFile -def duskGeneratedAssetsDir = layout.buildDirectory.dir('generated/assets/dusklight').get().asFile +def androidNativeBuildDir = new File(duskRepoDir, 'build/android-arm64') +def nativeLibrary = new File(androidNativeBuildDir, 'libmain.so') +def stageStripValue = providers.gradleProperty('ANDROID_STAGE_STRIP') + .orElse(providers.gradleProperty('androidStageStrip')) + .orElse(providers.environmentVariable('ANDROID_STAGE_STRIP')) + .orElse('1') +def androidHome = { + def sdkPath = System.getenv('ANDROID_HOME') + if (!sdkPath) { + throw new GradleException('ANDROID_HOME is not available') + } + def sdkDir = new File(sdkPath) + if (!sdkDir.isDirectory()) { + throw new GradleException("ANDROID_HOME points to a missing directory: ${sdkDir}") + } + sdkDir +}.memoize() + +def androidNdkVersion = { + def ndkVersion = System.getenv('ANDROID_NDK_VERSION') + if (!ndkVersion) { + throw new GradleException('ANDROID_NDK_VERSION is not available') + } + ndkVersion +}.memoize() + +def androidNdkDir = { + def ndkDir = new File(androidHome(), "ndk/${androidNdkVersion()}") + if (!new File(ndkDir, 'build/cmake/android.toolchain.cmake').isFile()) { + throw new GradleException( + "Android NDK ${androidNdkVersion()} is missing or invalid at ${ndkDir}" + ) + } + ndkDir +}.memoize() + +def llvmPrebuiltDir = { + def prebuiltRoot = new File(androidNdkDir(), 'toolchains/llvm/prebuilt') + def prebuiltDir = (prebuiltRoot.listFiles()?.findAll { it.isDirectory() } ?: []) + .sort { it.name } + .find { candidate -> + new File( + candidate, + 'sysroot/usr/lib/aarch64-linux-android/libc++_shared.so' + ).isFile() + } + if (!prebuiltDir) { + throw new GradleException("Cannot find NDK libc++_shared.so under ${prebuiltRoot}") + } + prebuiltDir +}.memoize() + +def stlLibrary = { + def library = new File( + llvmPrebuiltDir(), + 'sysroot/usr/lib/aarch64-linux-android/libc++_shared.so' + ) + if (!library.isFile()) { + throw new GradleException("libc++_shared.so is missing") + } + library +}.memoize() + +def stagedJniLibsDir = layout.buildDirectory.dir('generated/jniLibs/dusklight') + +def stageJniLibs = tasks.register('stageJniLibs', Sync) { + group = 'build' + from(nativeLibrary) { + rename { 'libmain.so' } + into 'arm64-v8a' + } + from(providers.provider { stlLibrary() }) { + rename { 'libc++_shared.so' } + into 'arm64-v8a' + } + into(stagedJniLibsDir) + + doFirst { + if (!nativeLibrary.isFile()) { + throw new GradleException("Native library is missing") + } + } +} + +def duskGeneratedAssetsDir = layout.buildDirectory.dir('generated/assets/dusklight') def syncDuskAssets = tasks.register('syncDuskAssets', Sync) { from(new File(duskRepoDir, 'res')) { into 'res' exclude '**/.DS_Store' } - // Staged by platforms/android/scripts/stage-jni-libs.sh - from(new File(projectDir, 'src/main/bundled_mods')) { + from(new File(androidNativeBuildDir, 'bundled_mods')) { into 'mods' include '*.dusk' } - into duskGeneratedAssetsDir + into(duskGeneratedAssetsDir) } android { namespace 'dev.twilitrealm.dusk' compileSdk 36 + ndkVersion androidNdkVersion() defaultConfig { applicationId 'dev.twilitrealm.dusk' @@ -44,16 +128,24 @@ android { sourceSets { main { - jniLibs.srcDirs = ['src/main/jniLibs'] + jniLibs.srcDirs = [stagedJniLibsDir] assets.srcDirs = [duskGeneratedAssetsDir] } } + packaging { + jniLibs { + if (stageStripValue.get() == '0') { + keepDebugSymbols += '**/libmain.so' + } + } + } + splits { abi { enable true reset() - include 'arm64-v8a', 'x86_64' + include 'arm64-v8a' universalApk false } } @@ -67,9 +159,6 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) } -tasks.configureEach { task -> - if ((task.name.startsWith('merge') && task.name.endsWith('Assets')) || - task.name.toLowerCase().contains('lint')) { - task.dependsOn(syncDuskAssets) - } +tasks.named('preBuild').configure { + dependsOn(stageJniLibs, syncDuskAssets) } diff --git a/platforms/android/scripts/stage-jni-libs.sh b/platforms/android/scripts/stage-jni-libs.sh deleted file mode 100755 index 3984cf03ee..0000000000 --- a/platforms/android/scripts/stage-jni-libs.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" -APP_DIR="$ROOT_DIR/platforms/android/app/src/main/jniLibs" -ANDROID_HOME_DIR="${ANDROID_HOME:-$HOME/Android/Sdk}" -ANDROID_NDK_VER="${ANDROID_NDK_VERSION:-}" -ANDROID_STAGE_ABIS="${ANDROID_STAGE_ABIS:-arm64-v8a x86_64}" -ANDROID_STAGE_STRIP="${ANDROID_STAGE_STRIP:-1}" -STRIP_TOOL="" - -if [[ -z "$ANDROID_NDK_VER" ]] && [[ -d "$ANDROID_HOME_DIR/ndk" ]]; then - ANDROID_NDK_VER="$(ls -1 "$ANDROID_HOME_DIR/ndk" | sort -V | tail -n 1)" -fi - -if [[ -n "$ANDROID_NDK_VER" ]]; then - case "$(uname -s)" in - Darwin) HOST_TAG="darwin-x86_64" ;; - Linux) HOST_TAG="linux-x86_64" ;; - *) HOST_TAG="" ;; - esac - - PREBUILT_DIR="$ANDROID_HOME_DIR/ndk/$ANDROID_NDK_VER/toolchains/llvm/prebuilt" - if [[ -n "$HOST_TAG" && -x "$PREBUILT_DIR/$HOST_TAG/bin/llvm-strip" ]]; then - STRIP_TOOL="$PREBUILT_DIR/$HOST_TAG/bin/llvm-strip" - else - for candidate in "$PREBUILT_DIR"/*/bin/llvm-strip; do - if [[ -x "$candidate" ]]; then - STRIP_TOOL="$candidate" - break - fi - done - fi -fi - -copy_lib() { - local abi="$1" - local src="$2" - local dst_dir="$APP_DIR/$abi" - local dst="$dst_dir/libmain.so" - local tmp="$dst_dir/.libmain.so.$$" - if [[ ! -f "$src" ]]; then - echo "Missing native library for $abi: $src" >&2 - exit 1 - fi - - mkdir -p "$dst_dir" - cp -f "$src" "$tmp" - if [[ "$ANDROID_STAGE_STRIP" != "0" ]] && [[ -n "$STRIP_TOOL" ]]; then - "$STRIP_TOOL" --strip-unneeded "$tmp" - mv -f "$tmp" "$dst" - echo "Stripped and staged $src -> $dst" - else - mv -f "$tmp" "$dst" - echo "Staged $src -> $dst (strip disabled or strip tool unavailable)" - fi -} - -# Drop any previously staged ABI directories to avoid stale APK contents. -rm -rf "$APP_DIR/x86" "$APP_DIR/arm64-v8a" "$APP_DIR/x86_64" - -for abi in $ANDROID_STAGE_ABIS; do - case "$abi" in - arm64-v8a) - src="$ROOT_DIR/build/android-arm64/libmain.so" - triple="aarch64-linux-android" - ;; - x86_64) - src="$ROOT_DIR/build/android-x86_64/libmain.so" - triple="x86_64-linux-android" - ;; - *) - echo "Unsupported ABI '$abi'. Supported ABIs: arm64-v8a x86_64" >&2 - exit 1 - ;; - esac - copy_lib "$abi" "$src" - if [[ -n "$STRIP_TOOL" ]]; then - stl="$(dirname "$STRIP_TOOL")/../sysroot/usr/lib/$triple/libc++_shared.so" - if [[ -f "$stl" ]]; then - cp -f "$stl" "$APP_DIR/$abi/libc++_shared.so" - echo "Staged $stl -> $APP_DIR/$abi/libc++_shared.so" - else - echo "Missing libc++_shared.so for $abi at $stl" >&2 - exit 1 - fi - else - echo "Cannot stage libc++_shared.so for $abi (NDK not found)" >&2 - exit 1 - fi -done - -# Stage bundled mod packages into the app's assets source dir. -MODS_STAGING_DIR="$ROOT_DIR/platforms/android/app/src/main/bundled_mods" -rm -rf "$MODS_STAGING_DIR" -mkdir -p "$MODS_STAGING_DIR" -for abi in $ANDROID_STAGE_ABIS; do - case "$abi" in - arm64-v8a) build_dir="$ROOT_DIR/build/android-arm64" ;; - x86_64) build_dir="$ROOT_DIR/build/android-x86_64" ;; - esac - [[ -d "$build_dir/bundled_mods" ]] || continue - for pkg in "$build_dir/bundled_mods"/*.dusk; do - [[ -f "$pkg" ]] || continue - name="$(basename "$pkg")" - if [[ ! -f "$MODS_STAGING_DIR/$name" ]]; then - cp -f "$pkg" "$MODS_STAGING_DIR/$name" - echo "Staged bundled mod $pkg" - else - stage_dir="$build_dir/mods/${name%.dusk}/${name%.dusk}_stage" - (cd "$stage_dir" && zip -q -r "$MODS_STAGING_DIR/$name" lib) - echo "Appended $abi libraries to bundled mod $name" - fi - done -done