diff --git a/.github/actions/cleanup-linux-disk-space/action.yml b/.github/actions/cleanup-linux-disk-space/action.yml index 0e823f22..daee2402 100644 --- a/.github/actions/cleanup-linux-disk-space/action.yml +++ b/.github/actions/cleanup-linux-disk-space/action.yml @@ -13,13 +13,37 @@ runs: run: | echo 'Disk space before cleanup' df -aH - sudo apt-get remove -y --purge '^mysql-.*' '^mongodb-.*' '^mssql-.*' '^postgresql-.*' '^aspnetcore-*' '^dotnet-.*' '^php.*-.*' 'mono-complete' '^llvm-.*' 'powershell' 'google-chrome-*' 'microsoft-edge-*' 'firefox' 'nginx' 'apache2' + + # Regular package cleanup + sudo apt-get remove -y --purge '^mysql-.*' '^mongodb-.*' '^mssql-.*' '^postgresql-.*' '^aspnetcore-*' '^dotnet-.*' '^php.*-.*' 'mono-complete' '^llvm-.*' 'powershell' 'google-chrome-*' 'microsoft-edge-*' 'firefox' 'nginx' 'apache2' 'ghc' '^ghc-*' sudo apt-get autoremove -y + + # Remove unnecessary large directories sudo rm -rf /usr/share/dotnet - echo 'Showing Android SDKs' - ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --list - ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --uninstall 'ndk;24.0.8215888' 'ndk;25.2.9519653' 'ndk;26.2.11394342' + sudo rm -rf /usr/local/.ghcup /opt/ghc + + # Android SDK cleanup + echo 'Showing installed Android SDKs' + ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --list_installed + + echo 'Cleaning unnecessary Android SDK components...' + echo 'Removing old build tools...' + ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --uninstall "build-tools;31.0.0" "build-tools;32.0.0" "build-tools;33.0.0" "build-tools;33.0.1" "build-tools;33.0.2" "build-tools;33.0.3" "build-tools;34.0.0" + + echo 'Removing old platforms...' + ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --uninstall "platforms;android-31" "platforms;android-32" "platforms;android-33" "platforms;android-33-ext4" "platforms;android-33-ext5" "platforms;android-34" "platforms;android-34-ext8" "platforms;android-34-ext10" "platforms;android-34-ext11" "platforms;android-34-ext12" + + echo 'Removing NDKs...' + ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --uninstall "ndk;26.3.11579264" + + echo 'Removing extras...' + ${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/sdkmanager --uninstall "extras;android;m2repository" "extras;google;google_play_services" "extras;google;m2repository" + + # Docker cleanup + echo 'Cleaning up Docker resources' + docker system prune -af || true echo 'Removing all Docker images' - docker rmi -f $(docker images -aq) + docker rmi -f $(docker images -aq) || true + echo 'Disk space after cleanup' df -aH diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 74959699..72214ce2 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -1,7 +1,20 @@ name: Build jsc-android and test on: - workflow_dispatch: {} + workflow_dispatch: + inputs: + publish: + description: 'Publish npm packages after build/test succeed' + type: boolean + default: false + npm-tag: + description: 'npm dist-tag' + required: false + default: latest + dry-run: + description: 'Run npm publish in dry-run mode' + type: boolean + default: true push: branches: [main] pull_request: @@ -12,10 +25,16 @@ jobs: env: ORG_GRADLE_PROJECT_signingKey: ${{ secrets.GPG_SIGNING_KEY }} ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.GPG_SIGNING_PASSWORD }} + NDK_VERSION_27: '27.1.12297006' + NDK_VERSION_28: '28.2.13676358' + BUILD_CACHE_VERSION: v1 steps: - uses: actions/checkout@v4 + - name: 🧹 Cleanup GitHub Linux runner disk space + uses: ./.github/actions/cleanup-linux-disk-space + - name: 🔨 Use JDK 17 uses: actions/setup-java@v4 with: @@ -27,39 +46,126 @@ jobs: with: node-version: 22 + - name: Compute build cache key + id: build-hash + run: | + HASH=$(node scripts/build-hash.js) + echo "hash=$HASH" >> "$GITHUB_OUTPUT" + + - name: Restore JSC build artifacts + id: cache-dist + uses: actions/cache@v4 + with: + path: | + dist-ndk27 + dist-ndk27.unstripped + dist-ndk28 + dist-ndk28.unstripped + dist-ndk29 + dist-ndk29.unstripped + key: jsc-dist-${{ env.BUILD_CACHE_VERSION }}-${{ steps.build-hash.outputs.hash }} + + - name: Restore WebKit sources + id: cache-download + uses: actions/cache@v4 + with: + path: build/download + key: jsc-download-${{ env.BUILD_CACHE_VERSION }}-${{ steps.build-hash.outputs.hash }} + restore-keys: | + jsc-download-${{ env.BUILD_CACHE_VERSION }}- + - name: Install packages run: | sudo apt-get update - sudo apt-get install coreutils curl git wget python3 ruby gperf -y + sudo apt-get install coreutils curl git wget python3 ruby gperf ccache -y shell: bash + - name: Restore ccache + id: cache-ccache + uses: actions/cache@v4 + with: + path: ~/.cache/ccache + key: ccache-${{ env.BUILD_CACHE_VERSION }}-${{ runner.os }}-${{ env.NDK_VERSION_27 }}-${{ steps.build-hash.outputs.hash }} + restore-keys: | + ccache-${{ env.BUILD_CACHE_VERSION }}-${{ runner.os }}-${{ env.NDK_VERSION_27 }}- + + - name: Configure ccache + run: | + mkdir -p ~/.cache/ccache + if command -v ccache >/dev/null 2>&1; then + ccache --max-size=5G + ccache --zero-stats || true + fi + shell: bash + + - name: Cache Android NDK r27 + id: cache-ndk-27 + uses: actions/cache@v4 + with: + path: ${{ env.ANDROID_HOME }}/ndk/${{ env.NDK_VERSION_27 }} + key: android-ndk-${{ runner.os }}-${{ env.NDK_VERSION_27 }} + - name: Install Android packages run: | export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools yes | sdkmanager --licenses || true - sdkmanager \ - "cmake;3.22.1" \ - "ndk;27.1.12297006" - # move out builtin icu headers from ndk and prevent icu build errors - mv "${ANDROID_HOME}/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/unicode" "${ANDROID_HOME}/ndk/27.1.12297006/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/unicode2" - - echo "ANDROID_NDK=$ANDROID_HOME/ndk/27.1.12297006" >> $GITHUB_ENV - echo "PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools" >> $GITHUB_ENV + sdkmanager "cmake;3.22.1" + if [[ ! -d "${ANDROID_HOME}/ndk/${NDK_VERSION_27}" ]]; then + sdkmanager "ndk;${NDK_VERSION_27}" + fi + UNICODE_DIR="${ANDROID_HOME}/ndk/${NDK_VERSION_27}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/unicode" + if [[ -d "${UNICODE_DIR}" ]]; then + mv "${UNICODE_DIR}" "${UNICODE_DIR}2" + fi + echo "ANDROID_NDK=$ANDROID_HOME/ndk/${NDK_VERSION_27}" >> $GITHUB_ENV + echo "PATH=$PATH" >> $GITHUB_ENV + shell: bash + + - name: Install dependencies + run: yarn install --frozen-lockfile + shell: bash + + - name: Clean previous build outputs + if: steps.cache-dist.outputs.cache-hit != 'true' + run: | + rm -rf dist dist.unstripped dist-ndk* build/target* build/compiled* build/cppruntime* + shell: bash + + - name: Download sources + if: steps.cache-download.outputs.cache-hit != 'true' + run: yarn download shell: bash - name: Build + if: steps.cache-dist.outputs.cache-hit != 'true' + run: yarn start + shell: bash + + - name: Show ccache stats + if: steps.cache-dist.outputs.cache-hit != 'true' run: | - yarn install --frozen-lockfile - yarn clean - yarn download - yarn start + if command -v ccache >/dev/null 2>&1; then + ccache --show-stats + fi shell: bash - name: Archive run: | + rm -rf archive mkdir -p archive - mv dist archive/ - mv dist.unstripped archive/ + shopt -s nullglob + found=0 + for dir in dist-ndk*; do + if [[ -d "$dir" ]]; then + cp -R "$dir" archive/ + found=1 + fi + done + shopt -u nullglob + if [[ $found -eq 0 ]]; then + echo "No distribution directories were produced." >&2 + exit 1 + fi shell: bash - uses: actions/upload-artifact@v4 @@ -96,8 +202,12 @@ jobs: - name: Extract archive run: | - mv archive/dist dist - mv archive/dist.unstripped dist.unstripped + shopt -s nullglob + for dir in archive/dist-ndk*; do + dest=$(basename "$dir") + mv "$dir" "$dest" + done + shopt -u nullglob rmdir archive shell: bash @@ -125,6 +235,7 @@ jobs: target: google_apis working-directory: test script: | + export JSC_GRADLE_DIST_PATH=../../dist-ndk27 npx expo run:android --variant release --no-bundler adb logcat -c set +e @@ -142,3 +253,56 @@ jobs: $HOME/.maestro/tests/**/* test/android/app/build/outputs/apk/release/app-release.apk test/adb.log + + publish: + if: github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true' + needs: + - build + - test + runs-on: ubuntu-latest + environment: + name: npm-publish + url: https://www.npmjs.com/package/jsc-android + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + + - name: ⬢ Setup Node + uses: actions/setup-node@v4 + with: + node-version: 22 + + - uses: actions/download-artifact@v4 + with: + name: archive + path: archive + + - name: Install dependencies + run: yarn install --frozen-lockfile + shell: bash + + - name: Verify npm token availability + if: github.event.inputs.dry-run != 'true' + run: | + if [[ -z "${NPM_TOKEN:-}" ]]; then + echo "NPM_TOKEN secret is required for publishing." >&2 + exit 1 + fi + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + shell: bash + + - name: Publish packages + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_CONFIG_PROVENANCE: 'true' + run: | + TAG="${{ github.event.inputs.npm-tag }}" + DRY_RUN="${{ github.event.inputs.dry-run }}" + PUBLISH_ARGS=("-T" "$TAG") + if [[ "$DRY_RUN" == 'true' ]]; then + PUBLISH_ARGS+=("--dry-run") + fi + node scripts/publish.js "${PUBLISH_ARGS[@]}" archive + shell: bash diff --git a/lib/jsc-android/build.gradle b/lib/jsc-android/build.gradle index fab7dbb2..7e71b48c 100644 --- a/lib/jsc-android/build.gradle +++ b/lib/jsc-android/build.gradle @@ -28,6 +28,10 @@ android { versionCode 1 versionName "1.0" + ndk { + abiFilters 'arm64-v8a', 'x86_64' + } + externalNativeBuild { cmake { arguments '-DANDROID_STL=c++_shared', diff --git a/package.json b/package.json index 3abd6d9c..c5ea81e0 100644 --- a/package.json +++ b/package.json @@ -20,14 +20,47 @@ "/dist" ], "scripts": { - "clean": "rm -rf dist; rm -rf build", + "clean": "rm -rf dist dist.unstripped dist-ndk* dist-ndk*.unstripped; rm -rf build", "info": "./scripts/info.sh", "download": "./scripts/download.sh", "start": "./scripts/start.sh" }, "config": { - "webkitGTK": "2.26.4", - "chromiumICUCommit": "64e5d7d43a1ff205e3787ab6150bbc1a1837332b" + "bunWebKitRepo": "https://github.com/oven-sh/WebKit.git", + "bunWebKitCommit": "26e6460697dab3e8681489ce67857434b2180e6f", + "icuRelease": "release-74-2", + "icuArchive": "icu4c-74_2-src.tgz", + "ndkVariants": [ + { + "id": "ndk27", + "label": "Android NDK r27", + "npmPackage": "jsc-android-ndk27", + "pkgRevisionPrefixes": ["27."], + "buildSuffix": "ndk27", + "distDir": "dist-ndk27", + "distUnstrippedDir": "dist-ndk27.unstripped", + "disableLoopVectorization": true + }, + { + "id": "ndk28c", + "label": "Android NDK r28c", + "npmPackage": "jsc-android", + "pkgRevisionPrefixes": ["28.2."], + "buildSuffix": "ndk28", + "distDir": "dist-ndk28", + "distUnstrippedDir": "dist-ndk28.unstripped", + "default": true + }, + { + "id": "ndk29", + "label": "Android NDK r29", + "npmPackage": "jsc-android-ndk29", + "pkgRevisionPrefixes": ["29."], + "buildSuffix": "ndk29", + "distDir": "dist-ndk29", + "distUnstrippedDir": "dist-ndk29.unstripped" + } + ] }, "devDependencies": { "commander": "^12.1.0", diff --git a/patches/jsc_android_collator_static.patch b/patches/jsc_android_collator_static.patch new file mode 100644 index 00000000..215afffa --- /dev/null +++ b/patches/jsc_android_collator_static.patch @@ -0,0 +1,30 @@ +diff --git a/webkit/Source/WTF/wtf/unicode/CollatorDefault.cpp b/webkit/Source/WTF/wtf/unicode/CollatorDefault.cpp +index 9a45990fa7..b709f02052 100644 +--- a/webkit/Source/WTF/wtf/unicode/CollatorDefault.cpp ++++ b/webkit/Source/WTF/wtf/unicode/CollatorDefault.cpp +@@ -27,13 +27,15 @@ + */ + + #include "config.h" ++#include ++#include + #include + + #if UCONFIG_NO_COLLATION + + namespace WTF { + +-int Collator::collate(StringView a, StringView b) const ++int Collator::collate(StringView a, StringView b) + { + unsigned commonLength = std::min(a.length(), b.length()); + for (unsigned i = 0; i < commonLength; ++i) { +@@ -51,7 +53,7 @@ int Collator::collate(StringView a, StringView b) const + return 0; + } + +-int Collator::collate(const char8_t* a, const char8_t* b) const ++int Collator::collate(const char8_t* a, const char8_t* b) + { + return collate(String::fromUTF8(byteCast(a)), String::fromUTF8(byteCast(b))); + } diff --git a/patches/jsc_android_define_bun_macros.patch b/patches/jsc_android_define_bun_macros.patch new file mode 100644 index 00000000..bef6648b --- /dev/null +++ b/patches/jsc_android_define_bun_macros.patch @@ -0,0 +1,15 @@ +diff --git a/webkit/Source/WTF/wtf/posix/OSAllocatorPOSIX.cpp b/webkit/Source/WTF/wtf/posix/OSAllocatorPOSIX.cpp +index 483d333b83..1612e84271 100644 +--- a/webkit/Source/WTF/wtf/posix/OSAllocatorPOSIX.cpp ++++ b/webkit/Source/WTF/wtf/posix/OSAllocatorPOSIX.cpp +@@ -63,6 +63,10 @@ + + #endif + ++#ifndef BUN_MACOSX ++#define BUN_MACOSX 0 ++#endif ++ + #ifdef MADV_DONTFORK + #define BUN_MADV_DONTFORK MADV_DONTFORK + #else diff --git a/patches/jsc_android_jit_guards.patch b/patches/jsc_android_jit_guards.patch new file mode 100644 index 00000000..abe8af33 --- /dev/null +++ b/patches/jsc_android_jit_guards.patch @@ -0,0 +1,36 @@ +diff --git a/webkit/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h b/webkit/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h +index 8b89733b83..9c1d93c23f 100644 +--- a/webkit/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h ++++ b/webkit/Source/JavaScriptCore/jit/JITInlineCacheGenerator.h +@@ -53,7 +53,11 @@ enum class AccessType : int8_t; + enum class CacheType : int8_t; + enum class JITType : uint8_t; + ++#if ENABLE(DFG_JIT) + using CompileTimeStructureStubInfo = Variant; ++#else ++using CompileTimeStructureStubInfo = Variant; ++#endif + + class JITInlineCacheGenerator { + protected: +diff --git a/webkit/Source/JavaScriptCore/jit/PCToCodeOriginMap.h b/webkit/Source/JavaScriptCore/jit/PCToCodeOriginMap.h +index 196e0516a9..572f6a4444 100644 +--- a/webkit/Source/JavaScriptCore/jit/PCToCodeOriginMap.h ++++ b/webkit/Source/JavaScriptCore/jit/PCToCodeOriginMap.h +@@ -41,6 +41,7 @@ namespace B3 { + class PCToOriginMap; + } + ++#if ENABLE(WEBASSEMBLY) + namespace Wasm { + class WasmOrigin { + MAKE_VALIDATED_REINTERPRET_CAST +@@ -59,6 +60,7 @@ public: + MAKE_VALIDATED_REINTERPRET_CAST_IMPL("WasmOrigin", WasmOrigin) + + } // namespace Wasm ++#endif + + class LinkBuffer; + class PCToCodeOriginMapBuilder; diff --git a/patches/jsc_android_jsc_wait.patch b/patches/jsc_android_jsc_wait.patch new file mode 100644 index 00000000..4c667da9 --- /dev/null +++ b/patches/jsc_android_jsc_wait.patch @@ -0,0 +1,22 @@ +diff --git a/webkit/Source/JavaScriptCore/jsc.cpp b/webkit/Source/JavaScriptCore/jsc.cpp +index 2b3b231e54..6b861fd1fe 100644 +--- a/webkit/Source/JavaScriptCore/jsc.cpp ++++ b/webkit/Source/JavaScriptCore/jsc.cpp +@@ -3649,7 +3649,7 @@ int main(int argc, char** argv) + WTF::fastDisableScavenger(); + fprintf(stdout, "\njs shell waiting for input to exit\n"); + fflush(stdout); +- getc(stdin); ++ (void)getc(stdin); + } + + #if OS(UNIX) +@@ -3658,7 +3658,7 @@ int main(int argc, char** argv) + fprintf(stdout, "\njs shell waiting for `kill -USR2 [pid]` to exit\n"); + fflush(stdout); + +- waitToExit.wait(); ++ (void)waitToExit.wait(); + + fprintf(stdout, "\njs shell exiting\n"); + fflush(stdout); diff --git a/patches/jsc_android_log_version.patch b/patches/jsc_android_log_version.patch new file mode 100644 index 00000000..483a6bb0 --- /dev/null +++ b/patches/jsc_android_log_version.patch @@ -0,0 +1,29 @@ +diff --git a/webkit/Source/JavaScriptCore/API/JSBase.cpp b/webkit/Source/JavaScriptCore/API/JSBase.cpp +index f0b01ec79a..1c9869b40b 100644 +--- a/webkit/Source/JavaScriptCore/API/JSBase.cpp ++++ b/webkit/Source/JavaScriptCore/API/JSBase.cpp +@@ -37,6 +37,12 @@ + #include "OpaqueJSString.h" + #include "SourceCode.h" + ++#if OS(ANDROID) ++#include ++#ifndef JSC_VERSION ++#define JSC_VERSION "unknown" ++#endif ++#endif + #if ENABLE(REMOTE_INSPECTOR) + #include "JSGlobalObjectInspectorController.h" + #endif +@@ -220,3 +226,11 @@ JSObjectRef JSGetMemoryUsageStatistics(JSContextRef ctx) + + return toRef(object); + } ++ ++#if OS(ANDROID) ++__attribute__((constructor)) ++static void logJSCVersion() ++{ ++ __android_log_print(ANDROID_LOG_INFO, "JavaScriptCore.Version", "%s", JSC_VERSION); ++} ++#endif diff --git a/patches/jsc_android_logging_property.patch b/patches/jsc_android_logging_property.patch new file mode 100644 index 00000000..7e65e2fc --- /dev/null +++ b/patches/jsc_android_logging_property.patch @@ -0,0 +1,30 @@ +diff --git a/webkit/Source/WTF/wtf/android/LoggingAndroid.cpp b/webkit/Source/WTF/wtf/android/LoggingAndroid.cpp +--- a/webkit/Source/WTF/wtf/android/LoggingAndroid.cpp ++++ b/webkit/Source/WTF/wtf/android/LoggingAndroid.cpp +@@ -32,20 +32,15 @@ + + String logLevelString() + { +- const char* propertyValue = nullptr; ++ constexpr auto propertyName = "debug." LOG_CHANNEL_WEBKIT_SUBSYSTEM ".log"; ++ char propertyValue[PROP_VALUE_MAX] { }; ++ int length = __system_property_get(propertyName, propertyValue); + +- if (const auto* propertyInfo = __system_property_find("debug." LOG_CHANNEL_WEBKIT_SUBSYSTEM ".log")) { +- __system_property_read_callback(propertyInfo, [](void *userData, const char*, const char* value, unsigned) { +- auto **propertyValue = static_cast(userData); +- *propertyValue = value; +- }, &propertyValue); +- } +- + // Disable all log channels if the property is unset or empty. +- if (!propertyValue || !*propertyValue) +- return makeString("-all"_s); ++ if (length <= 0) ++ return "-all"_s; + +- return String::fromLatin1(propertyValue); ++ return String::fromLatin1(propertyValue); + } + + } // namespace WTF diff --git a/patches/jsc_android_release_flags.patch b/patches/jsc_android_release_flags.patch new file mode 100644 index 00000000..50a84027 --- /dev/null +++ b/patches/jsc_android_release_flags.patch @@ -0,0 +1,17 @@ +diff --git a/webkit/Source/cmake/OptionsCommon.cmake b/webkit/Source/cmake/OptionsCommon.cmake +index ea7d508967d6..b4de9ef50bbf 100644 +--- a/webkit/Source/cmake/OptionsCommon.cmake ++++ b/webkit/Source/cmake/OptionsCommon.cmake +@@ -1,7 +1,11 @@ +-set(CMAKE_CXX_STANDARD 23) ++set(CMAKE_CXX_STANDARD 20) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_CXX_EXTENSIONS OFF) + set(CMAKE_EXPERIMENTAL_CXX_MODULE_DYNDEP OFF) ++ ++# Android builds rely on downstream flags, so keep CMake from adding -O3 automatically. ++set(CMAKE_C_COMPILE_OPTIONS_RELEASE -DNDEBUG CACHE STRING "" FORCE) ++set(CMAKE_CXX_COMPILE_OPTIONS_RELEASE -DNDEBUG CACHE STRING "" FORCE) + + add_definitions(-DBUILDING_WITH_CMAKE=1) + add_definitions(-DBUILDING_WEBKIT=1) diff --git a/patches/jsc_android_silence_unused.patch b/patches/jsc_android_silence_unused.patch new file mode 100644 index 00000000..94799666 --- /dev/null +++ b/patches/jsc_android_silence_unused.patch @@ -0,0 +1,78 @@ +diff --git a/webkit/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp b/webkit/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp +index 2e2203099e..9c8917096d 100644 +--- a/webkit/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp ++++ b/webkit/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.cpp +@@ -45,6 +45,7 @@ void JSModuleNamespaceObject::finishCreation(JSGlobalObject* globalObject, Abstr + { + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); ++ UNUSED_PARAM(shouldPreventExtensions); + Base::finishCreation(vm); + ASSERT(inherits(info())); + +@@ -208,6 +209,9 @@ bool JSModuleNamespaceObject::put(JSCell* cell, JSGlobalObject* globalObject, Pr + { + VM& vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); ++ UNUSED_PARAM(cell); ++ UNUSED_PARAM(propertyName); ++ UNUSED_PARAM(value); + + #if USE(BUN_JSC_ADDITIONS) + auto* thisObject = jsCast(cell); +diff --git a/webkit/Source/JavaScriptCore/runtime/JSModuleRecord.cpp b/webkit/Source/JavaScriptCore/runtime/JSModuleRecord.cpp +index 24cea00a3f..41ccae3c5e 100644 +--- a/webkit/Source/JavaScriptCore/runtime/JSModuleRecord.cpp ++++ b/webkit/Source/JavaScriptCore/runtime/JSModuleRecord.cpp +@@ -63,18 +63,18 @@ JSModuleRecord::JSModuleRecord(VM& vm, Structure* structure, const Identifier& m + { + } + +-#if USE(BUN_JSC_ADDITIONS) + size_t JSModuleRecord::estimatedSize(JSCell* cell, VM& vm) + { +- const auto& thisObject = jsCast(cell); + size_t size = Base::estimatedSize(cell, vm); ++#if USE(BUN_JSC_ADDITIONS) ++ const auto& thisObject = jsCast(cell); + const SourceCode& sourceCode = thisObject->sourceCode(); + StringView view = sourceCode.provider() ? sourceCode.provider()->source() : StringView(); + size += view.length() * (view.is8Bit() ? sizeof(Latin1Character) : sizeof(UChar)); + size += sourceCode.memoryCost(); ++#endif + return size; + } +-#endif + void JSModuleRecord::destroy(JSCell* cell) + { + JSModuleRecord* thisObject = static_cast(cell); +diff --git a/webkit/Source/JavaScriptCore/runtime/JSPromise.cpp b/webkit/Source/JavaScriptCore/runtime/JSPromise.cpp +index 09b051775b..a0a4a6b10f 100644 +--- a/webkit/Source/JavaScriptCore/runtime/JSPromise.cpp ++++ b/webkit/Source/JavaScriptCore/runtime/JSPromise.cpp +@@ -219,6 +219,7 @@ void JSPromise::fulfillWithNonPromise(JSGlobalObject* lexicalGlobalObject, JSVal + { + VM& vm = lexicalGlobalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); ++ UNUSED_PARAM(scope); + uint32_t flags = this->flags(); + ASSERT_WITH_MESSAGE(!value.inherits(), "Promise fulfilled with exception"); + ASSERT_WITH_MESSAGE(!value.inherits(), "Promise fulfilled with another promise"); +diff --git a/webkit/Source/JavaScriptCore/runtime/ModuleProgramExecutable.cpp b/webkit/Source/JavaScriptCore/runtime/ModuleProgramExecutable.cpp +index be5602f0b7..2f26538268 100644 +--- a/webkit/Source/JavaScriptCore/runtime/ModuleProgramExecutable.cpp ++++ b/webkit/Source/JavaScriptCore/runtime/ModuleProgramExecutable.cpp +@@ -37,10 +37,11 @@ ModuleProgramExecutable::ModuleProgramExecutable(JSGlobalObject* globalObject, c + { + SourceProviderSourceType sourceType = source.provider()->sourceType(); + ASSERT(sourceType == SourceProviderSourceType::Module +- #if USE(BUN_JSC_ADDITIONS) ++#if USE(BUN_JSC_ADDITIONS) + || sourceType == SourceProviderSourceType::BunTranspiledModule +- #endif ++#endif + ); ++ UNUSED_PARAM(sourceType); + VM& vm = globalObject->vm(); + if (vm.typeProfiler() || vm.controlFlowProfiler()) + vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), typeProfilingStartOffset(), typeProfilingEndOffset()); diff --git a/patches/jsc_android_systemheap_posix_memalign.patch b/patches/jsc_android_systemheap_posix_memalign.patch new file mode 100644 index 00000000..a02e93e6 --- /dev/null +++ b/patches/jsc_android_systemheap_posix_memalign.patch @@ -0,0 +1,18 @@ +diff --git a/webkit/Source/bmalloc/bmalloc/SystemHeap.cpp b/webkit/Source/bmalloc/bmalloc/SystemHeap.cpp +--- a/webkit/Source/bmalloc/bmalloc/SystemHeap.cpp ++++ b/webkit/Source/bmalloc/bmalloc/SystemHeap.cpp +@@ -210,7 +210,13 @@ void* SystemHeap::malloc(size_t size, FailureAction action) + + void* SystemHeap::memalign(size_t alignment, size_t size, FailureAction action) + { +- void* result = ::aligned_alloc(alignment, size); ++ void* result = nullptr; ++#if PAS_OS(ANDROID) ++ if (::posix_memalign(&result, alignment, size)) ++ result = nullptr; ++#else ++ result = ::aligned_alloc(alignment, size); ++#endif + RELEASE_BASSERT(action == FailureAction::ReturnNull || result); + return result; + } diff --git a/patches/jsc_android_thread_name_guard.patch b/patches/jsc_android_thread_name_guard.patch new file mode 100644 index 00000000..9689e62b --- /dev/null +++ b/patches/jsc_android_thread_name_guard.patch @@ -0,0 +1,17 @@ +diff --git a/webkit/Source/bmalloc/libpas/src/libpas/pas_thread_local_cache.c b/webkit/Source/bmalloc/libpas/src/libpas/pas_thread_local_cache.c +--- a/webkit/Source/bmalloc/libpas/src/libpas/pas_thread_local_cache.c ++++ b/webkit/Source/bmalloc/libpas/src/libpas/pas_thread_local_cache.c +@@ -221,9 +221,13 @@ static void dump_thread_diagnostics(pthread_t thread) + #endif + #if PAS_PLATFORM(PLAYSTATION) + getname_result = pthread_get_name_np(thread, thread_name); ++#else ++#if PAS_OS(ANDROID) ++ getname_result = -1; + #else + getname_result = pthread_getname_np(thread, thread_name, sizeof(thread_name)); + #endif ++#endif + if (!getname_result) + pas_log("[%d] thread %p has name %s\n", getpid(), (void*)thread, thread_name); + else diff --git a/patches/jsc_android_timezone_validate.patch b/patches/jsc_android_timezone_validate.patch new file mode 100644 index 00000000..e45b2cd1 --- /dev/null +++ b/patches/jsc_android_timezone_validate.patch @@ -0,0 +1,48 @@ +diff --git a/webkit/Source/JavaScriptCore/runtime/JSDateMath.cpp b/webkit/Source/JavaScriptCore/runtime/JSDateMath.cpp +index cbd32cefe0..16df1ec5a0 100644 +--- a/webkit/Source/JavaScriptCore/runtime/JSDateMath.cpp ++++ b/webkit/Source/JavaScriptCore/runtime/JSDateMath.cpp +@@ -502,6 +502,12 @@ static std::tuple> retrieveTimeZoneInformation() + getTimeZoneOverride(timeZoneID); + String canonical; + UErrorCode status = U_ZERO_ERROR; ++#if (defined(UCONFIG_NO_FORMATTING) && UCONFIG_NO_FORMATTING) || !defined(ucal_getCanonicalTimeZoneID) ++ if (!timeZoneID.isEmpty()) ++ canonical = String(timeZoneID.span()); ++ else ++ canonical = "UTC"_s; ++#else + if (timeZoneID.isEmpty()) { + status = callBufferProducingFunction(ucal_getHostTimeZone, timeZoneID); + ASSERT_UNUSED(status, U_SUCCESS(status)); +@@ -514,6 +520,7 @@ static std::tuple> retrieveTimeZoneInformation() + } + if (canonical.isNull() || isUTCEquivalent(canonical)) + canonical = "UTC"_s; ++#endif + + globalCache.get() = std::tuple { canonical.isolatedCopy(), WTFMove(timeZoneID), currentID }; + } +diff --git a/webkit/Source/WTF/wtf/DateMath.cpp b/webkit/Source/WTF/wtf/DateMath.cpp +index d4551c78ef..37b2ef6fc2 100644 +--- a/webkit/Source/WTF/wtf/DateMath.cpp ++++ b/webkit/Source/WTF/wtf/DateMath.cpp +@@ -1008,6 +1008,10 @@ String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, u + + static std::optional> validateTimeZone(StringView timeZone) + { ++#if defined(UCONFIG_NO_FORMATTING) && UCONFIG_NO_FORMATTING ++ UNUSED_PARAM(timeZone); ++ return std::nullopt; ++#else + auto buffer = timeZone.upconvertedCharacters(); + const char16_t* characters = buffer; + Vector canonicalBuffer; +@@ -1015,6 +1019,7 @@ static std::optional> validateTimeZone(StringView timeZone) + if (!U_SUCCESS(status)) + return std::nullopt; + return canonicalBuffer; ++#endif + } + + bool isTimeZoneValid(StringView timeZone) diff --git a/patches/jsc_android_uv_pri64.patch b/patches/jsc_android_uv_pri64.patch new file mode 100644 index 00000000..684edd13 --- /dev/null +++ b/patches/jsc_android_uv_pri64.patch @@ -0,0 +1,16 @@ +diff --git a/webkit/Source/bmalloc/bmalloc/uv_get_constrained_memory.cpp b/webkit/Source/bmalloc/bmalloc/uv_get_constrained_memory.cpp +index e39afda511..48f46d76fc 100644 +--- a/webkit/Source/bmalloc/bmalloc/uv_get_constrained_memory.cpp ++++ b/webkit/Source/bmalloc/bmalloc/uv_get_constrained_memory.cpp +@@ -21,11 +21,12 @@ + + #include "BPlatform.h" + #include ++#include + + #if BOS(LINUX) + + #ifndef PRIu64 +-#define PRIu64 "lu" ++#define PRIu64 "llu" + #endif diff --git a/patches/jsc_android_wtf_sources.patch b/patches/jsc_android_wtf_sources.patch new file mode 100644 index 00000000..0d1c18a6 --- /dev/null +++ b/patches/jsc_android_wtf_sources.patch @@ -0,0 +1,45 @@ +diff --git a/webkit/Source/WTF/wtf/PlatformJSCOnly.cmake b/webkit/Source/WTF/wtf/PlatformJSCOnly.cmake +index 0ab58fe2a2..4b94606617 100644 +--- a/webkit/Source/WTF/wtf/PlatformJSCOnly.cmake ++++ b/webkit/Source/WTF/wtf/PlatformJSCOnly.cmake +@@ -36,8 +36,16 @@ else () + text/unix/TextBreakIteratorInternalICUUnix.cpp + + unix/LanguageUnix.cpp +- unix/LoggingUnix.cpp + ) ++ if (CMAKE_SYSTEM_NAME MATCHES "Android") ++ list(APPEND WTF_SOURCES ++ android/LoggingAndroid.cpp ++ ) ++ else () ++ list(APPEND WTF_SOURCES ++ unix/LoggingUnix.cpp ++ ) ++ endif () + if (WTF_OS_FUCHSIA) + list(APPEND WTF_SOURCES + fuchsia/CPUTimeFuchsia.cpp +@@ -97,6 +105,22 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") + + unix/MemoryPressureHandlerUnix.cpp + ) ++ list(APPEND WTF_PUBLIC_HEADERS ++ linux/CurrentProcessMemoryStatus.h ++ linux/ProcessMemoryFootprint.h ++ ) ++elseif (CMAKE_SYSTEM_NAME MATCHES "Android") ++ list(APPEND WTF_SOURCES ++ linux/CurrentProcessMemoryStatus.cpp ++ linux/MemoryFootprintLinux.cpp ++ linux/RealTimeThreads.cpp ++ ++ unix/MemoryPressureHandlerUnix.cpp ++ ) ++ list(APPEND WTF_PUBLIC_HEADERS ++ linux/CurrentProcessMemoryStatus.h ++ linux/ProcessMemoryFootprint.h ++ ) + elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + list(APPEND WTF_SOURCES + generic/MemoryFootprintGeneric.cpp diff --git a/patches/jsc_async_frame_guard.patch b/patches/jsc_async_frame_guard.patch new file mode 100644 index 00000000..20435d3c --- /dev/null +++ b/patches/jsc_async_frame_guard.patch @@ -0,0 +1,16 @@ +diff --git a/webkit/Source/JavaScriptCore/runtime/StackFrame.h b/webkit/Source/JavaScriptCore/runtime/StackFrame.h +index b689e68d58..5578051a6b 100644 +--- a/webkit/Source/JavaScriptCore/runtime/StackFrame.h ++++ b/webkit/Source/JavaScriptCore/runtime/StackFrame.h +@@ -100,7 +100,11 @@ public: + + bool isAsyncFrameWithoutCodeBlock() const + { ++#if USE(BUN_JSC_ADDITIONS) + return isAsyncFrame() && !codeBlock(); ++#else ++ return false; ++#endif + } + + #if USE(BUN_JSC_ADDITIONS) diff --git a/patches/jsc_disable_api_tests.patch b/patches/jsc_disable_api_tests.patch new file mode 100644 index 00000000..f808ea81 --- /dev/null +++ b/patches/jsc_disable_api_tests.patch @@ -0,0 +1,16 @@ +diff --git a/webkit/Source/cmake/OptionsJSCOnly.cmake b/webkit/Source/cmake/OptionsJSCOnly.cmake +index f00830dd41..f9e131cfa3 100644 +--- a/webkit/Source/cmake/OptionsJSCOnly.cmake ++++ b/webkit/Source/cmake/OptionsJSCOnly.cmake +@@ -101,10 +101,8 @@ else () + endif () + WEBKIT_OPTION_END() + +-if (WIN32) ++if (NOT DEFINED ENABLE_API_TESTS) + set(ENABLE_API_TESTS OFF) +-else () +- set(ENABLE_API_TESTS ON) + endif () + + if (WTF_CPU_ARM OR WTF_CPU_MIPS) diff --git a/patches/jsc_fix_external_string_tests.patch b/patches/jsc_fix_external_string_tests.patch new file mode 100644 index 00000000..d13d8180 --- /dev/null +++ b/patches/jsc_fix_external_string_tests.patch @@ -0,0 +1,40 @@ +diff --git a/webkit/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp b/webkit/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp +index 72339a29d7..cfaac6b233 100644 +--- a/webkit/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp ++++ b/webkit/Tools/TestWebKitAPI/Tests/WTF/StringImpl.cpp +@@ -758,7 +758,7 @@ TEST(WTF, ExternalStringImplCreate8bit) + bool freeFunctionCalled = false; + + { +- auto external = ExternalStringImpl::create({ buffer, bufferStringLength }, [&freeFunctionCalled](ExternalStringImpl* externalStringImpl, void* buffer, unsigned bufferSize) mutable { ++ auto external = ExternalStringImpl::create({ buffer, bufferStringLength }, nullptr, [&freeFunctionCalled](void*, void*, unsigned) mutable { + freeFunctionCalled = true; + }); + +@@ -780,7 +780,7 @@ TEST(WTF, ExternalStringImplCreate16bit) + bool freeFunctionCalled = false; + + { +- auto external = ExternalStringImpl::create({ buffer, bufferStringLength }, [&freeFunctionCalled](ExternalStringImpl* externalStringImpl, void* buffer, unsigned bufferSize) mutable { ++ auto external = ExternalStringImpl::create({ buffer, bufferStringLength }, nullptr, [&freeFunctionCalled](void*, void*, unsigned) mutable { + freeFunctionCalled = true; + }); + +@@ -809,7 +809,7 @@ TEST(WTF, ExternalStringAtom) + bool freeFunctionCalled = false; + + { +- auto external = ExternalStringImpl::create({ buffer, bufferStringLength }, [&freeFunctionCalled](ExternalStringImpl* externalStringImpl, void* buffer, unsigned bufferSize) mutable { ++ auto external = ExternalStringImpl::create({ buffer, bufferStringLength }, nullptr, [&freeFunctionCalled](void*, void*, unsigned) mutable { + freeFunctionCalled = true; + }); + +@@ -845,7 +845,7 @@ TEST(WTF, ExternalStringToSymbol) + bool freeFunctionCalled = false; + + { +- auto external = ExternalStringImpl::create(buffer.span8(), [&freeFunctionCalled](ExternalStringImpl* externalStringImpl, void* buffer, unsigned bufferSize) mutable { ++ auto external = ExternalStringImpl::create(buffer.span8(), nullptr, [&freeFunctionCalled](void*, void*, unsigned) mutable { + freeFunctionCalled = true; + }); + diff --git a/patches/jsc_guard_error_instance.patch b/patches/jsc_guard_error_instance.patch new file mode 100644 index 00000000..7cb15732 --- /dev/null +++ b/patches/jsc_guard_error_instance.patch @@ -0,0 +1,58 @@ +diff --git a/webkit/Source/JavaScriptCore/runtime/ErrorInstance.cpp b/webkit/Source/JavaScriptCore/runtime/ErrorInstance.cpp +index 07999a9b28..e694388e2e 100644 +--- a/webkit/Source/JavaScriptCore/runtime/ErrorInstance.cpp ++++ b/webkit/Source/JavaScriptCore/runtime/ErrorInstance.cpp +@@ -108,6 +108,7 @@ String appendSourceToErrorMessage(CodeBlock* codeBlock, BytecodeIndex bytecodeIn + return appender(message, codeBlock->source().provider()->getRange(start, stop), type, ErrorInstance::FoundApproximateSource); + } + ++#if USE(BUN_JSC_ADDITIONS) + void ErrorInstance::setStackFrames(VM& vm, WTF::Vector&& stackFrames) + { + std::unique_ptr> stackTrace = makeUnique>(WTFMove(stackFrames)); +@@ -116,6 +117,7 @@ void ErrorInstance::setStackFrames(VM& vm, WTF::Vector&& stackFrames + m_stackTrace = WTFMove(stackTrace); + vm.writeBarrier(this); + } ++#endif + + size_t ErrorInstance::estimatedSize(JSCell* cell, VM& vm) + { +@@ -370,11 +372,16 @@ void ErrorInstance::computeErrorInfo(VM& vm, bool allocationAllowed) + UNUSED_PARAM(allocationAllowed); + + if (m_stackTrace && !m_stackTrace->isEmpty()) { +- auto& fn = vm.onComputeErrorInfo(); + WTF::String stackString; +- if (fn) { +- stackString = fn(vm, *m_stackTrace.get(), m_lineColumn.line, m_lineColumn.column, m_sourceURL, this->bunErrorData()); +- } else { ++ bool handled = false; ++#if USE(BUN_JSC_ADDITIONS) ++ auto& computeErrorInfo = vm.onComputeErrorInfo(); ++ if (computeErrorInfo) { ++ stackString = computeErrorInfo(vm, *m_stackTrace.get(), m_lineColumn.line, m_lineColumn.column, m_sourceURL, this->bunErrorData()); ++ handled = true; ++ } ++#endif ++ if (!handled) { + getLineColumnAndSource(vm, m_stackTrace.get(), m_lineColumn, m_sourceURL); + stackString = Interpreter::stackTraceAsString(vm, *m_stackTrace.get()); + } +@@ -394,13 +401,12 @@ bool ErrorInstance::materializeErrorInfoIfNeeded(VM& vm) + return false; + + #if USE(BUN_JSC_ADDITIONS) +- +- auto& fn = vm.onComputeErrorInfoJSValue(); +- if (fn && m_stackTrace && !m_stackTrace->isEmpty()) { ++ auto& computeErrorInfoJSValue = vm.onComputeErrorInfoJSValue(); ++ if (computeErrorInfoJSValue && m_stackTrace && !m_stackTrace->isEmpty()) { + m_errorInfoMaterialized = true; + DeferGCForAWhile deferGC(vm); + +- JSValue stack = fn(vm, *m_stackTrace.get(), m_lineColumn.line, m_lineColumn.column, m_sourceURL, this, this->bunErrorData()); ++ JSValue stack = computeErrorInfoJSValue(vm, *m_stackTrace.get(), m_lineColumn.line, m_lineColumn.column, m_sourceURL, this, this->bunErrorData()); + + { + Locker locker { cellLock() }; diff --git a/patches/jsc_stub_dfg_abstract_heap.patch b/patches/jsc_stub_dfg_abstract_heap.patch new file mode 100644 index 00000000..d4027a2a --- /dev/null +++ b/patches/jsc_stub_dfg_abstract_heap.patch @@ -0,0 +1,23 @@ +diff --git a/webkit/Source/JavaScriptCore/domjit/DOMJITEffect.h b/webkit/Source/JavaScriptCore/domjit/DOMJITEffect.h +index 6ba85116d1..91c6f4dc26 100644 +--- a/webkit/Source/JavaScriptCore/domjit/DOMJITEffect.h ++++ b/webkit/Source/JavaScriptCore/domjit/DOMJITEffect.h +@@ -25,7 +25,18 @@ + + #pragma once + ++#if ENABLE(DFG_JIT) + #include "DFGAbstractHeap.h" ++#else ++namespace JSC { ++namespace DFG { ++enum AbstractHeapKind : unsigned { ++ Heap, ++ InvalidAbstractHeap ++}; ++} ++} ++#endif + #include "DOMJITHeapRange.h" + + WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN diff --git a/scripts/build-hash.js b/scripts/build-hash.js new file mode 100644 index 00000000..83aa879d --- /dev/null +++ b/scripts/build-hash.js @@ -0,0 +1,75 @@ +#!/usr/bin/env node + +const crypto = require('crypto'); +const fs = require('fs'); +const path = require('path'); + +const rootDir = process.cwd(); + +const includePaths = [ + 'package.json', + 'yarn.lock', + 'patches', + 'scripts', + 'lib', +]; + +const excludePatterns = [/^scripts\/publish\.js$/]; + +const hash = crypto.createHash('sha256'); + +function shouldInclude(relPath) { + if (relPath.includes('node_modules')) { + return false; + } + if (relPath.startsWith('.git')) { + return false; + } + return true; +} + +function shouldExclude(relPath) { + return excludePatterns.some((pattern) => pattern.test(relPath)); +} + +function addFile(filePath, relPath) { + const content = fs.readFileSync(filePath); + hash.update(relPath); + hash.update('\0'); + hash.update(content); +} + +function walk(currentPath, basePath) { + const entries = fs.readdirSync(currentPath).sort(); + entries.forEach((entry) => { + const absPath = path.join(currentPath, entry); + const relPath = path.relative(basePath, absPath).replace(/\\/g, '/'); + + if (!shouldInclude(relPath) || shouldExclude(relPath)) { + return; + } + + const stat = fs.statSync(absPath); + if (stat.isDirectory()) { + walk(absPath, basePath); + } else if (stat.isFile()) { + addFile(absPath, relPath); + } + }); +} + +includePaths.forEach((relativePath) => { + const relative = relativePath.replace(/\\/g, '/'); + const abs = path.join(rootDir, relative); + if (!fs.existsSync(abs)) { + return; + } + const stat = fs.statSync(abs); + if (stat.isDirectory()) { + walk(abs, rootDir); + } else if (stat.isFile()) { + addFile(abs, path.relative(rootDir, abs).replace(/\\/g, '/')); + } +}); + +process.stdout.write(hash.digest('hex')); diff --git a/scripts/compile/all.sh b/scripts/compile/all.sh index 1a6e29c0..5c5bc744 100755 --- a/scripts/compile/all.sh +++ b/scripts/compile/all.sh @@ -15,12 +15,14 @@ compile_arch() { } compile() { - for arch in arm x86 - do - export ANDROID_API=$ANDROID_API_FOR_ABI_32 - export JSC_ARCH=$arch - compile_arch - done + if [[ "${INCLUDE_32_BIT_ABIS:-0}" == "1" ]]; then + for arch in arm x86 + do + export ANDROID_API=$ANDROID_API_FOR_ABI_32 + export JSC_ARCH=$arch + compile_arch + done + fi for arch in arm64 x86_64 do diff --git a/scripts/compile/common.sh b/scripts/compile/common.sh index 7eb3b3d5..46e9c1eb 100755 --- a/scripts/compile/common.sh +++ b/scripts/compile/common.sh @@ -26,6 +26,7 @@ process_switch_options() { } if ! [[ $ROOTDIR ]]; then ROOTDIR=`pwd`; fi +source $ROOTDIR/scripts/toolchain.sh ARCH=$JSC_ARCH TARGETDIR=$ROOTDIR/build/target @@ -53,6 +54,7 @@ PLATFORM_CFLAGS_arm="" PLATFORM_LDFLAGS_arm="" JNI_ARCH_arm=armeabi-v7a +PLATFORM_CFLAGS_arm64="-mtune=cortex-a77" PLATFORM_LDFLAGS_arm64="" JNI_ARCH_arm64=arm64-v8a @@ -74,7 +76,7 @@ JNI_ARCH=${!var} # options flags # INTL -SWITCH_COMMON_CFLAGS_INTL_OFF="-DUCONFIG_NO_COLLATION=1 -DUCONFIG_NO_FORMATTING=1" +SWITCH_COMMON_CFLAGS_INTL_OFF="" SWITCH_BUILD_WEBKIT_OPTIONS_INTL_OFF="--no-intl" SWITCH_BUILD_WEBKIT_OPTIONS_INTL_ON="--intl" @@ -82,9 +84,10 @@ SWITCH_BUILD_WEBKIT_OPTIONS_INTL_ON="--intl" fix_zero_value_flag "INTL" process_switch_options "INTL" + # checks err=false -if ! [[ $ANDROID_API_FOR_ABI_32 ]]; then echo "set ANDROID_API_FOR_ABI_32 to the minimum supported Android platform version for arm and x86 (e.g. 16)"; err=true; fi +if [[ "${INCLUDE_32_BIT_ABIS:-0}" == "1" ]] && ! [[ $ANDROID_API_FOR_ABI_32 ]]; then echo "set ANDROID_API_FOR_ABI_32 to the minimum supported Android platform version for arm and x86 (e.g. 16)"; err=true; fi if ! [[ $ANDROID_API_FOR_ABI_64 ]]; then echo "set ANDROID_API_FOR_ABI_64 to the minimum supported Android platform version for arm64 and x86_64 (e.g. 21)"; err=true; fi if ! [[ $FLAVOR ]]; then echo "set FLAVOR to the name of the flavor"; err=true; fi if ! [[ $CROSS_COMPILE_PLATFORM ]]; then echo "set JSC_ARCH to one of {arm,arm64,x86,x86_64}"; err=true; fi @@ -99,8 +102,16 @@ DEBUG_SYMBOL_LEVEL="-g2" if [[ "$BUILD_TYPE" = "Release" ]] then FRAME_POINTER_FLAG="-fomit-frame-pointer" - CFLAGS_BUILD_TYPE="-DNDEBUG -g0 -Oz -flto=full" - ICU_CFLAGS_BUILD_TYPE="-Oz" + CFLAGS_BUILD_TYPE="-DNDEBUG -g0 -O2" + ICU_CFLAGS_BUILD_TYPE="-O2" + if [[ -n "$JSC_TOOLCHAIN_LTO_FLAG" ]]; then + CFLAGS_BUILD_TYPE="$CFLAGS_BUILD_TYPE $JSC_TOOLCHAIN_LTO_FLAG" + ICU_CFLAGS_BUILD_TYPE="$ICU_CFLAGS_BUILD_TYPE $JSC_TOOLCHAIN_LTO_FLAG" + fi + if [[ -n "$JSC_TOOLCHAIN_RELEASE_CFLAGS" ]]; then + CFLAGS_BUILD_TYPE="$CFLAGS_BUILD_TYPE $JSC_TOOLCHAIN_RELEASE_CFLAGS" + ICU_CFLAGS_BUILD_TYPE="$ICU_CFLAGS_BUILD_TYPE $JSC_TOOLCHAIN_RELEASE_CFLAGS" + fi else FRAME_POINTER_FLAG="-fno-omit-frame-pointer" CFLAGS_BUILD_TYPE="" @@ -117,6 +128,10 @@ COMMON_LDFLAGS=" \ -Wl,-z,max-page-size=16384 \ " +if [[ "$BUILD_TYPE" = "Release" && -n "$JSC_TOOLCHAIN_RELEASE_LDFLAGS" ]]; then + COMMON_LDFLAGS="$COMMON_LDFLAGS $JSC_TOOLCHAIN_RELEASE_LDFLAGS" +fi + COMMON_CFLAGS=" \ -fstack-protector \ -ffunction-sections \ @@ -133,13 +148,18 @@ $CFLAGS_BUILD_TYPE \ " COMMON_CXXFLAGS=" \ +-std=c++20 \ " ICU_CFLAGS="$COMMON_CFLAGS $PLATFORM_CFLAGS $ICU_CFLAGS_BUILD_TYPE" -ICU_CXXFLAGS="$COMMON_CXXFLAGS $ICU_CFLAGS $ICU_CFLAGS_BUILD_TYPE" +ICU_CXXFLAGS="$COMMON_CXXFLAGS $ICU_CFLAGS" ICU_LDFLAGS="$COMMON_LDFLAGS \ $PLATFORM_LDFLAGS \ " -JSC_LDFLAGS="$COMMON_LDFLAGS" +JSC_LDFLAGS="$COMMON_LDFLAGS -llog" JSC_CFLAGS="$COMMON_CFLAGS -Wno-implicit-const-int-float-conversion -DU_STATIC_IMPLEMENTATION=1 -DU_SHOW_CPLUSPLUS_API=0 -DTRUE=1 -DFALSE=0" + +if [[ -n "$JSC_VERSION" ]]; then + JSC_CFLAGS="$JSC_CFLAGS -DJSC_VERSION=\\\"${JSC_VERSION}\\\"" +fi diff --git a/scripts/compile/icu.sh b/scripts/compile/icu.sh index 1696958d..d96a15ce 100755 --- a/scripts/compile/icu.sh +++ b/scripts/compile/icu.sh @@ -26,8 +26,23 @@ else BUILD_TYPE_CONFIG="--enable-debug=yes" fi -ICU_DATA_FILTER_FILE="${TARGETDIR}/icu/filters/android.json" \ -$TARGETDIR/icu/source/configure --prefix=${INSTALL_DIR} \ +ICU_FILTER_FILE="${TARGETDIR}/icu/filters/android.json" +if [[ -f "$ICU_FILTER_FILE" ]]; then + echo "Using ICU data filter: ${ICU_FILTER_FILE}" + CONFIGURE_PREFIX=(env ICU_DATA_FILTER_FILE="$ICU_FILTER_FILE") +else + echo "ICU data filter not found at ${ICU_FILTER_FILE}; building without data pruning" + CONFIGURE_PREFIX=() +fi + +CC_BIN=$CROSS_COMPILE_PLATFORM_CC-clang +CXX_BIN=$CROSS_COMPILE_PLATFORM_CC-clang++ +if [[ -n "$JSC_CCACHE_BIN" ]]; then + CC_BIN="$JSC_CCACHE_BIN $CC_BIN" + CXX_BIN="$JSC_CCACHE_BIN $CXX_BIN" +fi + +"${CONFIGURE_PREFIX[@]}" $TARGETDIR/icu/source/configure --prefix=${INSTALL_DIR} \ $BUILD_TYPE_CONFIG \ --host=$CROSS_COMPILE_PLATFORM \ --enable-static=yes \ @@ -44,8 +59,8 @@ $TARGETDIR/icu/source/configure --prefix=${INSTALL_DIR} \ CFLAGS="$ICU_CFLAGS" \ CXXFLAGS="$ICU_CXXFLAGS" \ LDFLAGS="$ICU_LDFLAGS" \ - CC=$CROSS_COMPILE_PLATFORM_CC-clang \ - CXX=$CROSS_COMPILE_PLATFORM_CC-clang++ \ + CC="$CC_BIN" \ + CXX="$CXX_BIN" \ AR=$TOOLCHAIN_DIR/bin/llvm-ar \ LD=$TOOLCHAIN_DIR/bin/ld \ RANLIB=$TOOLCHAIN_DIR/bin/llvm-ranlib \ diff --git a/scripts/compile/jsc.sh b/scripts/compile/jsc.sh index d8eb4716..8abcd62a 100755 --- a/scripts/compile/jsc.sh +++ b/scripts/compile/jsc.sh @@ -6,24 +6,15 @@ source $SCRIPT_DIR/common.sh CMAKE_FOLDER=$(cd $ANDROID_HOME/cmake && ls -1 | sort -r | head -1) PATH=$TOOLCHAIN_DIR/bin:$ANDROID_HOME/cmake/$CMAKE_FOLDER/bin/:$PATH +CCACHE_CMAKE_ARGS="" +if [[ -n "$JSC_CCACHE_BIN" ]]; then + CCACHE_CMAKE_ARGS="-DCMAKE_C_COMPILER_LAUNCHER=${JSC_CCACHE_BIN} -DCMAKE_CXX_COMPILER_LAUNCHER=${JSC_CCACHE_BIN}" +fi + rm -rf $TARGETDIR/webkit/$CROSS_COMPILE_PLATFORM-${FLAVOR} rm -rf $TARGETDIR/webkit/WebKitBuild cd $TARGETDIR/webkit/Tools/Scripts -CMAKE_CXX_FLAGS=" \ -$SWITCH_JSC_CFLAGS_COMPAT \ -$JSC_CFLAGS \ -$PLATFORM_CFLAGS \ -" - -CMAKE_LD_FLAGS=" \ --latomic \ --lm \ --lc++_shared \ -$JSC_LDFLAGS \ -$PLATFORM_LDFLAGS \ -" - ARCH_NAME_PLATFORM_arm="armv7-a" ARCH_NAME_PLATFORM_arm64="aarch64" ARCH_NAME_PLATFORM_x86="i686" @@ -31,6 +22,13 @@ ARCH_NAME_PLATFORM_x86_64="x86_64" var="ARCH_NAME_PLATFORM_$JSC_ARCH" export ARCH_NAME=${!var} +BASE_C_FLAGS="$COMMON_CFLAGS $PLATFORM_CFLAGS" +BASE_CXX_FLAGS="$COMMON_CXXFLAGS $BASE_C_FLAGS" +BASE_LD_FLAGS="-latomic -lm -lc++_shared $JSC_LDFLAGS $PLATFORM_LDFLAGS" + +export CFLAGS="$BASE_C_FLAGS" +export CXXFLAGS="$BASE_CXX_FLAGS" +export LDFLAGS="$BASE_LD_FLAGS" if [[ "$BUILD_TYPE" = "Release" ]] then @@ -41,25 +39,17 @@ else BUILD_TYPE_FLAGS="-DDEBUG_FISSION=OFF" fi -if [[ "$ARCH_NAME" = "i686" ]] -then - JSC_FEATURE_FLAGS=" \ - -DENABLE_JIT=OFF \ - -DENABLE_C_LOOP=ON \ - " -else - JSC_FEATURE_FLAGS=" \ - -DENABLE_JIT=ON \ - -DENABLE_C_LOOP=OFF \ - " -fi +JSC_FEATURE_FLAGS=" \ + -DENABLE_JIT=OFF \ + -DENABLE_C_LOOP=ON \ + -DENABLE_WEBASSEMBLY=OFF \ +" $TARGETDIR/webkit/Tools/Scripts/build-webkit \ --jsc-only \ $BUILD_TYPE_CONFIG \ - --jit \ + --no-fatal-warnings \ "$SWITCH_BUILD_WEBKIT_OPTIONS_INTL" \ - --no-webassembly \ --no-xslt \ --no-netscape-plugin-api \ --no-tools \ @@ -67,16 +57,30 @@ $TARGETDIR/webkit/Tools/Scripts/build-webkit \ -DUSE_LD_GOLD=OFF \ -DANDROID_ABI=${JNI_ARCH} \ -DANDROID_PLATFORM=${ANDROID_API} \ + -DANDROID_TARGET_SDK_VERSION=${ANDROID_TARGET_API:-${ANDROID_API}} \ + -DENABLE_JIT=OFF \ + -DENABLE_WEBASSEMBLY=OFF \ -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH \ -DICU_ROOT=${TARGETDIR}/icu/${CROSS_COMPILE_PLATFORM}-${FLAVOR}/prebuilts \ - -DCMAKE_CXX_FLAGS='${CMAKE_CXX_FLAGS} $COMMON_CXXFLAGS $CMAKE_CXX_FLAGS' \ - -DCMAKE_C_FLAGS='${CMAKE_C_FLAGS} $CMAKE_CXX_FLAGS' \ - -DCMAKE_C_FLAGS_DEBUG='${DEBUG_SYMBOL_LEVEL}' \ - -DCMAKE_CXX_FLAGS_DEBUG='${DEBUG_SYMBOL_LEVEL}' \ - -DCMAKE_SHARED_LINKER_FLAGS='${CMAKE_SHARED_LINKER_FLAGS} $CMAKE_LD_FLAGS' \ - -DCMAKE_EXE_LINKER_FLAGS='${CMAKE_MODULE_LINKER_FLAGS} $CMAKE_LD_FLAGS' \ + -DICU_INCLUDE_DIR=${TARGETDIR}/icu/${CROSS_COMPILE_PLATFORM}-${FLAVOR}/prebuilts/include \ + -DENABLE_API_TESTS=OFF \ + -DCMAKE_C_FLAGS=\"$BASE_C_FLAGS\" \ + -DCMAKE_CXX_FLAGS=\"$BASE_CXX_FLAGS\" \ + -DCMAKE_C_FLAGS_RELEASE=\"$BASE_C_FLAGS\" \ + -DCMAKE_CXX_FLAGS_RELEASE=\"$BASE_CXX_FLAGS\" \ + -DCMAKE_C_FLAGS_RELWITHDEBINFO=\"$BASE_C_FLAGS\" \ + -DCMAKE_CXX_FLAGS_RELWITHDEBINFO=\"$BASE_CXX_FLAGS\" \ + -DCMAKE_C_FLAGS_DEBUG=\"$BASE_C_FLAGS $DEBUG_SYMBOL_LEVEL\" \ + -DCMAKE_CXX_FLAGS_DEBUG=\"$BASE_CXX_FLAGS $DEBUG_SYMBOL_LEVEL\" \ + -DCMAKE_SHARED_LINKER_FLAGS=\"$BASE_LD_FLAGS\" \ + -DCMAKE_MODULE_LINKER_FLAGS=\"$BASE_LD_FLAGS\" \ + -DCMAKE_EXE_LINKER_FLAGS=\"$BASE_LD_FLAGS\" \ + -DCMAKE_CXX_STANDARD=20 \ + -DCMAKE_CXX_STANDARD_REQUIRED=ON \ + -DCMAKE_CXX_EXTENSIONS=OFF \ -DCMAKE_VERBOSE_MAKEFILE=on \ + $CCACHE_CMAKE_ARGS \ -DENABLE_API_TESTS=OFF \ -DENABLE_SAMPLING_PROFILER=OFF \ -DENABLE_DFG_JIT=OFF \ @@ -89,9 +93,16 @@ $TARGETDIR/webkit/Tools/Scripts/build-webkit \ mkdir -p $INSTALL_UNSTRIPPED_DIR_I18N/$JNI_ARCH mkdir -p $INSTALL_DIR_I18N/$JNI_ARCH -cp $TARGETDIR/webkit/WebKitBuild/$BUILD_TYPE/lib/libjsc.so $INSTALL_UNSTRIPPED_DIR_I18N/$JNI_ARCH -cp $TARGETDIR/webkit/WebKitBuild/$BUILD_TYPE/lib/libjsc.so $INSTALL_DIR_I18N/$JNI_ARCH -$TOOLCHAIN_DIR/bin/llvm-strip $INSTALL_DIR_I18N/$JNI_ARCH/libjsc.so +BUILT_LIB_PATH=$TARGETDIR/webkit/WebKitBuild/JSCOnly/$BUILD_TYPE/lib/libJavaScriptCore.so +OUTPUT_LIB_NAME=libjsc.so +if [[ ! -f $BUILT_LIB_PATH ]] +then + echo "Failed to find expected JavaScriptCore shared library at $BUILT_LIB_PATH" >&2 + exit 1 +fi +cp $BUILT_LIB_PATH $INSTALL_UNSTRIPPED_DIR_I18N/$JNI_ARCH/$OUTPUT_LIB_NAME +cp $BUILT_LIB_PATH $INSTALL_DIR_I18N/$JNI_ARCH/$OUTPUT_LIB_NAME +$TOOLCHAIN_DIR/bin/llvm-strip $INSTALL_DIR_I18N/$JNI_ARCH/$OUTPUT_LIB_NAME mv $TARGETDIR/webkit/WebKitBuild $TARGETDIR/webkit/${CROSS_COMPILE_PLATFORM}-${FLAVOR} mkdir -p $INSTALL_CPPRUNTIME_DIR/$JNI_ARCH diff --git a/scripts/download.sh b/scripts/download.sh index e0b92980..d94fa9eb 100755 --- a/scripts/download.sh +++ b/scripts/download.sh @@ -1,13 +1,40 @@ #!/bin/bash -e +ROOTDIR=$PWD + # download sources -rm -rf $PWD/build -TARGET_DIR=$PWD/build/download -REPO_URL="https://github.com/WebKit/WebKit.git" +rm -rf "$ROOTDIR/build" +TARGET_DIR="$ROOTDIR/build/download" +WEBKIT_DIR="$TARGET_DIR/webkit" + +REPO_URL="${npm_package_config_bunWebKitRepo:-https://github.com/oven-sh/WebKit.git}" +WEBKIT_COMMIT="${npm_package_config_bunWebKitCommit}" +ICU_RELEASE="${npm_package_config_icuRelease}" +ICU_ARCHIVE="${npm_package_config_icuArchive}" + +if [[ -z "$WEBKIT_COMMIT" ]]; then + echo "Missing bunWebKitCommit in package.json config." >&2 + exit 1 +fi + +mkdir -p "$TARGET_DIR" +mkdir -p "$WEBKIT_DIR" -mkdir -p $TARGET_DIR -# FIXME: hardcoded branch because WebKitGTK 2.26 does not have tag -git clone $REPO_URL --branch 'webkitgtk/2.26' --depth 1 $TARGET_DIR/webkit +pushd "$WEBKIT_DIR" > /dev/null +git init +git remote add origin "$REPO_URL" +git fetch --depth 1 origin "$WEBKIT_COMMIT" +git checkout --detach FETCH_HEAD +popd > /dev/null -mkdir -p $TARGET_DIR/icu -curl "https://chromium.googlesource.com/chromium/deps/icu/+archive/${npm_package_config_chromiumICUCommit}.tar.gz" | tar xzf - -C $TARGET_DIR/icu +mkdir -p "$TARGET_DIR/icu" +if [[ -n "$ICU_RELEASE" ]]; then + if [[ -z "$ICU_ARCHIVE" ]]; then + echo "Missing icuArchive for release ${ICU_RELEASE}" >&2 + exit 1 + fi + curl -L "https://github.com/unicode-org/icu/releases/download/${ICU_RELEASE}/${ICU_ARCHIVE}" | tar xzf - --strip-components=1 -C "$TARGET_DIR/icu" +else + echo "No ICU release configured for download." >&2 + exit 1 +fi diff --git a/scripts/env.sh b/scripts/env.sh index b5779e7c..ee88d028 100644 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -2,17 +2,22 @@ export ROOTDIR=$PWD +BUILD_VARIANT_SUFFIX="" +if [[ -n "$JSC_BUILD_VARIANT" ]]; then + BUILD_VARIANT_SUFFIX="-$JSC_BUILD_VARIANT" +fi + # Intermediated build target dir -export TARGETDIR=$ROOTDIR/build/target +export TARGETDIR=${TARGETDIR:-$ROOTDIR/build/target${BUILD_VARIANT_SUFFIX}} # JSC shared library install dir -export INSTALL_DIR=$ROOTDIR/build/compiled +export INSTALL_DIR=${INSTALL_DIR:-$ROOTDIR/build/compiled${BUILD_VARIANT_SUFFIX}} # JSC unstripped shared library install dir -export INSTALL_UNSTRIPPED_DIR=$ROOTDIR/build/compiled.unstripped +export INSTALL_UNSTRIPPED_DIR=${INSTALL_UNSTRIPPED_DIR:-$ROOTDIR/build/compiled.unstripped${BUILD_VARIANT_SUFFIX}} # CPP runtime shared library install dir -export INSTALL_CPPRUNTIME_DIR=$ROOTDIR/build/cppruntime +export INSTALL_CPPRUNTIME_DIR=${INSTALL_CPPRUNTIME_DIR:-$ROOTDIR/build/cppruntime${BUILD_VARIANT_SUFFIX}} # Install dir for i18n build variants export INSTALL_DIR_I18N_true=$INSTALL_DIR/intl diff --git a/scripts/info.sh b/scripts/info.sh index fdf737c4..2bd19efd 100755 --- a/scripts/info.sh +++ b/scripts/info.sh @@ -1,24 +1,41 @@ #!/bin/bash -e -WEBKITGTK_VERSION="${npm_package_config_webkitGTK}" -# URL="https://github.com/WebKit/WebKit/tree/webkitgtk-${WEBKITGTK_VERSION}" -# FIXME: hardcoded branch because WebKitGTK 2.26 does not have tag -URL="https://github.com/WebKit/WebKit/tree/webkitgtk/2.26" -RAW_URL="https://raw.githubusercontent.com/WebKit/WebKit/refs/heads/webkitgtk/2.26" ROOTDIR=$PWD +WEBKIT_REPO="${npm_package_config_bunWebKitRepo:-https://github.com/oven-sh/WebKit.git}" +WEBKIT_COMMIT="${npm_package_config_bunWebKitCommit}" + +export JSC_TOOLCHAIN_SUPPRESS_LOG=1 +source $ROOTDIR/scripts/toolchain.sh +unset JSC_TOOLCHAIN_SUPPRESS_LOG + export REVISION=$(node -e "console.log(require('./package.json').version.split('.')[0])") -CONFIG=$(node -e "console.log(require('$ROOTDIR/package.json').config)") -APPLE_VERSION=$(wget -q -O - "${RAW_URL}/Source/WebCore/Configurations/Version.xcconfig" | grep 'MAJOR_VERSION\s=\|MINOR_VERSION\s=\|TINY_VERSION\s=\|MICRO_VERSION\s=\|NANO_VERSION\s=') +CONFIG=$(node -e "console.log(JSON.stringify(require('$ROOTDIR/package.json').config, null, 2))") + +if [[ -n "$WEBKIT_COMMIT" ]]; then + WEBKIT_URL="https://github.com/oven-sh/WebKit/tree/${WEBKIT_COMMIT}" + RAW_URL="https://raw.githubusercontent.com/oven-sh/WebKit/${WEBKIT_COMMIT}" + APPLE_VERSION=$(curl -fsSL "${RAW_URL}/Configurations/Version.xcconfig" | grep 'MAJOR_VERSION\s=\|MINOR_VERSION\s=\|TINY_VERSION\s=\|MICRO_VERSION\s=\|NANO_VERSION\s=' || true) +else + WEBKIT_URL="$WEBKIT_REPO" + APPLE_VERSION="unknown" +fi if [ -d "$INSTALL_DIR_I18N_false" ]; then - SIZE=$(du -ah $INSTALL_DIR_I18N_false) + SIZE=$(du -ah "$INSTALL_DIR_I18N_false") else SIZE="0" fi printf "\n\n\n\n\n\t\t\tRevision: \x1B[32m$REVISION\x1B[0m\n\n\n" -printf "WebKitGTK version:\n$WEBKITGTK_VERSION\n\n" -printf "Config:\n$CONFIG\n\n" -printf "AppleWebkit:\n$APPLE_VERSION\n\n" +printf "WebKit repository:\n%s @ %s\n\n" "$WEBKIT_REPO" "${WEBKIT_COMMIT:-unknown}" +printf "Upstream URL:\n%s\n\n" "$WEBKIT_URL" +printf "Config:\n%s\n\n" "$CONFIG" +printf "NDK variant: %s\n" "${JSC_TOOLCHAIN_VARIANT:-unknown}" +if [[ -n "$JSC_TOOLCHAIN_NDK_REVISION" ]]; then + printf "NDK revision: %s\n\n" "$JSC_TOOLCHAIN_NDK_REVISION" +else + printf "\n" +fi +printf "AppleWebKit version components:\n%s\n\n" "$APPLE_VERSION" printf "Size:\n$SIZE\n\n" diff --git a/scripts/patch.sh b/scripts/patch.sh index 82178529..9452ca5d 100755 --- a/scripts/patch.sh +++ b/scripts/patch.sh @@ -9,51 +9,60 @@ ICU_PATCHSET=( ) JSC_PATCHSET=( - # Basic build setup, e.g. libjsc.so output name - "jsc.patch" + # Android-specific logging for version identification + "jsc_android_log_version.patch" - # Feature toggles, e.g. disable unnecessary build or JIT settings - "jsc_features.patch" + # Ensure PRIu64 fallback matches 64-bit width on Android builds + "jsc_android_uv_pri64.patch" - # NDK does not support backtrace and execinfo.h - "jsc_fix_build_error_execinfo.patch" + # Fix Collator stub implementation for builds without ICU collation + "jsc_android_collator_static.patch" - # Fix build error which related to C++StringView - "jsc_fix_build_error_stringview.patch" + # Provide defaults for Bun-specific macros on non-Bun platforms + "jsc_android_define_bun_macros.patch" - # Integrate with Chromium ICU - "jsc_icu_integrate.patch" + # Update TestWTF to match new ExternalStringImpl signature + "jsc_fix_external_string_tests.patch" - # Support getting correct locale setting in Android system - "jsc_locale_support.patch" + # Disable building TestWebKitAPI when consuming JSC only + "jsc_disable_api_tests.patch" - # Will print current JSC version in adb log during initialization - "jsc_startup_log_version.patch" + # Provide stubs for DFG abstract heap when DFG JIT is disabled + "jsc_stub_dfg_abstract_heap.patch" - # Misc errors - "jsc_fix_build_error_miss_headers.patch" + # Guard async frame helper when Bun additions disabled + "jsc_async_frame_guard.patch" - # Workaround JIT crash on arm64, especially for Saumsung S7 Edge - "jsc_fix_arm64_jit_crash.patch" + # Guard Bun-specific error helpers when Bun additions are disabled + "jsc_guard_error_instance.patch" - # Intl default timezone with Android integration - "jsc_intl_timezone.patch" + # Silence unused parameter warnings in modules and promise helpers + "jsc_android_silence_unused.patch" - # Improve heap GC mechanism like iOS - "jsc_heap_gc_like_ios.patch" + # Include Android-specific WTF sources for logging and real-time threads + "jsc_android_wtf_sources.patch" - # GC concurrent issue potential fix - # https://trac.webkit.org/changeset/251307/webkit - "jsc_fix_concurrent_gc_issue.patch" -) + # Avoid unused-result warning in CLI wait helper + "jsc_android_jsc_wait.patch" -if [[ "$I18N" = false ]] -then - JSC_PATCHSET+=( - # Disable i18n for non-i18n build - "jsc_disable_icu.patch" - ) -fi + # Guard JIT helpers when DFG/WebAssembly are disabled + "jsc_android_jit_guards.patch" + + # Avoid ICU formatting dependencies when validating time zones + "jsc_android_timezone_validate.patch" + + # Force Android builds to use C++20 and drop toolchain -O3 defaults + "jsc_android_release_flags.patch" + + # Avoid pthread_getname_np usage on Android where it's unavailable + "jsc_android_thread_name_guard.patch" + + # Use posix_memalign when aligned_alloc is missing on older Android + "jsc_android_systemheap_posix_memalign.patch" + + # Use legacy system property getter on older Android + "jsc_android_logging_property.patch" +) ###################################################################################### # Patchset management end diff --git a/scripts/publish.js b/scripts/publish.js index b8f23a7c..9a51d269 100755 --- a/scripts/publish.js +++ b/scripts/publish.js @@ -10,8 +10,8 @@ const path = require('path'); const rimraf = require('rimraf'); const semver = require('semver'); -if (!semver.satisfies(process.versions.node, '>= 10.12.0')) { - console.log('Please execute this script with node version >= 10.12.0'); +if (!semver.satisfies(process.versions.node, '>= 16.7.0')) { + console.log('Please execute this script with node version >= 16.7.0'); process.exit(1); } @@ -21,79 +21,145 @@ commander .option('--dry-run', 'Dry run mode for npm publish') .parse(process.argv); -const artifactZipFile = verifyFile(commander.args[0], ''); +const artifactInput = resolveArtifactPath(commander.args[0], ''); const rootDir = path.dirname(__dirname); +const pkgJsonPath = path.join(rootDir, 'package.json'); +const packageTemplate = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8')); const workDir = path.join(rootDir, 'build', 'publish'); const distDir = path.join(rootDir, 'dist'); + if (fs.existsSync(workDir)) { rimraf.sync(workDir); } fs.mkdirSync(workDir, {recursive: true}); -child_process.execFileSync('unzip', [artifactZipFile, '-d', workDir]); +if (artifactInput.isDirectory) { + fs.cpSync(artifactInput.path, workDir, {recursive: true}); +} else { + child_process.execFileSync('unzip', [artifactInput.path, '-d', workDir]); +} -// Publish standard package -console.log('\n\n========== Publish standard package =========='); -createPatchedContext(rootDir, '', () => { - if (fs.existsSync(distDir)) { - rimraf.sync(distDir); - } - fs.renameSync(path.join(workDir, 'dist'), distDir); - const publishArgs = ['publish', '--tag', commander.tag]; - if (commander.dryRun) { - publishArgs.push('--dry-run'); - } - child_process.execFileSync('npm', publishArgs); -}); +const variantList = Array.isArray(packageTemplate.config?.ndkVariants) + ? packageTemplate.config.ndkVariants + : []; -// Publish unstripped package -// 1. Add suffix in version, e.g. 245459.0.0-unstripped -// 2. Add suffix in tag, e.g. latest-unstripped -// 3. Get unstripped distribution from dist.unstripped/ in CI archive.zip -console.log('\n\n========== Publish unstripped package =========='); -createPatchedContext(rootDir, 'unstripped', () => { - if (fs.existsSync(distDir)) { - rimraf.sync(distDir); - } - fs.renameSync(path.join(workDir, 'dist.unstripped'), distDir); - const publishArgs = ['publish', '--tag', `${commander.tag}-unstripped`]; - if (commander.dryRun) { - publishArgs.push('--dry-run'); - } - child_process.execFileSync('npm', publishArgs); +const variants = + variantList.length > 0 + ? [...variantList].sort((a, b) => { + const aDefault = a && a.default ? 1 : 0; + const bDefault = b && b.default ? 1 : 0; + return bDefault - aDefault; + }) + : [ + { + id: 'default', + npmPackage: packageTemplate.name, + distDir: 'dist', + distUnstrippedDir: 'dist.unstripped', + }, + ]; + +variants.forEach((variant) => { + publishVariant(variant); }); // --------------------------------------------------------------------------- // Helper functions // --------------------------------------------------------------------------- -function verifyFile(filePath, argName) { - if (filePath == null) { +function publishVariant(variant) { + const displayName = variant?.id || 'default'; + console.log(`\n\n========== Publish ${displayName} package ==========`); // eslint-disable-line no-console + + publishVariantFlavor(variant, { + sourceDirName: variant.distDir || 'dist', + versionSuffix: '', + tagSuffix: '', + }); + + publishVariantFlavor(variant, { + sourceDirName: variant.distUnstrippedDir || 'dist.unstripped', + versionSuffix: 'unstripped', + tagSuffix: '-unstripped', + }); +} + +function publishVariantFlavor(variant, {sourceDirName, versionSuffix, tagSuffix}) { + if (!sourceDirName) { + return; + } + + const sourceDir = path.join(workDir, sourceDirName); + if (!fs.existsSync(sourceDir)) { + console.warn( + `Skipping ${variant?.id || 'default'}${tagSuffix ? ` (${tagSuffix.replace('-', '')})` : ''} - missing directory ${sourceDirName}`, + ); + return; + } + + createPatchedContext(rootDir, {variant, versionSuffix}, () => { + if (fs.existsSync(distDir)) { + rimraf.sync(distDir); + } + copyDir(sourceDir, distDir); + const publishTag = tagSuffix ? `${commander.tag}${tagSuffix}` : commander.tag; + const publishArgs = ['publish', '--tag', publishTag]; + if (commander.dryRun) { + publishArgs.push('--dry-run'); + } + child_process.execFileSync('npm', publishArgs, {stdio: 'inherit'}); + }); +} + +function copyDir(source, destination) { + fs.mkdirSync(path.dirname(destination), {recursive: true}); + fs.cpSync(source, destination, {recursive: true, force: true}); +} + +function resolveArtifactPath(inputPath, argName) { + if (inputPath == null) { console.error(`Error: ${argName} is required`); process.exit(1); } + const resolvedPath = path.resolve(process.cwd(), inputPath); let stat; try { - stat = fs.lstatSync(filePath); + stat = fs.lstatSync(resolvedPath); } catch (error) { console.error(error.toString()); process.exit(1); } - if (!stat.isFile()) { - console.error(`Error: ${argName} is not a regular file`); + if (!stat.isDirectory() && !stat.isFile()) { + console.error(`Error: ${argName} must be a directory or zip file`); process.exit(1); } - return filePath; + return {path: resolvedPath, isDirectory: stat.isDirectory()}; } -function createPatchedContext(rootDir, versionSuffix, wrappedRunner) { +function createPatchedContext(rootDir, options, wrappedRunner) { + const {versionSuffix, variant} = options || {}; const configPath = path.join(rootDir, 'package.json'); const origConfig = fs.readFileSync(configPath); function enter() { const patchedConfig = JSON.parse(origConfig); + if (variant) { + if (variant.npmPackage) { + patchedConfig.name = variant.npmPackage; + } + patchedConfig.config = patchedConfig.config || {}; + if (variant.id) { + patchedConfig.config.selectedNdkVariant = variant.id; + } + if (variant.npmPackage) { + patchedConfig.config.selectedNdkPackage = variant.npmPackage; + } + if (variant.distDir) { + patchedConfig.config.selectedNdkDistDir = variant.distDir; + } + } if (versionSuffix) { patchedConfig.version += '-' + versionSuffix; } diff --git a/scripts/start.sh b/scripts/start.sh index f03eb65c..70fcc4cb 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -2,14 +2,56 @@ export ANDROID_API_FOR_ABI_32=24 export ANDROID_API_FOR_ABI_64=24 +export ANDROID_TARGET_API=35 export ROOTDIR=$PWD +# Default toolchain locations when not provided. +DEFAULT_ANDROID_HOME="$HOME/Library/Android/sdk" +if [[ -z "$ANDROID_HOME" || ! -d "$ANDROID_HOME" ]]; then + export ANDROID_HOME="$DEFAULT_ANDROID_HOME" +fi + +DEFAULT_ANDROID_NDK="$ANDROID_HOME/ndk/28.2.13676358" +if [[ -z "$ANDROID_NDK" || ! -d "$ANDROID_NDK" ]]; then + export ANDROID_NDK="$DEFAULT_ANDROID_NDK" +fi + +export JSC_TOOLCHAIN_SUPPRESS_LOG=1 +source $ROOTDIR/scripts/toolchain.sh +unset JSC_TOOLCHAIN_SUPPRESS_LOG + +if [[ -z "$JAVA_HOME" || ! -x "$JAVA_HOME/bin/java" ]]; then + if [[ "$(uname -s)" == "Darwin" ]]; then + if command -v brew >/dev/null 2>&1; then + HOMEBREW_JAVA_ROOT="$(brew --prefix openjdk@17 2>/dev/null)/libexec/openjdk.jdk/Contents/Home" + if [[ -x "$HOMEBREW_JAVA_ROOT/bin/java" ]]; then + export JAVA_HOME="$HOMEBREW_JAVA_ROOT" + fi + fi + fi +fi + +if [[ -n "$JAVA_HOME" && -x "$JAVA_HOME/bin/java" ]]; then + export PATH="$JAVA_HOME/bin:$PATH" +fi + source $ROOTDIR/scripts/env.sh source $ROOTDIR/scripts/info.sh export JSC_VERSION=${npm_package_version} export BUILD_TYPE=Release # export BUILD_TYPE=Debug +STRIPPED_DIST_DIR=${JSC_DIST_DIR:-${ROOTDIR}/dist-ndk28} +UNSTRIPPED_DIST_DIR=${JSC_DIST_UNSTRIPPED_DIR:-${ROOTDIR}/dist-ndk28.unstripped} + +printf "Building with Android NDK variant: %s\n" "${JSC_TOOLCHAIN_VARIANT}" +if [[ -n "$JSC_TOOLCHAIN_NDK_REVISION" ]]; then + printf "Detected Android NDK revision: %s\n" "${JSC_TOOLCHAIN_NDK_REVISION}" +fi +printf "Using distribution directories:\n" +printf " stripped : %s\n" "$STRIPPED_DIST_DIR" +printf " unstripped : %s\n" "$UNSTRIPPED_DIST_DIR" + SCRIPT_DIR=$(cd `dirname $0`; pwd) patchAndMakeICU() { @@ -17,27 +59,80 @@ patchAndMakeICU() { ICU_VERSION_MAJOR="$(awk '/ICU_VERSION_MAJOR_NUM/ {print $3}' $TARGETDIR/icu/source/common/unicode/uvernum.h)" printf "ICU version: ${ICU_VERSION_MAJOR}\n" $SCRIPT_DIR/patch.sh icu - rm -rf $TARGETDIR/icu/host mkdir -p $TARGETDIR/icu/host cd $TARGETDIR/icu/host + local HAS_CLANG=0 + if command -v clang >/dev/null 2>&1 && command -v clang++ >/dev/null 2>&1; then + HAS_CLANG=1 + fi + if [[ "$BUILD_TYPE" = "Release" ]] then - CFLAGS="-Os" + local opt_flags="-O2" + local lto_flag="" + if [[ $HAS_CLANG -eq 1 ]]; then + lto_flag="$JSC_TOOLCHAIN_LTO_FLAG" + elif [[ -n "$JSC_TOOLCHAIN_LTO_FLAG" ]]; then + lto_flag="-flto" + fi + if [[ -n "$lto_flag" ]]; then + opt_flags="$opt_flags $lto_flag" + fi + if [[ -n "$JSC_TOOLCHAIN_RELEASE_CFLAGS" ]]; then + opt_flags="$opt_flags $JSC_TOOLCHAIN_RELEASE_CFLAGS" + fi + + CFLAGS="$opt_flags" + CXXFLAGS="-std=c++20 $opt_flags" + + local ldflags="$JSC_TOOLCHAIN_RELEASE_LDFLAGS" + if [[ $HAS_CLANG -eq 0 && "$ldflags" == "-flto=thin" ]]; then + ldflags="-flto" + fi + LDFLAGS="$ldflags" else CFLAGS="-g2" + CXXFLAGS="-std=c++20" + LDFLAGS="" + fi + + ICU_FILTER_FILE="${TARGETDIR}/icu/filters/android.json" + local CONFIG_ENV=(env "CFLAGS=$CFLAGS" "CXXFLAGS=$CXXFLAGS") + if [[ -n "$LDFLAGS" ]]; then + CONFIG_ENV+=("LDFLAGS=$LDFLAGS") + fi + if [[ $HAS_CLANG -eq 1 ]]; then + local cc_cmd="clang" + local cxx_cmd="clang++" + if [[ -n "$JSC_CCACHE_BIN" ]]; then + cc_cmd="$JSC_CCACHE_BIN clang" + cxx_cmd="$JSC_CCACHE_BIN clang++" + fi + CONFIG_ENV+=("CC=$cc_cmd" "CXX=$cxx_cmd") fi - ICU_DATA_FILTER_FILE="${TARGETDIR}/icu/filters/android.json" \ - $TARGETDIR/icu/source/runConfigureICU Linux \ - --prefix=$PWD/prebuilts \ - CFLAGS="$CFLAGS" \ - CXXFLAGS="--std=c++11" \ - --disable-tests \ - --disable-samples \ - --disable-layout \ - --disable-layoutex + if [[ -f "$ICU_FILTER_FILE" ]]; then + printf "Using ICU data filter: %s\n" "$ICU_FILTER_FILE" + ICU_DATA_FILTER_FILE="$ICU_FILTER_FILE" \ + "${CONFIG_ENV[@]}" \ + $TARGETDIR/icu/source/runConfigureICU Linux \ + --prefix=$PWD/prebuilts \ + --disable-tests \ + --disable-samples \ + --disable-layout \ + --disable-layoutex + else + printf "ICU data filter not found at %s, building without data pruning\n" "$ICU_FILTER_FILE" + "${CONFIG_ENV[@]}" \ + $TARGETDIR/icu/source/runConfigureICU Linux \ + --prefix=$PWD/prebuilts \ + --disable-tests \ + --disable-samples \ + --disable-layout \ + --disable-layoutex + fi make -j5 cd $ROOTDIR @@ -98,23 +193,27 @@ copyHeaders() { cp -Rf $TARGETDIR/webkit/Source/JavaScriptCore/API/*.h ${distDir}/include } -export I18N=false -prep -compile +if [[ "${SKIP_NO_INTL}" != "1" ]]; then + export I18N=false + prep + compile +fi -export I18N=true -prep -compile +if [[ "${SKIP_INTL}" != "1" ]]; then + export I18N=true + prep + compile +fi printf "\n\n\t\t===================== create stripped distributions =====================\n\n" -export DISTDIR=${ROOTDIR}/dist +export DISTDIR=${STRIPPED_DIST_DIR} copyHeaders ${DISTDIR} createAAR "jsc-android" ${DISTDIR} ${INSTALL_DIR_I18N_false} "false" createAAR "jsc-android" ${DISTDIR} ${INSTALL_DIR_I18N_true} "true" createAAR "cppruntime" ${DISTDIR} ${INSTALL_CPPRUNTIME_DIR} "false" printf "\n\n\t\t===================== create unstripped distributions =====================\n\n" -export DISTDIR=${ROOTDIR}/dist.unstripped +export DISTDIR=${UNSTRIPPED_DIST_DIR} copyHeaders ${DISTDIR} createAAR "jsc-android" ${DISTDIR} ${INSTALL_UNSTRIPPED_DIR_I18N_false} "false" createAAR "jsc-android" ${DISTDIR} ${INSTALL_UNSTRIPPED_DIR_I18N_true} "true" diff --git a/scripts/toolchain.sh b/scripts/toolchain.sh new file mode 100644 index 00000000..e4571631 --- /dev/null +++ b/scripts/toolchain.sh @@ -0,0 +1,193 @@ +#!/bin/bash + +if [[ "${JSC_TOOLCHAIN_CONFIGURED:-0}" == "1" ]]; then + return +fi +export JSC_TOOLCHAIN_CONFIGURED=1 + +if ! [[ $ROOTDIR ]]; then + ROOTDIR=$(pwd) +fi + +ANDROID_NDK_PATH="${ANDROID_NDK:-}" +SOURCE_PROPERTIES_PATH="" +if [[ -n "$ANDROID_NDK_PATH" && -f "$ANDROID_NDK_PATH/source.properties" ]]; then + SOURCE_PROPERTIES_PATH="$ANDROID_NDK_PATH/source.properties" +fi + +VARIANT_OVERRIDE="${JSC_NDK_VARIANT:-}" + +variant_output=$(node /dev/stdin "$ROOTDIR" "$VARIANT_OVERRIDE" "$SOURCE_PROPERTIES_PATH" <<'NODE' +const fs = require('fs'); +const path = require('path'); + +const rootDir = process.argv[2]; +const variantOverride = process.argv[3] || ''; +const sourcePropertiesPath = process.argv[4]; + +const pkg = require(path.join(rootDir, 'package.json')); +const variants = Array.isArray(pkg.config?.ndkVariants) + ? pkg.config.ndkVariants + : []; + +const defaultVariant = + variants.find((variant) => variant && variant.default) || + variants[0] || + null; + +let revision = ''; +if (sourcePropertiesPath && fs.existsSync(sourcePropertiesPath)) { + const contents = fs.readFileSync(sourcePropertiesPath, 'utf8'); + const match = contents.match(/Pkg\.Revision\s*=\s*([^\s]+)/); + if (match) { + revision = match[1].trim(); + } +} + +const matchRevision = (variant) => { + if (!revision || !variant) { + return false; + } + const prefixes = Array.isArray(variant.pkgRevisionPrefixes) + ? variant.pkgRevisionPrefixes + : []; + return prefixes.some((prefix) => revision.startsWith(prefix)); +}; + +let variant = + (variantOverride && variants.find((variant) => variant.id === variantOverride)) || + variants.find(matchRevision) || + defaultVariant || + null; + +const emit = (line) => { + if (line !== undefined && line !== null) { + console.log(line); + } +}; + +if (revision) { + emit(`JSC_TOOLCHAIN_NDK_REVISION=${revision}`); +} + +if (defaultVariant) { + emit(`JSC_TOOLCHAIN_DEFAULT_VARIANT=${defaultVariant.id}`); + if (defaultVariant.npmPackage) { + emit(`JSC_TOOLCHAIN_DEFAULT_NPM_PACKAGE=${defaultVariant.npmPackage}`); + } + if (defaultVariant.distDir) { + emit(`JSC_TOOLCHAIN_DEFAULT_DIST_DIR=${defaultVariant.distDir}`); + } + if (defaultVariant.distUnstrippedDir) { + emit(`JSC_TOOLCHAIN_DEFAULT_DIST_UNSTRIPPED_DIR=${defaultVariant.distUnstrippedDir}`); + } +} + +if (variant) { + emit(`JSC_TOOLCHAIN_VARIANT=${variant.id}`); + if (variant.npmPackage) { + emit(`JSC_TOOLCHAIN_VARIANT_PACKAGE=${variant.npmPackage}`); + } + const buildSuffix = + variant.hasOwnProperty('buildSuffix') + ? String(variant.buildSuffix ?? '') + : defaultVariant && variant.id === defaultVariant.id + ? '' + : variant.id; + emit(`JSC_TOOLCHAIN_VARIANT_BUILD_SUFFIX=${buildSuffix}`); + if (variant.distDir) { + emit(`JSC_TOOLCHAIN_VARIANT_DIST_DIR=${variant.distDir}`); + } + if (variant.distUnstrippedDir) { + emit(`JSC_TOOLCHAIN_VARIANT_DIST_UNSTRIPPED_DIR=${variant.distUnstrippedDir}`); + } + emit( + `JSC_TOOLCHAIN_VARIANT_DISABLE_LOOP_VECTORIZATION=${variant.disableLoopVectorization ? 1 : 0}`, + ); + emit( + `JSC_TOOLCHAIN_VARIANT_ENABLE_THIN_LTO=${variant.enableThinLTO === false ? 0 : 1}`, + ); +} else { + emit('JSC_TOOLCHAIN_VARIANT='); + emit('JSC_TOOLCHAIN_VARIANT_BUILD_SUFFIX='); + emit('JSC_TOOLCHAIN_VARIANT_DIST_DIR='); + emit('JSC_TOOLCHAIN_VARIANT_DIST_UNSTRIPPED_DIR='); + emit('JSC_TOOLCHAIN_VARIANT_DISABLE_LOOP_VECTORIZATION=0'); + emit('JSC_TOOLCHAIN_VARIANT_ENABLE_THIN_LTO=1'); +} +NODE +) +ret=$? +if [[ $ret -ne 0 ]]; then + echo "Failed to read NDK variant configuration" 1>&2 + exit $ret +fi + +eval "$variant_output" + +if [[ -z "$JSC_TOOLCHAIN_VARIANT" ]]; then + if [[ -n "$JSC_TOOLCHAIN_DEFAULT_VARIANT" ]]; then + export JSC_TOOLCHAIN_VARIANT="$JSC_TOOLCHAIN_DEFAULT_VARIANT" + else + export JSC_TOOLCHAIN_VARIANT=unknown + fi +fi + +if [[ -n "$JSC_TOOLCHAIN_VARIANT_BUILD_SUFFIX" && -z "$JSC_BUILD_VARIANT" ]]; then + if [[ -n "$JSC_TOOLCHAIN_VARIANT_BUILD_SUFFIX" ]]; then + export JSC_BUILD_VARIANT="$JSC_TOOLCHAIN_VARIANT_BUILD_SUFFIX" + fi +fi + +if [[ -n "$JSC_TOOLCHAIN_VARIANT_DIST_DIR" && -z "$JSC_DIST_DIR" ]]; then + if [[ "$JSC_TOOLCHAIN_VARIANT_DIST_DIR" = /* ]]; then + export JSC_DIST_DIR="$JSC_TOOLCHAIN_VARIANT_DIST_DIR" + else + export JSC_DIST_DIR="$ROOTDIR/$JSC_TOOLCHAIN_VARIANT_DIST_DIR" + fi +fi + +if [[ -n "$JSC_TOOLCHAIN_VARIANT_DIST_UNSTRIPPED_DIR" && -z "$JSC_DIST_UNSTRIPPED_DIR" ]]; then + if [[ "$JSC_TOOLCHAIN_VARIANT_DIST_UNSTRIPPED_DIR" = /* ]]; then + export JSC_DIST_UNSTRIPPED_DIR="$JSC_TOOLCHAIN_VARIANT_DIST_UNSTRIPPED_DIR" + else + export JSC_DIST_UNSTRIPPED_DIR="$ROOTDIR/$JSC_TOOLCHAIN_VARIANT_DIST_UNSTRIPPED_DIR" + fi +fi + +if [[ -z "$JSC_CCACHE_BIN" && "${JSC_TOOLCHAIN_DISABLE_CCACHE:-0}" != "1" ]]; then + if command -v ccache >/dev/null 2>&1; then + export JSC_CCACHE_BIN=$(command -v ccache) + export CCACHE_DIR=${CCACHE_DIR:-$HOME/.cache/ccache} + export CCACHE_BASEDIR=${CCACHE_BASEDIR:-$ROOTDIR} + export CCACHE_COMPRESS=${CCACHE_COMPRESS:-1} + export CCACHE_CPP2=${CCACHE_CPP2:-yes} + export ANDROID_NDK_CCACHE="$JSC_CCACHE_BIN" + fi +fi + +if [[ "${JSC_TOOLCHAIN_VARIANT_ENABLE_THIN_LTO:-1}" == "1" ]]; then + export JSC_TOOLCHAIN_LTO_FLAG="-flto=thin" +else + export JSC_TOOLCHAIN_LTO_FLAG="" +fi + +if [[ "${JSC_TOOLCHAIN_VARIANT_DISABLE_LOOP_VECTORIZATION:-0}" == "1" ]]; then + export JSC_TOOLCHAIN_RELEASE_CFLAGS="-fno-vectorize -fno-slp-vectorize" +else + export JSC_TOOLCHAIN_RELEASE_CFLAGS="-Wno-pass-failed=loop-vectorize" +fi + +if [[ -n "$JSC_TOOLCHAIN_LTO_FLAG" ]]; then + export JSC_TOOLCHAIN_RELEASE_LDFLAGS="$JSC_TOOLCHAIN_LTO_FLAG" +else + export JSC_TOOLCHAIN_RELEASE_LDFLAGS="" +fi + +if [[ "${JSC_TOOLCHAIN_SUPPRESS_LOG:-0}" != "1" ]]; then + if [[ -n "$JSC_TOOLCHAIN_NDK_REVISION" ]]; then + echo "Detected Android NDK revision ${JSC_TOOLCHAIN_NDK_REVISION} (variant ${JSC_TOOLCHAIN_VARIANT})" + else + echo "Using Android NDK variant ${JSC_TOOLCHAIN_VARIANT}" + fi +fi diff --git a/test/plugins/withJscAndroid.js b/test/plugins/withJscAndroid.js index 63c864fa..37b6c132 100644 --- a/test/plugins/withJscAndroid.js +++ b/test/plugins/withJscAndroid.js @@ -1,9 +1,14 @@ const assert = require('assert'); const { withAppBuildGradle, + withGradleProperties, withProjectBuildGradle, } = require('expo/config-plugins'); +const DEFAULT_RELATIVE_DIST_PATH = '../../dist-ndk28'; +const GRADLE_DIST_PATH = + process.env.JSC_GRADLE_DIST_PATH || DEFAULT_RELATIVE_DIST_PATH; + const withJscAndroidAppBuildGradle = (config) => { return withAppBuildGradle(config, (config) => { assert(config.modResults.language === 'groovy'); @@ -24,7 +29,7 @@ afterEvaluate { repositories { maven { // Local dist maven repo - url("\${rootDir}/../../dist") + url("\${rootDir}/${GRADLE_DIST_PATH}") } mavenCentral { @@ -47,6 +52,7 @@ afterEvaluate { `; config.modResults.contents += code; } + return config; }); }; @@ -73,6 +79,41 @@ const withJscAndroidProjectBuildGradle = (config) => { const withJscAndroid = (config) => { config = withJscAndroidAppBuildGradle(config); config = withJscAndroidProjectBuildGradle(config); + config = withGradleProperties(config, (config) => { + const DEFAULT_ARCHS = ['arm64-v8a', 'x86_64']; + const ARCHS_TO_REMOVE = new Set(['armeabi-v7a', 'x86']); + const propertyName = 'reactNativeArchitectures'; + const desiredValue = DEFAULT_ARCHS.join(','); + const existingProp = config.modResults.find( + (item) => item.type === 'property' && item.key === propertyName + ); + const cleanValue = (value) => { + if (!value) return desiredValue; + const archs = value + .split(',') + .map((arch) => arch.trim()) + .filter(Boolean); + if (!archs.length) return desiredValue; + const result = []; + archs.forEach((arch) => { + if (!ARCHS_TO_REMOVE.has(arch) && !result.includes(arch)) { + result.push(arch); + } + }); + if (!result.length) return desiredValue; + return result.join(','); + }; + if (existingProp) { + existingProp.value = cleanValue(existingProp.value); + } else { + config.modResults.push({ + type: 'property', + key: propertyName, + value: desiredValue, + }); + } + return config; + }); return config; };