Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: refactor Android build system #44207

Merged
merged 5 commits into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 35 additions & 83 deletions android-configure
Original file line number Diff line number Diff line change
@@ -1,83 +1,35 @@
#!/bin/bash

# In order to cross-compile node for Android using NDK, run:
# source android-configure <path_to_ndk> [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=<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)
26 changes: 26 additions & 0 deletions android-patches/trap-handler.h.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--- trap-handler.h 2022-08-11 09:01:23.384000000 +0800
F3n67u marked this conversation as resolved.
Show resolved Hide resolved
+++ 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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛔ means that GitHub expects all text files to end with on and only one \n

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry but I don't seem to fully understand what you're saying, could you describe it in a little more detail?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a text file doesn't has a ending newline, then GitHub will show a ⛔symbol in the “File Changed” panel. Could we ending this file with an ending newline?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot

76 changes: 76 additions & 0 deletions android_configure.py
Original file line number Diff line number Diff line change
@@ -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')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use subprocess.run() instead of os.system() for security and compatibility reasons.

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] <path to the Android NDK> <Android SDK version> <target architecture>")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but in this branch, BUILDING.md is out of date, do I need to create a new branch and pull requests to update it or later?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to update this doc in the same pr.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @MeowShe. Would you update BUILDING.md in this pr?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @MeowShe. Would you update BUILDING.md in this pr?

I want but I don't seem to know how to do it because the BUILDING.md in this branch is out of date and if I update BUILDING.md it will cause a conflict and I will have to merge main branch to solve it, but the nodejs Pull Request CI doesn't seem to allow me to do that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I will update BUILDING.md using rebase when all the fix are ready.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MeowShe would you mind update the BUILDING.md to keep the doc update with this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will open a new pull request to update it, and a macOS build fix will be included, thank you.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. A person asked me in an email if android configure is supported in the latest main branch. So I remember our BUILING.md if lost updated with our codebase.😃

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will commit those changes ASAP 😃

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")