fix(android): PATH wrapper to redirect tauri-cli's android24-clang → android26
Some checks failed
Mirror to GitHub / mirror (push) Failing after 37s
Build Release Binaries / build-amd64 (push) Failing after 3m48s

Build #12's instrumented pthread_shim gave us the definitive diagnosis:

  WZP_pthread_shim: dlsym(RTLD_DEFAULT, pthread_create) returned NULL:
    libdl.a is a stub --- use libdl.so instead

Tauri-cli invokes `aarch64-linux-android24-clang` as the linker and the
API-24 NDK sysroot ships *stub* libdl.a / libc.a: they compile fine but
every symbol crashes if called, because they're meant to coexist with a
separate dynamic .so that the dynamic linker provides at runtime. Rust's
pre-built libstd.rlib has static calls into those stubs baked in, so no
matter what we do at link time the broken code lands in the .so.

Env-var overrides of CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER don't
stick — tauri-cli resets them before invoking cargo. So instead of
fighting the env, we put a wrapper on $PATH, literally named
`aarch64-linux-android24-clang`, that exec()s the android26 version.
When tauri-cli looks up android24-clang via PATH, it gets our wrapper,
our wrapper runs android26-clang, and suddenly the whole build is using
the API-26 NDK sysroot with real dynamic bindings to libc.so / libdl.so.

Wrappers are installed for all four ABIs (aarch64, armv7, x86_64, i686)
× both suffixes (clang, clang++) directly inside the docker bash -c
preamble before any cargo invocation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-04-09 13:23:47 +04:00
parent 1a8288c95f
commit 2718402e96

View File

@@ -166,6 +166,30 @@ docker run --rm \
wzp-android-builder \
bash -c '
set -euo pipefail
# ─── Linker wrappers ───────────────────────────────────────────────────────
# Tauri-cli hard-codes aarch64-linux-android24-clang as the Rust linker for
# the aarch64 target, which resolves pthread_create / dlsym / __init_tcb
# against the NDK API-24 *stub* libc.a/libdl.a. Those stubs are designed to
# crash if called — they only exist so the API-24 sysroot compiles, not so
# symbols actually work. API-26 has the real dynamic bindings to libc.so.
#
# Rather than fight tauri-cli to change which clang it invokes, we put a
# wrapper on $PATH that IS named android24-clang but exec()s the android26
# version. Same trick works for every ABI.
mkdir -p /tmp/wrappers
for abi in aarch64-linux-android armv7a-linux-androideabi i686-linux-android x86_64-linux-android; do
for suffix in clang clang++; do
cat > /tmp/wrappers/${abi}24-${suffix} <<WRAPPER
#!/bin/sh
exec /opt/android-sdk/ndk/26.1.10909125/toolchains/llvm/prebuilt/linux-x86_64/bin/${abi}26-${suffix} "\$@"
WRAPPER
chmod +x /tmp/wrappers/${abi}24-${suffix}
done
done
export PATH=/tmp/wrappers:$PATH
echo ">>> installed android24→android26 linker wrappers in /tmp/wrappers"
cd /build/source/desktop
echo ">>> npm install"