diff --git a/.github/workflows/gradle-publish.yml b/.github/workflows/gradle-publish.yml index a593f92..b8458b3 100644 --- a/.github/workflows/gradle-publish.yml +++ b/.github/workflows/gradle-publish.yml @@ -16,7 +16,7 @@ jobs: publish: runs-on: ubuntu-latest permissions: - contents: read + contents: write packages: write steps: @@ -58,7 +58,7 @@ jobs: if [[ -z "$VERSION" ]]; then VERSION="$GITHUB_REF_NAME" fi - echo "version=${VERSION#v}" >> $GITHUB_OUTPUT + echo "version=${VERSION#v}" >> "$GITHUB_OUTPUT" - name: Generate Android bindings run: ./build_android.sh @@ -67,6 +67,18 @@ jobs: working-directory: bindings/android run: ./gradlew build -Pversion=${{ steps.version.outputs.version }} + - name: Upload native debug symbols artifact + uses: actions/upload-artifact@v4 + with: + name: bitkit-core-native-debug-symbols-${{ steps.version.outputs.version }} + path: bindings/android/native-debug-symbols.zip + + - name: Upload native debug symbols to release + if: github.event_name == 'release' + env: + GH_TOKEN: ${{ github.token }} + run: gh release upload "${{ github.event.release.tag_name }}" bindings/android/native-debug-symbols.zip --clobber + # same credentials env vars used in the publishing section of build.gradle.kts - name: Publish to GitHub Packages working-directory: bindings/android diff --git a/.gitignore b/.gitignore index 03ef30e..ceee4e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target/ +bindings/android/native-debug-symbols.zip .idea/ .DS_Store # AI diff --git a/Cargo.lock b/Cargo.lock index f9a8481..62d79b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -475,7 +475,7 @@ dependencies = [ [[package]] name = "bitkitcore" -version = "0.1.72" +version = "0.1.73" dependencies = [ "android_logger", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 329f60a..9502908 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bitkitcore" -version = "0.1.72" +version = "0.1.73" edition = "2021" [lib] diff --git a/Package.swift b/Package.swift index 8be7257..22c2bdd 100644 --- a/Package.swift +++ b/Package.swift @@ -3,7 +3,7 @@ import PackageDescription -let tag = "v0.1.72" +let tag = "v0.1.73" let checksum = "0fc1897b87ef3224abcec3b119d02c4a93966dd04c0a7c938588d4c5e98fc013" let url = "https://github.com/synonymdev/bitkit-core/releases/download/\(tag)/BitkitCore.xcframework.zip" diff --git a/bindings/android/README.md b/bindings/android/README.md index edd8b2d..d488daa 100644 --- a/bindings/android/README.md +++ b/bindings/android/README.md @@ -90,4 +90,4 @@ cd ./bindings/android ./gradlew publish -Pversion=0.1.0 ``` -Run `./build_android.sh` before any direct Gradle publish so `jniLibs` is regenerated with native debug metadata and 16 KB page-size alignment. +Run `./build_android.sh` before any direct Gradle publish so `jniLibs` is regenerated as stripped release libraries with separate `native-debug-symbols.zip` metadata and 16 KB page-size alignment. diff --git a/bindings/android/gradle.properties b/bindings/android/gradle.properties index 2b1cacb..65db0f1 100644 --- a/bindings/android/gradle.properties +++ b/bindings/android/gradle.properties @@ -3,4 +3,4 @@ android.useAndroidX=true android.enableJetifier=true kotlin.code.style=official group=com.synonym -version=0.1.72 +version=0.1.73 diff --git a/bindings/android/lib/build.gradle.kts b/bindings/android/lib/build.gradle.kts index a8409bf..d8c7d4c 100644 --- a/bindings/android/lib/build.gradle.kts +++ b/bindings/android/lib/build.gradle.kts @@ -42,12 +42,6 @@ android { } } - packaging { - jniLibs { - keepDebugSymbols += "**/libbitkitcore.so" - } - } - publishing { singleVariant("release") { withSourcesJar() @@ -121,7 +115,7 @@ fun String.parseElfAlignment(): Long { val validateReleaseNativeLibraries by tasks.registering { group = "verification" - description = "Validates release JNI libraries keep full DWARF metadata and 16 KB LOAD alignment." + description = "Validates release JNI libraries are stripped and keep 16 KB LOAD alignment." doLast { val readelf = findReadelf() @@ -134,8 +128,11 @@ val validateReleaseNativeLibraries by tasks.registering { } val (sectionsExit, sections) = runReadelf(readelf, "-S", lib.absolutePath) - if (sectionsExit != 0 || !Regex("""\.debug_info""").containsMatchIn(sections)) { - throw GradleException("Android native library has no .debug_info DWARF metadata: '${lib.path}'") + if (sectionsExit != 0) { + throw GradleException("Unable to inspect Android native library sections: '${lib.path}'") + } + if (Regex("""\.debug_""").containsMatchIn(sections)) { + throw GradleException("Android release native library still contains .debug_* sections: '${lib.path}'") } val wideHeaders = runReadelf(readelf, "-W", "-l", lib.absolutePath) @@ -175,6 +172,10 @@ afterEvaluate { version = providers.gradleProperty("version").orNull ?: "0.0.0" from(components["release"]) + artifact(rootProject.layout.projectDirectory.file("native-debug-symbols.zip")) { + classifier = "native-debug-symbols" + extension = "zip" + } pom { name.set(mavenArtifactId) description.set("Bitkit Core Android bindings.") diff --git a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so index 686c715..7e8982e 100755 Binary files a/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/arm64-v8a/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so index 5f7f951..f398fcc 100755 Binary files a/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/armeabi-v7a/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so index a8605b5..32f9fee 100755 Binary files a/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/x86/libbitkitcore.so differ diff --git a/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so index f42479b..02c4522 100755 Binary files a/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so and b/bindings/android/lib/src/main/jniLibs/x86_64/libbitkitcore.so differ diff --git a/build_android.sh b/build_android.sh index 0de4d79..dd6da6b 100755 --- a/build_android.sh +++ b/build_android.sh @@ -69,6 +69,7 @@ export CARGO_PROFILE_RELEASE_STRIP=false ANDROID_LIB_DIR="./bindings/android" BASE_DIR="$ANDROID_LIB_DIR/lib/src/main/kotlin/com/synonym/bitkitcore" JNILIBS_DIR="$ANDROID_LIB_DIR/lib/src/main/jniLibs" +NATIVE_DEBUG_SYMBOLS_ZIP="$ANDROID_LIB_DIR/native-debug-symbols.zip" # Create output directories mkdir -p "$BASE_DIR" @@ -101,10 +102,36 @@ find_readelf() { exit 1 } +find_strip() { + if command -v llvm-strip >/dev/null 2>&1; then + command -v llvm-strip + return + fi + + for ndk_dir in "${ANDROID_NDK_ROOT:-}" "${ANDROID_NDK_HOME:-}" "${NDK_HOME:-}"; do + if [ -z "$ndk_dir" ] || [ ! -d "$ndk_dir/toolchains/llvm/prebuilt" ]; then + continue + fi + + ndk_strip=$(find "$ndk_dir/toolchains/llvm/prebuilt" -path '*/bin/llvm-strip' | head -n 1) + if [ -n "$ndk_strip" ]; then + echo "$ndk_strip" + return + fi + done + + echo "Error: llvm-strip is required to strip Android native release libraries" + exit 1 +} + has_dwarf_debug_metadata() { "$READELF_BIN" -S "$1" | grep -Eq '\.debug_info' } +has_dwarf_sections() { + "$READELF_BIN" -S "$1" | grep -Eq '\.debug_' +} + readelf_program_headers() { if "$READELF_BIN" -W -l "$1" >/dev/null 2>&1; then "$READELF_BIN" -W -l "$1" @@ -147,6 +174,20 @@ validate_android_library() { fi } +validate_stripped_android_library() { + lib="$1" + if has_dwarf_sections "$lib"; then + echo "Error: Android release native library still contains .debug_* sections: $lib" + exit 1 + fi + + if ! has_16kb_load_alignment "$lib"; then + echo "Error: Android native library is not 16 KB page-size aligned: $lib" + readelf_program_headers "$lib" | grep LOAD || true + exit 1 + fi +} + validate_android_symbols() { READELF_BIN=$(find_readelf) @@ -161,6 +202,40 @@ validate_android_symbols() { done } +create_native_debug_symbols_archive() { + tmp_dir=$(mktemp -d) + + for abi in armeabi-v7a arm64-v8a x86 x86_64; do + mkdir -p "$tmp_dir/$abi" + cp "$JNILIBS_DIR/$abi/libbitkitcore.so" "$tmp_dir/$abi/" + done + + rm -f "$NATIVE_DEBUG_SYMBOLS_ZIP" + archive_path="$PWD/$NATIVE_DEBUG_SYMBOLS_ZIP" + ( + cd "$tmp_dir" + zip -qr "$archive_path" armeabi-v7a arm64-v8a x86 x86_64 + ) + zip -T "$NATIVE_DEBUG_SYMBOLS_ZIP" >/dev/null + rm -rf "$tmp_dir" +} + +strip_android_libraries() { + STRIP_BIN=$(find_strip) + + for abi in armeabi-v7a arm64-v8a x86 x86_64; do + "$STRIP_BIN" --strip-unneeded "$JNILIBS_DIR/$abi/libbitkitcore.so" + done +} + +validate_stripped_android_symbols() { + READELF_BIN=$(find_readelf) + + for abi in armeabi-v7a arm64-v8a x86 x86_64; do + validate_stripped_android_library "$JNILIBS_DIR/$abi/libbitkitcore.so" + done +} + validate_android_aar_symbols() { READELF_BIN=$(find_readelf) aar=$(find "$ANDROID_LIB_DIR" -path '*/build/outputs/aar/*release.aar' -print | head -n 1) @@ -180,7 +255,7 @@ validate_android_aar_symbols() { exit 1 fi - validate_android_library "$lib" + validate_stripped_android_library "$lib" done rm -rf "$tmp_dir" @@ -247,6 +322,9 @@ cargo ndk \ build --release validate_android_symbols +create_native_debug_symbols_archive +strip_android_libraries +validate_stripped_android_symbols # Generate Kotlin bindings echo "Generating Kotlin bindings..."