Merge pull request #108 from anestisb/android-deps-cc-automation
[Android] Improve deps compilation automation & error handling
diff --git a/Makefile b/Makefile
index b6123d8..f9fc5f0 100644
--- a/Makefile
+++ b/Makefile
@@ -76,8 +76,8 @@
# Figure out which crash reporter to use.
CRASHWRANGLER := third_party/mac
OS_VERSION := $(shell sw_vers -productVersion)
- ifneq (,$(findstring 10.12,$(OS_VERSION)))
- CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Yosemite.o
+ ifneq (,$(findstring 10.12,$(OS_VERSION)))
+ CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Yosemite.o
else ifneq (,$(findstring 10.11,$(OS_VERSION)))
# El Capitan didn't break compatibility
CRASH_REPORT := $(CRASHWRANGLER)/CrashReport_Yosemite.o
@@ -176,24 +176,32 @@
# clang works only against APIs >= 23
ifeq ($(ANDROID_APP_ABI),$(filter $(ANDROID_APP_ABI),armeabi armeabi-v7a))
ANDROID_NDK_TOOLCHAIN ?= arm-linux-androideabi-clang
+ ANDROID_ARCH_CPU := arm
else ifeq ($(ANDROID_APP_ABI),$(filter $(ANDROID_APP_ABI),x86))
ANDROID_NDK_TOOLCHAIN ?= x86-clang
+ ANDROID_ARCH_CPU := x86
else ifeq ($(ANDROID_APP_ABI),$(filter $(ANDROID_APP_ABI),arm64-v8a))
ANDROID_NDK_TOOLCHAIN ?= aarch64-linux-android-clang
+ ANDROID_ARCH_CPU := arm64
else ifeq ($(ANDROID_APP_ABI),$(filter $(ANDROID_APP_ABI),x86_64))
ANDROID_NDK_TOOLCHAIN ?= x86_64-clang
+ ANDROID_ARCH_CPU := x86_64
else
$(error Unsuported / Unknown APP_API '$(ANDROID_APP_ABI)')
endif
else
ifeq ($(ANDROID_APP_ABI),$(filter $(ANDROID_APP_ABI),armeabi armeabi-v7a))
ANDROID_NDK_TOOLCHAIN ?= arm-linux-androideabi-4.9
+ ANDROID_ARCH_CPU := arm
else ifeq ($(ANDROID_APP_ABI),$(filter $(ANDROID_APP_ABI),x86))
ANDROID_NDK_TOOLCHAIN ?= x86-4.9
+ ANDROID_ARCH_CPU := x86
else ifeq ($(ANDROID_APP_ABI),$(filter $(ANDROID_APP_ABI),arm64-v8a))
ANDROID_NDK_TOOLCHAIN ?= aarch64-linux-android-4.9
+ ANDROID_ARCH_CPU := arm64
else ifeq ($(ANDROID_APP_ABI),$(filter $(ANDROID_APP_ABI),x86_64))
ANDROID_NDK_TOOLCHAIN ?= x86_64-4.9
+ ANDROID_ARCH_CPU := x86_64
else
$(error Unsuported / Unknown APP_API '$(ANDROID_APP_ABI)')
endif
@@ -240,6 +248,17 @@
.PHONY: android
android:
+ @ANDROID_API=$(ANDROID_API) third_party/android/scripts/compile-libunwind.sh \
+ third_party/android/libunwind $(ANDROID_ARCH_CPU)
+
+ @ANDROID_API=$(ANDROID_API) third_party/android/scripts/compile-capstone.sh \
+ third_party/android/capstone $(ANDROID_ARCH_CPU)
+
+ ifeq ($(ANDROID_CLANG),true)
+ @ANDROID_API=$(ANDROID_API) third_party/android/scripts/compile-libBlocksRuntime.sh \
+ third_party/android/libBlocksRuntime $(ANDROID_ARCH_CPU)
+ endif
+
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./android/Android.mk \
APP_PLATFORM=$(ANDROID_API) APP_ABI=$(ANDROID_APP_ABI) \
NDK_TOOLCHAIN=$(ANDROID_NDK_TOOLCHAIN) $(NDK_BUILD_ARGS)
@@ -259,6 +278,18 @@
echo ""; \
done
+.PHONY: android-clean-deps
+android-clean-deps:
+ @for cpu in arm arm64 x86 x86_64; do \
+ make -C "third_party/android/capstone" clean; \
+ rm -rf "third_party/android/capstone/$$cpu"; \
+ make -C "third_party/android/libunwind" clean; \
+ rm -rf "third_party/android/libunwind/$$cpu"; \
+ ndk-build -C "third_party/android/libBlocksRuntime" \
+ NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk clean; \
+ rm -rf "third_party/android/libBlocksRuntime/$$cpu"; \
+ done
+
# DO NOT DELETE
cmdline.o: cmdline.h common.h log.h files.h util.h
diff --git a/android/Android.mk b/android/Android.mk
index 41f924a..492d295 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -15,22 +15,36 @@
LOCAL_PATH := $(abspath $(call my-dir)/..)
+# Force a clean if target API has changed and a previous build exists
+ifneq ("$(wildcard $(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/android_api.txt)","")
+ CACHED_API := $(shell cat "$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/android_api.txt")
+ ifneq ($(ANDROID_API),$(CACHED_API))
+ $(info [!] Previous build was targeting different API level - cleaning)
+ DUMMY_CLEAN := $(shell make clean)
+ endif
+endif
+
+# Force a clean if selected toolchain has changed and a previous build exists
+ifneq ("$(wildcard $(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/ndk_toolchain.txt)","")
+ CACHED_TOOLCHAIN := $(shell cat "$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/ndk_toolchain.txt")
+ ifneq ($(NDK_TOOLCHAIN),$(CACHED_TOOLCHAIN))
+ $(info [!] Previous build was using different toolchain - cleaning)
+ DUMMY_CLEAN := $(shell make clean)
+ endif
+endif
+
# Enable Linux ptrace() instead of POSIX signal interface by default
ANDROID_WITH_PTRACE ?= true
ifeq ($(ANDROID_WITH_PTRACE),true)
ifeq ($(APP_ABI),$(filter $(APP_ABI),armeabi armeabi-v7a))
ARCH_ABI := arm
- UNW_ARCH := arm
else ifeq ($(APP_ABI),$(filter $(APP_ABI),x86))
ARCH_ABI := x86
- UNW_ARCH := x86
else ifeq ($(APP_ABI),$(filter $(APP_ABI),arm64-v8a))
ARCH_ABI := arm64
- UNW_ARCH := aarch64
else ifeq ($(APP_ABI),$(filter $(APP_ABI),x86_64))
ARCH_ABI := x86_64
- UNW_ARCH := x86_64
else
$(error Unsuported / Unknown APP_API '$(APP_ABI)')
endif
@@ -43,9 +57,9 @@
endif
# Upstream libunwind compiled from sources with Android NDK toolchain
- LIBUNWIND_A := third_party/android/libunwind/$(ARCH_ABI)/libunwind-$(UNW_ARCH).a
+ LIBUNWIND_A := third_party/android/libunwind/$(ARCH_ABI)/libunwind-$(ARCH_ABI).a
ifeq ("$(wildcard $(LIBUNWIND_A))","")
- $(error libunwind-$(UNW_ARCH) is missing - to build execute \
+ $(error libunwind-$(ARCH_ABI) is missing - to build execute \
'third_party/android/scripts/compile-libunwind.sh third_party/android/libunwind $(ARCH_ABI)')
endif
@@ -57,7 +71,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE := libunwind-arch
- LOCAL_SRC_FILES := third_party/android/libunwind/$(ARCH_ABI)/libunwind-$(UNW_ARCH).a
+ LOCAL_SRC_FILES := third_party/android/libunwind/$(ARCH_ABI)/libunwind-$(ARCH_ABI).a
LOCAL_EXPORT_C_INCLUDES := third_party/android/libunwind/include
include $(PREBUILT_STATIC_LIBRARY)
@@ -165,9 +179,13 @@
include $(BUILD_EXECUTABLE)
# The NDK build system does not copy static libraries into project/packages
-# so it has to be done manually in order to have all output under a single path
+# so it has to be done manually in order to have all output under a single path.
+# Also save some build attribute cache files so that cleans can be enforced when
+# required.
all:POST_BUILD_EVENT
POST_BUILD_EVENT:
+ @echo $(ANDROID_API) > $(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/android_api.txt
+ @echo $(NDK_TOOLCHAIN) > $(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/ndk_toolchain.txt
@test -f $(LOCAL_PATH)/obj/local/$(TARGET_ARCH_ABI)/libhfuzz.a && \
cp $(LOCAL_PATH)/obj/local/$(TARGET_ARCH_ABI)/libhfuzz.a \
$(LOCAL_PATH)/libs/$(TARGET_ARCH_ABI)/libhfuzz.a || true
diff --git a/third_party/android/scripts/compile-capstone.sh b/third_party/android/scripts/compile-capstone.sh
index 452f973..efc831f 100755
--- a/third_party/android/scripts/compile-capstone.sh
+++ b/third_party/android/scripts/compile-capstone.sh
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+#set -x # debug
+
abort() {
cd - &>/dev/null
exit "$1"
@@ -29,7 +31,7 @@
exit 1
fi
-readonly CAPSTONE_DIR=$1
+readonly CAPSTONE_DIR="$1"
if [ ! -d "$CAPSTONE_DIR/.git" ]; then
git submodule update --init third_party/android/capstone || {
@@ -63,7 +65,7 @@
NDK=$(dirname $(which ndk-build))
else
echo "[-] Could not detect Android NDK dir"
- exit 1
+ abort 1
fi
fi
@@ -74,10 +76,22 @@
;;
*)
echo "[-] Invalid CPU architecture"
- exit 1
+ abort 1
;;
esac
+# Check if previous build exists and matches selected ANDROID_API level
+# If API cache file not there always rebuild
+if [ -f "$ARCH/libcapstone.a" ]; then
+ if [ -f "$ARCH/android_api.txt" ]; then
+ old_api=$(cat "$ARCH/android_api.txt")
+ if [[ "$old_api" == "$ANDROID_API" ]]; then
+ # No need to recompile
+ abort 0
+ fi
+ fi
+fi
+
case "$ARCH" in
arm)
CS_ARCH="arm"
@@ -113,15 +127,23 @@
$NDK=$(dirname $(which ndk-build))
else
echo "[-] Could not detect Android NDK dir"
- exit 1
+ abort 1
fi
fi
+if [ -z "$ANDROID_API" ]; then
+ ANDROID_API="android-21"
+fi
+if ! echo "$ANDROID_API" | grep -qoE 'android-[0-9]{1,2}'; then
+ echo "[-] Invalid ANDROID_API '$ANDROID_API'"
+ abort 1
+fi
+
# Support both Linux & Darwin
HOST_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
HOST_ARCH=$(uname -m)
-SYSROOT="$NDK/platforms/android-21/arch-$ARCH"
+SYSROOT="$NDK/platforms/$ANDROID_API/arch-$ARCH"
export CC="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-gcc --sysroot=$SYSROOT"
export CXX="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-g++ --sysroot=$SYSROOT"
export PATH="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin":$PATH
@@ -137,11 +159,12 @@
eval $CS_BUILD_BIN
if [ $? -ne 0 ]; then
echo "[-] Compilation failed"
- exit 1
+ abort 1
else
echo "[*] '$ARCH' libcapstone available at '$CAPSTONE_DIR/$ARCH'"
fi
-cp libcapstone.a $ARCH/
+cp libcapstone.a "$ARCH/"
+echo "$ANDROID_API" > "$ARCH/android_api.txt"
abort 0
diff --git a/third_party/android/scripts/compile-libBlocksRuntime.sh b/third_party/android/scripts/compile-libBlocksRuntime.sh
index f854fb5..870f84b 100755
--- a/third_party/android/scripts/compile-libBlocksRuntime.sh
+++ b/third_party/android/scripts/compile-libBlocksRuntime.sh
@@ -15,8 +15,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-readonly ANDROID_API="android-23"
-
if [ -z "$NDK" ]; then
# Search in $PATH
if [[ $(which ndk-build) != "" ]]; then
@@ -27,6 +25,14 @@
fi
fi
+if [ -z "$ANDROID_API" ]; then
+ ANDROID_API="android-23"
+fi
+if ! echo "$ANDROID_API" | grep -qoE 'android-[0-9]{1,2}'; then
+ echo "[-] Invalid ANDROID_API '$ANDROID_API'"
+ exit 1
+fi
+
if [ $# -ne 2 ]; then
echo "[-] Invalid arguments"
echo "[!] $0 <libBlocksRuntime_DIR> <ARCH>"
@@ -34,7 +40,7 @@
exit 1
fi
-readonly BRT_DIR=$1
+readonly BRT_DIR="$1"
case "$2" in
arm|arm64|x86|x86_64)
@@ -47,6 +53,18 @@
;;
esac
+# Check if previous build exists and matches selected ANDROID_API level
+# If API cache file not there always rebuild
+if [ -f "$BRT_DIR/$ARCH/libblocksruntime.a" ]; then
+ if [ -f "$BRT_DIR/$ARCH/android_api.txt" ]; then
+ old_api=$(cat "$BRT_DIR/$ARCH/android_api.txt")
+ if [[ "$old_api" == "$ANDROID_API" ]]; then
+ # No need to recompile
+ exit 0
+ fi
+ fi
+fi
+
case "$ARCH" in
arm)
BRT_ARCH="armeabi-v7a"
@@ -85,7 +103,8 @@
# Change workdir to simplify args
cd $BRT_DIR
-cp obj/local/$BRT_ARCH/libblocksruntime.a $ARCH/
+cp obj/local/$BRT_ARCH/libblocksruntime.a "$ARCH/"
+echo "$ANDROID_API" > "$ARCH/android_api.txt"
# Revert workdir to caller
cd - &>/dev/null
diff --git a/third_party/android/scripts/compile-libunwind.sh b/third_party/android/scripts/compile-libunwind.sh
index 0a81ce9..4d6980f 100755
--- a/third_party/android/scripts/compile-libunwind.sh
+++ b/third_party/android/scripts/compile-libunwind.sh
@@ -23,7 +23,7 @@
echo "[!] git patches are not reverted since running under debug mode"
else
# Extra care to ensure we're under expected project
- if [[ "$(basename $(git rev-parse --show-toplevel))" == "libunwind" ]]; then
+ if [[ $# -eq 1 && "$(basename $(git rev-parse --show-toplevel))" == "libunwind" ]]; then
echo "[*] Resetting locally applied patches"
git reset --hard &>/dev/null || {
echo "[-] git reset failed"
@@ -44,7 +44,6 @@
exit 1
fi
-# Change workspace
readonly LIBUNWIND_DIR="$1"
if [ ! -d "$LIBUNWIND_DIR/.git" ]; then
@@ -83,6 +82,14 @@
fi
fi
+if [ -z "$ANDROID_API" ]; then
+ ANDROID_API="android-21"
+fi
+if ! echo "$ANDROID_API" | grep -qoE 'android-[0-9]{1,2}'; then
+ echo "[-] Invalid ANDROID_API '$ANDROID_API'"
+ abort 1
+fi
+
case "$2" in
arm|arm64|x86|x86_64)
readonly ARCH="$2"
@@ -94,6 +101,18 @@
;;
esac
+# Check if previous build exists and matches selected ANDROID_API level
+# If API cache file not there always rebuild
+if [ -f "$ARCH/libunwind-$ARCH.a" ]; then
+ if [ -f "$ARCH/android_api.txt" ]; then
+ old_api=$(cat "$ARCH/android_api.txt")
+ if [[ "$old_api" == "$ANDROID_API" ]]; then
+ # No need to recompile
+ abort 0 true
+ fi
+ fi
+fi
+
LC_LDFLAGS="-static"
# For debugging
@@ -180,7 +199,7 @@
HOST_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
HOST_ARCH=$(uname -m)
-SYSROOT="$NDK/platforms/android-21/arch-$ARCH"
+SYSROOT="$NDK/platforms/$ANDROID_API/arch-$ARCH"
export CC="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-gcc --sysroot=$SYSROOT"
export CXX="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin/$TOOLCHAIN-g++ --sysroot=$SYSROOT"
export PATH="$NDK/toolchains/$TOOLCHAIN_S/prebuilt/$HOST_OS-$HOST_ARCH/bin":$PATH
@@ -218,6 +237,19 @@
fi
echo "[*] '$ARCH' libunwind available at '$LIBUNWIND_DIR/$ARCH'"
-cp src/.libs/*.a $ARCH
+cp src/.libs/*.a "$ARCH"
+echo "$ANDROID_API" > "$ARCH/android_api.txt"
+
+# Naming conventions for arm64
+if [[ "$ARCH" == "arm64" ]]; then
+ cd "$ARCH"
+ find . -type f -name "*aarch64*.a" | while read -r libFile
+ do
+ fName=$(basename "$libFile")
+ newFName=$(echo "$fName" | sed "s#aarch64#arm64#")
+ ln -sf "$fName" "$newFName"
+ done
+ cd -
+fi
abort 0