From 5a25ec41dc6678290df328821d822dedde28afe7 Mon Sep 17 00:00:00 2001 From: BuShe Pie Date: Mon, 12 Sep 2022 16:10:29 +0800 Subject: [PATCH] build: rewritten the Android build system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completely rewritten the Android build system using Python Co-Authored-By: 东灯 <43312495+Lampese@users.noreply.github.com> Co-Authored-By: Feng Yu PR-URL: https://github.com/nodejs/node/pull/44207 Refs: https://github.com/nodejs/node/issues/36287 Reviewed-By: Feng Yu Reviewed-By: Christian Clauss --- android-configure | 118 ++++++++------------------- android-patches/trap-handler.h.patch | 26 ++++++ android_configure.py | 76 +++++++++++++++++ 3 files changed, 137 insertions(+), 83 deletions(-) create mode 100644 android-patches/trap-handler.h.patch create mode 100644 android_configure.py diff --git a/android-configure b/android-configure index 6200f35200c774..8bab2e0b90c000 100755 --- a/android-configure +++ b/android-configure @@ -1,83 +1,35 @@ -#!/bin/bash - -# In order to cross-compile node for Android using NDK, run: -# source android-configure [arch] -# -# By running android-configure with source, will allow environment variables to -# be persistent in current session. This is useful for installing native node -# modules with npm. Also, don't forget to set the arch in npm config using -# 'npm config set arch=' - -if [ $# -ne 3 ]; then - echo "$0 should have 3 parameters: ndk_path, target_arch and sdk_version" - return 1 -fi - -NDK_PATH=$1 -ARCH="$2" -ANDROID_SDK_VERSION=$3 - -if [ $ANDROID_SDK_VERSION -lt 24 ]; then - echo "$ANDROID_SDK_VERSION should equal or later than 24 (Android 7.0)" -fi - -case $ARCH in - arm) - DEST_CPU="arm" - TOOLCHAIN_NAME="armv7a-linux-androideabi" - ;; - x86) - DEST_CPU="ia32" - TOOLCHAIN_NAME="i686-linux-android" - ;; - x86_64) - DEST_CPU="x64" - TOOLCHAIN_NAME="x86_64-linux-android" - ARCH="x64" - ;; - arm64|aarch64) - DEST_CPU="arm64" - TOOLCHAIN_NAME="aarch64-linux-android" - ARCH="arm64" - ;; - *) - echo "Unsupported architecture provided: $ARCH" - return 1 - ;; -esac - -HOST_OS="linux" -HOST_ARCH="x86_64" -export CC_host=$(command -v gcc) -export CXX_host=$(command -v g++) - -host_gcc_version=$($CC_host --version | grep gcc | awk '{print $NF}') -major=$(echo $host_gcc_version | awk -F . '{print $1}') -minor=$(echo $host_gcc_version | awk -F . '{print $2}') -if [ -z $major ] || [ -z $minor ] || [ $major -lt 6 ] || ( [ $major -eq 6 ] && [ $minor -lt 3 ] ); then - echo "host gcc $host_gcc_version is too old, need gcc 6.3.0" - return 1 -fi - -SUFFIX="$TOOLCHAIN_NAME$ANDROID_SDK_VERSION" -TOOLCHAIN=$NDK_PATH/toolchains/llvm/prebuilt/$HOST_OS-$HOST_ARCH - -export PATH=$TOOLCHAIN/bin:$PATH -export CC=$TOOLCHAIN/bin/$SUFFIX-clang -export CXX=$TOOLCHAIN/bin/$SUFFIX-clang++ - - -GYP_DEFINES="target_arch=$ARCH" -GYP_DEFINES+=" v8_target_arch=$ARCH" -GYP_DEFINES+=" android_target_arch=$ARCH" -GYP_DEFINES+=" host_os=$HOST_OS OS=android" -export GYP_DEFINES - -if [ -f "configure" ]; then - ./configure \ - --dest-cpu=$DEST_CPU \ - --dest-os=android \ - --without-snapshot \ - --openssl-no-asm \ - --cross-compiling -fi +#!/bin/sh + +# Locate an acceptable Python interpreter and then re-execute the script. +# Note that the mix of single and double quotes is intentional, +# as is the fact that the ] goes on a new line. +_=[ 'exec' '/bin/sh' '-c' ''' +command -v python3.10 >/dev/null && exec python3.10 "$0" "$@" +command -v python3.9 >/dev/null && exec python3.9 "$0" "$@" +command -v python3.8 >/dev/null && exec python3.8 "$0" "$@" +command -v python3.7 >/dev/null && exec python3.7 "$0" "$@" +command -v python3.6 >/dev/null && exec python3.6 "$0" "$@" +command -v python3 >/dev/null && exec python3 "$0" "$@" +exec python "$0" "$@" +''' "$0" "$@" +] +del _ + +import sys +try: + from shutil import which +except ImportError: + from distutils.spawn import find_executable as which + +print('Node.js android configure: Found Python {}.{}.{}...'.format(*sys.version_info)) +acceptable_pythons = ((3, 10), (3, 9), (3, 8), (3, 7), (3, 6)) +if sys.version_info[:2] in acceptable_pythons: + import android_configure +else: + python_cmds = ['python{}.{}'.format(*vers) for vers in acceptable_pythons] + sys.stderr.write('Please use {}.\n'.format(' or '.join(python_cmds))) + for python_cmd in python_cmds: + python_cmd_path = which(python_cmd) + if python_cmd_path and 'pyenv/shims' not in python_cmd_path: + sys.stderr.write('\t{} {}\n'.format(python_cmd_path, ' '.join(sys.argv[:1]))) + sys.exit(1) diff --git a/android-patches/trap-handler.h.patch b/android-patches/trap-handler.h.patch new file mode 100644 index 00000000000000..f4f151f65261f1 --- /dev/null +++ b/android-patches/trap-handler.h.patch @@ -0,0 +1,26 @@ +--- trap-handler.h 2022-08-11 09:01:23.384000000 +0800 ++++ fixed-trap-handler.h 2022-08-11 09:09:15.352000000 +0800 +@@ -17,23 +17,7 @@ + namespace internal { + namespace trap_handler { + +-// X64 on Linux, Windows, MacOS, FreeBSD. +-#if V8_HOST_ARCH_X64 && V8_TARGET_ARCH_X64 && \ +- ((V8_OS_LINUX && !V8_OS_ANDROID) || V8_OS_WIN || V8_OS_DARWIN || \ +- V8_OS_FREEBSD) +-#define V8_TRAP_HANDLER_SUPPORTED true +-// Arm64 (non-simulator) on Mac. +-#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_ARM64 && V8_OS_DARWIN +-#define V8_TRAP_HANDLER_SUPPORTED true +-// Arm64 simulator on x64 on Linux, Mac, or Windows. +-#elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_X64 && \ +- (V8_OS_LINUX || V8_OS_DARWIN) +-#define V8_TRAP_HANDLER_VIA_SIMULATOR +-#define V8_TRAP_HANDLER_SUPPORTED true +-// Everything else is unsupported. +-#else + #define V8_TRAP_HANDLER_SUPPORTED false +-#endif + + // Setup for shared library export. + #if defined(BUILDING_V8_SHARED) && defined(V8_OS_WIN) \ No newline at end of file diff --git a/android_configure.py b/android_configure.py new file mode 100644 index 00000000000000..57d940239150df --- /dev/null +++ b/android_configure.py @@ -0,0 +1,76 @@ +import platform +import sys +import os + +# TODO: In next version, it will be a JSON file listing all the patches, and then it will iterate through to apply them. +def patch_android(): + print("- Patches List -") + print("[1] [deps/v8/src/trap-handler/trap-handler.h] related to https://github.com/nodejs/node/issues/36287") + if platform.system() == "Linux": + os.system('patch -f ./deps/v8/src/trap-handler/trap-handler.h < ./android-patches/trap-handler.h.patch') + print("\033[92mInfo: \033[0m" + "Tried to patch.") + +if platform.system() == "Windows": + print("android-configure is not supported on Windows yet.") + sys.exit(1) + +if len(sys.argv) == 2 and sys.argv[1] == "patch": + patch_android() + sys.exit(0) + +if len(sys.argv) != 4: + print("Usage: ./android-configure [patch] ") + sys.exit(1) + +if not os.path.exists(sys.argv[1]) or not os.listdir(sys.argv[1]): + print("\033[91mError: \033[0m" + "Invalid path to the Android NDK") + sys.exit(1) + +if int(sys.argv[2]) < 24: + print("\033[91mError: \033[0m" + "Android SDK version must be at least 24 (Android 7.0)") + sys.exit(1) + +android_ndk_path = sys.argv[1] +android_sdk_version = sys.argv[2] +arch = sys.argv[3] + +if arch == "arm": + DEST_CPU = "arm" + TOOLCHAIN_PREFIX = "armv7a-linux-androideabi" +elif arch in ("aarch64", "arm64"): + DEST_CPU = "arm64" + TOOLCHAIN_PREFIX = "aarch64-linux-android" + arch = "arm64" +elif arch == "x86": + DEST_CPU = "ia32" + TOOLCHAIN_PREFIX = "i686-linux-android" +elif arch == "x86_64": + DEST_CPU = "x64" + TOOLCHAIN_PREFIX = "x86_64-linux-android" + arch = "x64" +else: + print("\033[91mError: \033[0m" + "Invalid target architecture, must be one of: arm, arm64, aarch64, x86, x86_64") + sys.exit(1) + +print("\033[92mInfo: \033[0m" + "Configuring for " + DEST_CPU + "...") + +if platform.system() == "Darwin": + host_os = "darwin" + toolchain_path = android_ndk_path + "/toolchains/llvm/prebuilt/darwin-x86_64" + +elif platform.system() == "Linux": + host_os = "linux" + toolchain_path = android_ndk_path + "/toolchains/llvm/prebuilt/linux-x86_64" + +os.environ['PATH'] += os.pathsep + toolchain_path + "/bin" +os.environ['CC'] = toolchain_path + "/bin/" + TOOLCHAIN_PREFIX + android_sdk_version + "-" + "clang" +os.environ['CXX'] = toolchain_path + "/bin/" + TOOLCHAIN_PREFIX + android_sdk_version + "-" + "clang++" + +GYP_DEFINES = "target_arch=" + arch +GYP_DEFINES += " v8_target_arch=" + arch +GYP_DEFINES += " android_target_arch=" + arch +GYP_DEFINES += " host_os=" + host_os + " OS=android" +os.environ['GYP_DEFINES'] = GYP_DEFINES + +if os.path.exists("./configure"): + os.system("./configure --dest-cpu=" + DEST_CPU + " --dest-os=android --openssl-no-asm --cross-compiling")