diff --git a/nodejs-assets/nodejs-project/main.js b/nodejs-assets/nodejs-project/main.js index 3e7f315..ffcc691 100644 --- a/nodejs-assets/nodejs-project/main.js +++ b/nodejs-assets/nodejs-project/main.js @@ -1,7 +1,36 @@ 'use strict'; +const fs = require('fs'); const path = require('path'); +// better-sqlite3's better_sqlite3.node is architecture-specific (it links +// against libnode.so, which is the real Android binary already loaded into +// this process by nodejs-mobile-cordova). The copy under node_modules/ is +// whichever architecture it happened to be built for last; replace it with +// the prebuild matching this device's actual arch before anything requires +// better-sqlite3. See scripts/build-better-sqlite3-arm.sh. +(function installBetterSqlite3Prebuild() { + const archDirs = { + arm64: 'arm64-v8a', + arm: 'armeabi-v7a', + x64: 'x86_64', + ia32: 'x86', + }; + const archDir = archDirs[process.arch]; + if (!archDir) return; // Unknown arch — fall back to whatever's bundled. + + const prebuilt = path.join(__dirname, 'prebuilds', archDir, 'better_sqlite3.node'); + const target = path.join(__dirname, 'node_modules', 'better-sqlite3', 'build', 'Release', 'better_sqlite3.node'); + if (!fs.existsSync(prebuilt)) return; + + try { + fs.mkdirSync(path.dirname(target), { recursive: true }); + fs.copyFileSync(prebuilt, target); + } catch (err) { + console.error('[main.js] Failed to install better-sqlite3 prebuild for', process.arch, err); + } +})(); + // Node 12.19 predates crypto.randomUUID (added in Node 14.17), used by // services/authService.js for session token IDs. const nodeCrypto = require('crypto'); diff --git a/nodejs-assets/nodejs-project/prebuilds/arm64-v8a/better_sqlite3.node b/nodejs-assets/nodejs-project/prebuilds/arm64-v8a/better_sqlite3.node new file mode 100755 index 0000000..b4bb34a Binary files /dev/null and b/nodejs-assets/nodejs-project/prebuilds/arm64-v8a/better_sqlite3.node differ diff --git a/nodejs-assets/nodejs-project/prebuilds/armeabi-v7a/better_sqlite3.node b/nodejs-assets/nodejs-project/prebuilds/armeabi-v7a/better_sqlite3.node new file mode 100755 index 0000000..015367f Binary files /dev/null and b/nodejs-assets/nodejs-project/prebuilds/armeabi-v7a/better_sqlite3.node differ diff --git a/nodejs-assets/nodejs-project/prebuilds/x86_64/better_sqlite3.node b/nodejs-assets/nodejs-project/prebuilds/x86_64/better_sqlite3.node new file mode 100755 index 0000000..ea4404c Binary files /dev/null and b/nodejs-assets/nodejs-project/prebuilds/x86_64/better_sqlite3.node differ diff --git a/scripts/build-better-sqlite3-arm.sh b/scripts/build-better-sqlite3-arm.sh new file mode 100755 index 0000000..670d73d --- /dev/null +++ b/scripts/build-better-sqlite3-arm.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash +# Cross-compiles better-sqlite3 for arm64-v8a and armeabi-v7a (real Android +# devices) and writes the resulting better_sqlite3.node binaries into +# nodejs-assets/nodejs-project/prebuilds//. main.js installs the one +# matching the device's actual process.arch at runtime — see main.js's +# installBetterSqlite3Prebuild(). +# +# The existing x86_64 build (emulator) in +# nodejs-assets/nodejs-project/node_modules/better-sqlite3/build/Release/ +# already covers nodejs-assets/nodejs-project/prebuilds/x86_64/ via +# fix-better-sqlite3-android.sh; re-copy it manually if that build changes: +# cp nodejs-assets/nodejs-project/node_modules/better-sqlite3/build/Release/better_sqlite3.node \ +# nodejs-assets/nodejs-project/prebuilds/x86_64/ +# +# Requires: Android NDK (ANDROID_HOME or ANDROID_NDK_HOME set), and +# `npm install` already run in nodejs-assets/nodejs-project (so +# better-sqlite3's source + nodejs-mobile-gyp are present). +# +# Usage: ./scripts/build-better-sqlite3-arm.sh + +set -euo pipefail + +MOBILE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PKG_SRC="$MOBILE_DIR/nodejs-assets/nodejs-project/node_modules/better-sqlite3" +PREBUILDS_DIR="$MOBILE_DIR/nodejs-assets/nodejs-project/prebuilds" +GYP="$MOBILE_DIR/nodejs-assets/nodejs-project/node_modules/.bin/nodejs-mobile-gyp" +NODEDIR="$MOBILE_DIR/node_modules/nodejs-mobile-cordova/libs/android/libnode" + +NDK="${ANDROID_NDK_HOME:-${ANDROID_NDK_ROOT:-}}" +if [[ -z "$NDK" ]]; then + SDK="${ANDROID_HOME:-${ANDROID_SDK_ROOT:-}}" + [[ -n "$SDK" ]] && NDK="$(ls -d "$SDK"/ndk/*/ 2>/dev/null | sort -V | tail -1)" +fi +NDK="${NDK%/}" + +if [[ ! -d "$PKG_SRC" ]]; then + echo "Error: $PKG_SRC not found. Run npm install in nodejs-assets/nodejs-project first." >&2 + exit 1 +fi +if [[ -z "$NDK" || ! -d "$NDK" ]]; then + echo "Error: Android NDK not found. Set ANDROID_NDK_HOME (or ANDROID_HOME with an ndk/ subdir)." >&2 + exit 1 +fi +if [[ ! -x "$GYP" ]]; then + echo "Error: $GYP not found. Run npm install in nodejs-assets/nodejs-project first." >&2 + exit 1 +fi + +TOOLCHAIN="$NDK/toolchains/llvm/prebuilt/linux-x86_64" +API=24 # matches android/variables.gradle minSdkVersion + +# Each ABI's libnode.so ships gzipped; better-sqlite3's binding.gyp (via +# nodejs-mobile's common.gypi) needs the real .so to add it as a NEEDED entry. +for abi in arm64-v8a armeabi-v7a; do + LIBNODE_DIR="$NODEDIR/bin/$abi" + if [[ ! -f "$LIBNODE_DIR/libnode.so" && -f "$LIBNODE_DIR/libnode.so.gz" ]]; then + gunzip -k "$LIBNODE_DIR/libnode.so.gz" + fi +done + +build_one() { + local abi="$1" gyp_arch="$2" cc="$3" cxx="$4" + local build_dir="$MOBILE_DIR/build-output/better-sqlite3-$abi" + + echo "── Building better-sqlite3 for $abi ($gyp_arch) ──" + rm -rf "$build_dir" + mkdir -p "$build_dir" + rsync -a --exclude=build --exclude=prebuilds "$PKG_SRC/" "$build_dir/" + + # v8::Object::CreationContext() was removed in newer V8; nodejs-mobile's + # bundled V8 (Node 12.19) only has the old non-checked accessor. Same patch + # as fix-better-sqlite3-android.sh. + sed -i 's/obj->GetCreationContext().ToLocalChecked()/obj->CreationContext()/' \ + "$build_dir/src/util/binder.cpp" + + ( + cd "$build_dir" + CC="$TOOLCHAIN/bin/$cc" \ + CXX="$TOOLCHAIN/bin/$cxx" \ + AR="$TOOLCHAIN/bin/llvm-ar" \ + GYP_DEFINES="OS=android" \ + "$GYP" configure --target=12.19.0 --arch="$gyp_arch" --nodedir="$NODEDIR" + + CC="$TOOLCHAIN/bin/$cc" \ + CXX="$TOOLCHAIN/bin/$cxx" \ + AR="$TOOLCHAIN/bin/llvm-ar" \ + "$GYP" build + ) + + mkdir -p "$PREBUILDS_DIR/$abi" + cp "$build_dir/build/Release/better_sqlite3.node" "$PREBUILDS_DIR/$abi/better_sqlite3.node" + echo "Wrote $PREBUILDS_DIR/$abi/better_sqlite3.node" +} + +build_one arm64-v8a arm64 aarch64-linux-android${API}-clang aarch64-linux-android${API}-clang++ +build_one armeabi-v7a arm armv7a-linux-androideabi${API}-clang armv7a-linux-androideabi${API}-clang++ + +echo "Done. Verify with: file $PREBUILDS_DIR/*/better_sqlite3.node" diff --git a/scripts/fix-better-sqlite3-android.sh b/scripts/fix-better-sqlite3-android.sh index 3e5754e..2d184fa 100755 --- a/scripts/fix-better-sqlite3-android.sh +++ b/scripts/fix-better-sqlite3-android.sh @@ -52,4 +52,11 @@ cd "$PKG_DIR/build" rm -f Release/better_sqlite3.node Release/obj.target/better_sqlite3.node make BUILDTYPE=Release better_sqlite3.node +# Keep the x86_64 prebuild (emulator) in sync — main.js picks the right one +# for the device's process.arch at runtime. arm64-v8a/armeabi-v7a prebuilds +# are produced separately by build-better-sqlite3-arm.sh. +PREBUILD_DIR="$MOBILE_DIR/nodejs-assets/nodejs-project/prebuilds/x86_64" +mkdir -p "$PREBUILD_DIR" +cp "$PKG_DIR/build/Release/better_sqlite3.node" "$PREBUILD_DIR/better_sqlite3.node" + echo "Done. Verify with: readelf -d \"$PKG_DIR/build/Release/better_sqlite3.node\" | grep libnode"