Skip to content

Commit 118a8da

Browse files
committed
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: #57748
1 parent ae0aaec commit 118a8da

2 files changed

Lines changed: 114 additions & 10 deletions

File tree

android-patches.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"format_version": "1.0",
3+
"patches": [
4+
{
5+
"name": "V8 Trap Handler Fix",
6+
"target_file": "./deps/v8/src/trap-handler/trap-handler.h",
7+
"patch_file": "./android-patches/trap-handler.h.patch",
8+
"platforms": ["Linux"],
9+
"description": "Related to https://github.com/nodejs/node/issues/36287",
10+
"required": true
11+
}
12+
]
13+
}

android_configure.py

Lines changed: 101 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,100 @@
11
import platform
22
import sys
33
import os
4+
import json
5+
46

5-
# TODO: In next version, it will be a JSON file listing all the patches, and then it will iterate through to apply them.
67
def patch_android():
78
print("- Patches List -")
8-
print("[1] [deps/v8/src/trap-handler/trap-handler.h] related to https://github.com/nodejs/node/issues/36287")
9-
if platform.system() == "Linux":
10-
os.system('patch -f ./deps/v8/src/trap-handler/trap-handler.h < ./android-patches/trap-handler.h.patch')
9+
10+
try:
11+
with open('android-patches.json', 'r') as f:
12+
config = json.load(f)
13+
except FileNotFoundError:
14+
print("\033[91mError: \033[0m" +
15+
"android-patches.json not found. This file is required for Android patch management.")
16+
return
17+
except json.JSONDecodeError as e:
18+
print("\033[91mError: \033[0m" +
19+
f"Invalid JSON in android-patches.json: {e}")
20+
return
21+
22+
patches = config.get('patches', [])
23+
if not patches:
24+
print("\033[93mWarning: \033[0m" +
25+
"No patches found in configuration.")
26+
print("\033[92mInfo: \033[0m" + "Tried to patch.")
27+
return
28+
29+
current_platform = platform.system()
30+
patch_number = 1
31+
patches_applied = 0
32+
33+
for patch in patches:
34+
try:
35+
name = patch.get('name', 'Unknown Patch')
36+
target_file = patch.get('target_file', '')
37+
patch_file = patch.get('patch_file', '')
38+
platforms = patch.get('platforms', [])
39+
description = patch.get('description', '')
40+
required = patch.get('required', True)
41+
42+
# Display patch information
43+
if description:
44+
print(f"[{patch_number}] [{target_file}] {description}")
45+
else:
46+
print(f"[{patch_number}] [{target_file}] {name}")
47+
48+
# Check if patch applies to current platform
49+
if platforms and current_platform not in platforms:
50+
print(f" Skipping: Not applicable to {current_platform}")
51+
patch_number += 1
52+
continue
53+
54+
# Check if patch file exists
55+
if not os.path.exists(patch_file):
56+
error_msg = f"Patch file not found: {patch_file}"
57+
if required:
58+
print(f"\033[91mError: \033[0m{error_msg}")
59+
return
60+
else:
61+
print(f"\033[93mWarning: \033[0m{error_msg}")
62+
patch_number += 1
63+
continue
64+
65+
# Check if target file exists
66+
if not os.path.exists(target_file):
67+
error_msg = f"Target file not found: {target_file}"
68+
if required:
69+
print(f"\033[91mError: \033[0m{error_msg}")
70+
return
71+
else:
72+
print(f"\033[93mWarning: \033[0m{error_msg}")
73+
patch_number += 1
74+
continue
75+
76+
# Apply the patch
77+
result = os.system(f'patch -f {target_file} < {patch_file}')
78+
if result == 0:
79+
patches_applied += 1
80+
elif required:
81+
print(
82+
f"\033[91mError: \033[0mFailed to apply required patch: {name}")
83+
return
84+
85+
patch_number += 1
86+
87+
except KeyError as e:
88+
print(
89+
f"\033[91mError: \033[0mMissing required field in patch configuration: {e}")
90+
if patch.get('required', True):
91+
return
92+
patch_number += 1
93+
continue
94+
1195
print("\033[92mInfo: \033[0m" + "Tried to patch.")
1296

97+
1398
if platform.system() != "Linux" and platform.system() != "Darwin":
1499
print("android-configure is currently only supported on Linux and Darwin.")
15100
sys.exit(1)
@@ -19,15 +104,17 @@ def patch_android():
19104
sys.exit(0)
20105

21106
if len(sys.argv) != 4:
22-
print("Usage: ./android-configure [patch] <path to the Android NDK> <Android SDK version> <target architecture>")
107+
print(
108+
"Usage: ./android-configure [patch] <path to the Android NDK> <Android SDK version> <target architecture>")
23109
sys.exit(1)
24110

25111
if not os.path.exists(sys.argv[1]) or not os.listdir(sys.argv[1]):
26112
print("\033[91mError: \033[0m" + "Invalid path to the Android NDK")
27113
sys.exit(1)
28114

29115
if int(sys.argv[2]) < 24:
30-
print("\033[91mError: \033[0m" + "Android SDK version must be at least 24 (Android 7.0)")
116+
print("\033[91mError: \033[0m" +
117+
"Android SDK version must be at least 24 (Android 7.0)")
31118
sys.exit(1)
32119

33120
android_ndk_path = sys.argv[1]
@@ -49,7 +136,8 @@ def patch_android():
49136
TOOLCHAIN_PREFIX = "x86_64-linux-android"
50137
arch = "x64"
51138
else:
52-
print("\033[91mError: \033[0m" + "Invalid target architecture, must be one of: arm, arm64, aarch64, x86, x86_64")
139+
print("\033[91mError: \033[0m" +
140+
"Invalid target architecture, must be one of: arm, arm64, aarch64, x86, x86_64")
53141
sys.exit(1)
54142

55143
print("\033[92mInfo: \033[0m" + "Configuring for " + DEST_CPU + "...")
@@ -63,8 +151,10 @@ def patch_android():
63151
toolchain_path = android_ndk_path + "/toolchains/llvm/prebuilt/linux-x86_64"
64152

65153
os.environ['PATH'] += os.pathsep + toolchain_path + "/bin"
66-
os.environ['CC'] = toolchain_path + "/bin/" + TOOLCHAIN_PREFIX + android_sdk_version + "-" + "clang"
67-
os.environ['CXX'] = toolchain_path + "/bin/" + TOOLCHAIN_PREFIX + android_sdk_version + "-" + "clang++"
154+
os.environ['CC'] = toolchain_path + "/bin/" + \
155+
TOOLCHAIN_PREFIX + android_sdk_version + "-" + "clang"
156+
os.environ['CXX'] = toolchain_path + "/bin/" + \
157+
TOOLCHAIN_PREFIX + android_sdk_version + "-" + "clang++"
68158

69159
GYP_DEFINES = "target_arch=" + arch
70160
GYP_DEFINES += " v8_target_arch=" + arch
@@ -74,4 +164,5 @@ def patch_android():
74164
os.environ['GYP_DEFINES'] = GYP_DEFINES
75165

76166
if os.path.exists("./configure"):
77-
os.system("./configure --dest-cpu=" + DEST_CPU + " --dest-os=android --openssl-no-asm --cross-compiling")
167+
os.system("./configure --dest-cpu=" + DEST_CPU +
168+
" --dest-os=android --openssl-no-asm --cross-compiling")

0 commit comments

Comments
 (0)