From 118a8dacfa7b3061c14f7353b1d483f4e4d80546 Mon Sep 17 00:00:00 2001 From: lluisemper <58423269+lluisemper@users.noreply.github.com> Date: Tue, 19 Aug 2025 21:07:55 +0200 Subject: [PATCH] build: implement JSON-driven Android patch system Replace hardcoded Android patch application with JSON configuration to improve maintainability and enable multiple patches. The current patch_android() function only applies a single hardcoded patch, making it difficult to add new patches needed for Android builds. Recent contributions show multiple patches are required for proper Android cross-compilation support. This change: - Creates android-patches.json for patch configuration - Refactors patch_android() to read from JSON - Enables platform-specific patch filtering - Maintains 100% backward compatibility - Prepares infrastructure for additional patches Implements TODO comment in android_configure.py line 5 Refs: https://github.com/nodejs/node/pull/57748 --- android-patches.json | 13 +++++ android_configure.py | 111 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 android-patches.json diff --git a/android-patches.json b/android-patches.json new file mode 100644 index 00000000000000..43a911fb06240c --- /dev/null +++ b/android-patches.json @@ -0,0 +1,13 @@ +{ + "format_version": "1.0", + "patches": [ + { + "name": "V8 Trap Handler Fix", + "target_file": "./deps/v8/src/trap-handler/trap-handler.h", + "patch_file": "./android-patches/trap-handler.h.patch", + "platforms": ["Linux"], + "description": "Related to https://github.com/nodejs/node/issues/36287", + "required": true + } + ] +} \ No newline at end of file diff --git a/android_configure.py b/android_configure.py index 5cea0393f48a76..8ae63d550a86a4 100644 --- a/android_configure.py +++ b/android_configure.py @@ -1,15 +1,100 @@ import platform import sys import os +import json + -# 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') + + try: + with open('android-patches.json', 'r') as f: + config = json.load(f) + except FileNotFoundError: + print("\033[91mError: \033[0m" + + "android-patches.json not found. This file is required for Android patch management.") + return + except json.JSONDecodeError as e: + print("\033[91mError: \033[0m" + + f"Invalid JSON in android-patches.json: {e}") + return + + patches = config.get('patches', []) + if not patches: + print("\033[93mWarning: \033[0m" + + "No patches found in configuration.") + print("\033[92mInfo: \033[0m" + "Tried to patch.") + return + + current_platform = platform.system() + patch_number = 1 + patches_applied = 0 + + for patch in patches: + try: + name = patch.get('name', 'Unknown Patch') + target_file = patch.get('target_file', '') + patch_file = patch.get('patch_file', '') + platforms = patch.get('platforms', []) + description = patch.get('description', '') + required = patch.get('required', True) + + # Display patch information + if description: + print(f"[{patch_number}] [{target_file}] {description}") + else: + print(f"[{patch_number}] [{target_file}] {name}") + + # Check if patch applies to current platform + if platforms and current_platform not in platforms: + print(f" Skipping: Not applicable to {current_platform}") + patch_number += 1 + continue + + # Check if patch file exists + if not os.path.exists(patch_file): + error_msg = f"Patch file not found: {patch_file}" + if required: + print(f"\033[91mError: \033[0m{error_msg}") + return + else: + print(f"\033[93mWarning: \033[0m{error_msg}") + patch_number += 1 + continue + + # Check if target file exists + if not os.path.exists(target_file): + error_msg = f"Target file not found: {target_file}" + if required: + print(f"\033[91mError: \033[0m{error_msg}") + return + else: + print(f"\033[93mWarning: \033[0m{error_msg}") + patch_number += 1 + continue + + # Apply the patch + result = os.system(f'patch -f {target_file} < {patch_file}') + if result == 0: + patches_applied += 1 + elif required: + print( + f"\033[91mError: \033[0mFailed to apply required patch: {name}") + return + + patch_number += 1 + + except KeyError as e: + print( + f"\033[91mError: \033[0mMissing required field in patch configuration: {e}") + if patch.get('required', True): + return + patch_number += 1 + continue + print("\033[92mInfo: \033[0m" + "Tried to patch.") + if platform.system() != "Linux" and platform.system() != "Darwin": print("android-configure is currently only supported on Linux and Darwin.") sys.exit(1) @@ -19,7 +104,8 @@ def patch_android(): sys.exit(0) if len(sys.argv) != 4: - print("Usage: ./android-configure [patch] ") + print( + "Usage: ./android-configure [patch] ") sys.exit(1) if not os.path.exists(sys.argv[1]) or not os.listdir(sys.argv[1]): @@ -27,7 +113,8 @@ def patch_android(): 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)") + 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] @@ -49,7 +136,8 @@ def patch_android(): 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") + 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 + "...") @@ -63,8 +151,10 @@ def patch_android(): 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++" +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 @@ -74,4 +164,5 @@ def patch_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") + os.system("./configure --dest-cpu=" + DEST_CPU + + " --dest-os=android --openssl-no-asm --cross-compiling")