Cross-Compile Rust Application for Linux, Windows, and Android Termux on EndeavourOS

sudo pacman -S rustup
rustup default stable
# 🐧 Linux (Already default, but ensuring native architecture toolchain)
rustup target add x86_64-unknown-linux-gnu

# 🪟 Windows (Using GNU/MinGW ABI for easy cross-compiling from Linux)
rustup target add x86_64-pc-windows-gnu

# 🤖 Android / Termux (armv8 / 64-bit ARM)
rustup target add aarch64-linux-android

# 🤖 Android / Termux (armv7 / 32-bit ARM)
rustup target add armv7-linux-androideabi

Install System Cross-Linkers

sudo pacman -S mingw-w64-gcc
yay -S android-ndk

Configure Cargo Linkers

Cargo needs to know which linker to pull when you pass a --target flag. Create or edit your global Cargo configuration file at ~/.cargo/config.toml (or create one locally inside your project folder) and add the following mapping:

# ==================== 🪟 WINDOWS TARGET ====================
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
ar = "x86_64-w64-mingw32-ar"

# ==================== 🤖 ANDROID ARMV8 (64-bit ARM) ====================
# This matches: aarch64-linux-android35-clang
[target.aarch64-linux-android]
linker = "/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android35-clang"

# ==================== 🤖 ANDROID ARMV7 (32-bit ARM) ====================
# This matches: armv7a-linux-androideabi35-clang
[target.armv7-linux-androideabi]
linker = "/opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi35-clang"

⚠️ Important NDK Note: Double-check the path inside /opt/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/. Depending on the NDK version installed, the API version number suffix at the end of the compiler name (e.g., android34-clang) might vary (like android31-clang). Change it to match what is present in your folder.

Fix the Critical Android Linker Issue

Rust cross-compilation for Android has a historic quirk: even when you specify the custom clang compiler executable above as your linker, Cargo’s internal driver often tries to pass arguments to it using standard GNU tools (strip, ar) rather than the LLVM tools inside the NDK.

To prevent compilation failures when building complex dependency crates, you must let your terminal environment know where the NDK binaries live. Add these exports to your shell script or run them right before building:

export ANDROID_NDK_HOME="/opt/android-ndk"
export PATH="$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH"

If you are using the Fish Shell, run these lines instead to set them up:

set -gx ANDROID_NDK_HOME /opt/android-ndk
set -gx PATH $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin $PATH

Building the App

# 🐧 Build for Linux
cargo build --release

# 🪟 Build for Windows (Generates a .exe in target/x86_64-pc-windows-gnu/release/)
cargo build --target x86_64-pc-windows-gnu --release

# 🤖 Build for Termux 64-bit (armv8)
cargo build --target aarch64-linux-android --release

# 🤖 Build for Termux 32-bit (armv7)
cargo build --target armv7-linux-androideabi --release