Skip to content

The build

The recipe

  1. One-time WSL setup. It covers the toolchain and DNS.
  2. Build Node for both ABIs with --dest-os=android --shared --openssl-no-asm --with-intl=small-icu and NDK r27d clang. Build in ext4 (/root/node-build*) for speed, and install to per-ABI prefixes.
  3. Build the JNI bridge (native/nodembed.cpp, CMake + NDK toolchain) against libnode.so, and deploy both into jniLibs/<abi>/.
  4. Bundle the Pi node_modules into assets/pi/, gradlew assembleDebug, adb install, launch.

Three commands re-run the proof afterwards.

scripts/build-android.ps1                                  # gradle build, install, launch
adb logcat -s DroidPi:*                                    # watch the app log
adb shell "run-as com.droidpi.proof cat files/result.json" # read back the verdict

A full Node rebuild rarely needs a re-run. When it does, the command is wsl -d Ubuntu -u root -- bash scripts/run-node-build.sh <arm64|x64>.

The fixes the build needed

Upstream does not build for Android cleanly. Each one showed up in the failure itself, not the last lines of the log.

  1. V8 trap handler. Force V8_TRAP_HANDLER_SUPPORTED false. The upstream patch file targets an older V8 layout. It fails to apply and reports nothing, and without it the host mksnapshot gets undefined symbols.
  2. zlib’s ARMV8 path. It references android_getCpuFeatures(), which Node never compiles. The fix also touches the vendored NDK cpu-features.c.
  3. Host compiler. CC_host/CXX_host must point at a native Linux compiler. The NDK’s own clang-18 works. Otherwise gyp builds host tools with the Android clang.
  4. Build node, not all. cctest uses aligned_alloc, which needs API 28+.
  5. Packaging. AGP’s ignoreAssetsPattern must not drop dotfiles. The bundle needs data/.manifest.json. Ship libc++_shared.so and set useLegacyPackaging=true.

Environment gotchas

  • Spaces in the workspace path. They break build scripts that assume otherwise. The tree now lives in a path with no spaces.
  • robocopy mangles Linux symlinks. The NDK copy needed symlink repair.
  • drvfs is not a build disk. Build on ext4 instead. WSL crashed more than once under drvfs load.
  • Never reuse the same out/ dir across ABIs.