#!/bin/bash set -euo pipefail # Builds shadowhook as a static library for Android arm64. # Produces: libs/libshadowhook.a and libs/libshadowhook_nothing.so SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" BUILD_DIR="$PROJECT_DIR/build/deps" mkdir -p "$BUILD_DIR" # --- Auto-detect Android NDK (same logic as build.sh) --- find_ndk() { if [ -n "${ANDROID_NDK_HOME:-}" ] && [ -d "$ANDROID_NDK_HOME" ]; then echo "$ANDROID_NDK_HOME"; return fi local brew_ndk brew_ndk=$(find /opt/homebrew /usr/local -path "*/android-ndk/*/toolchains/llvm/prebuilt" -type d 2>/dev/null | head -1) if [ -n "$brew_ndk" ]; then echo "$(dirname "$(dirname "$(dirname "$brew_ndk")")")"; return fi local sdk_ndk sdk_ndk=$(find "$HOME/Library/Android/sdk/ndk" -maxdepth 1 -type d 2>/dev/null | sort -V | tail -1) if [ -n "$sdk_ndk" ] && [ -d "$sdk_ndk" ]; then echo "$sdk_ndk"; return fi for p in /opt/android-ndk /usr/local/android-ndk "$HOME/android-ndk"; do if [ -d "$p" ]; then echo "$p"; return; fi done echo "" } NDK_HOME="$(find_ndk)" API_LEVEL="${ANDROID_API_LEVEL:-21}" CC="" if [ -n "$NDK_HOME" ]; then CC=$(find "$NDK_HOME/toolchains/llvm/prebuilt" -type f \ -name "aarch64-linux-android${API_LEVEL}-clang" -print -quit 2>/dev/null) fi if [ -z "$CC" ]; then echo "ERROR: aarch64-linux-android clang not found." echo " Set ANDROID_NDK_HOME to your NDK path." exit 1 fi TOOLCHAIN_DIR="$(dirname "$CC")" AR="$TOOLCHAIN_DIR/llvm-ar" CFLAGS="-O2 -ffunction-sections -fdata-sections -fPIC -DANDROID -Wall -Wextra -Wno-unused-parameter -Wno-unused-function" OUT_DIR="$SCRIPT_DIR" echo "=== Building shadowhook (arm64-v8a) ===" SH="$SCRIPT_DIR/shadowhook/shadowhook/src/main/cpp" SH_SRCS=" $SH/sh_elf.c $SH/sh_enter.c $SH/sh_hub.c $SH/sh_island.c $SH/sh_linker.c $SH/sh_recorder.c $SH/sh_safe.c $SH/sh_switch.c $SH/sh_task.c $SH/sh_xdl.c $SH/shadowhook.c $SH/arch/arm64/sh_a64.c $SH/arch/arm64/sh_inst.c $SH/arch/arm64/sh_glue.S $SH/common/bytesig.c $SH/common/sh_errno.c $SH/common/sh_log.c $SH/common/sh_ref.c $SH/common/sh_trampo.c $SH/common/sh_util.c $SH/third_party/xdl/xdl.c $SH/third_party/xdl/xdl_iterate.c $SH/third_party/xdl/xdl_linker.c $SH/third_party/xdl/xdl_lzma.c $SH/third_party/xdl/xdl_util.c " SH_INCLUDES=" -I$SH -I$SH/include -I$SH/arch/arm64 -I$SH/common -I$SH/third_party/xdl -I$SH/third_party/bsd -I$SH/third_party/lss " SH_OBJS="" for src in $SH_SRCS; do [ -z "$src" ] && continue src=$(echo "$src" | xargs) if [ ! -f "$src" ]; then echo "ERROR: shadowhook source not found: $src" exit 1 fi basename=$(echo "$src" | sed "s|$SH/||" | tr '/' '_') obj="$BUILD_DIR/sh_${basename%.c}.o" obj="${obj%.S.o}.o" if [[ "$src" == *.S ]]; then "$CC" $CFLAGS $SH_INCLUDES -c "$src" -o "$obj" else "$CC" $CFLAGS $SH_INCLUDES -c "$src" -o "$obj" fi SH_OBJS="$SH_OBJS $obj" done if [ -z "$SH_OBJS" ]; then echo "ERROR: shadowhook produced no object files." exit 1 fi "$AR" rcs "$OUT_DIR/libshadowhook.a" $SH_OBJS SH_SIZE=$(wc -c < "$OUT_DIR/libshadowhook.a" 2>/dev/null || echo "unknown") echo " Built $OUT_DIR/libshadowhook.a ($SH_SIZE bytes)" NOTHING_SRC="$SH/nothing/sh_nothing.c" if [ ! -f "$NOTHING_SRC" ]; then echo "ERROR: ShadowHook companion source not found: $NOTHING_SRC" exit 1 fi "$CC" -shared -Oz -fPIC -fno-ident -fno-unwind-tables -fno-asynchronous-unwind-tables \ -nostdlib -nostartfiles -nodefaultlibs \ -Wl,-z,max-page-size=16384 \ -Wl,--strip-all -Wl,--as-needed -Wl,--hash-style=sysv \ -Wl,--build-id=none \ -o "$OUT_DIR/libshadowhook_nothing.so" "$NOTHING_SRC" echo " Built $OUT_DIR/libshadowhook_nothing.so"