How To Build a Static rsync Binary

This page shows various ways of building rsync as a static binary that can be executed in the adb shell on an Android device. Both native builds and cross-compilation to ARM are demonstrated.

Created
February 22, 2025

Motivation

I want to build an rsync binary that can be executed on my Android device. My Pixel phone runs a 64-bit ARM (AArch64) version of Android. Because Android is based on the Linux kernel, I will compile rsync as a statically-linked binary for the AArch64 Linux target.

Glibc can't properly build static binaries, and the Android NDK failed to compile the rsync binary because of incompatible data types. So I chose the musl C standard library, which works without any issues.

Pre-Requisites

This guide uses a Fedora Linux computer with podman installed to run Linux containers. Any Linux distribution is suitable because we will run the build in a container.

Check the CPU architecture of the computer:

uname -m

It will most likely be aarch64 or x86_64.

Run the same command on the Android device (either via the adb shell or in the Termux app) to find the CPU architecture of the Android device. It will most likely be aarch64, although some older devices may be armv7l or some other version of ARM.

Option 1: Use musl-cross-make

This option is the most universal, but it requires us to build the musl cross-compiler from the source, which may take a few minutes.

My old Motorola phone used a 32-bit ARM version of Android. In that case, I followed the same instructions, except that I replaced the aarch64-linux-musl target triplet with armv7l-linux-musleabihf.

Devices that are even older may need arm-linux-musleabi.

On the Linux computer, create a new container in which we will set up the build environment:

podman run -it --name musl-cross-builder --workdir /root fedora

Inside the container, install C/C++ build tools:

dnf -y --refresh upgrade
dnf -y install @c-development

Next, install the musl cross-compiler toolchain.

Download the latest rsync source code from https://rsync.samba.org/:

curl -L -O https://download.samba.org/pub/rsync/src/rsync-3.4.1.tar.gz
tar -xvf rsync-3.4.1.tar.gz
mv rsync-3.4.1 rsync-src

Compile the rsync source code into an AArch64 static executable binary:

export PATH="$PATH:$(realpath aarch64-linux-musl)/bin"
cd rsync-src
TARGET=aarch64-linux-musl
./configure --disable-openssl --disable-xxhash --disable-zstd --disable-lz4 CFLAGS="-static" --host="$TARGET"
make
cd ..
mkdir -p compiled
cp -a rsync-src/rsync compiled/rsync-"$TARGET"

Optionally, strip debugging information from the rsync binary and calculate a checksum.

cd compiled
"$TARGET"-strip rsync-"$TARGET"
sha256sum * > sha256sum.txt

Option 2: Use Debian's musl Cross-Compiler

On the Linux computer, create a new container in which we will set up the build environment:

podman run -it --name musl-cross-builder --workdir /root debian:sid

I use Debian Sid because its packages are more up-to-date compared to stable Debian versions.

Cross-Compile to AArch64

In this scenario, we want to build an rsync binary for the AArch64 architecture when our computer uses a different architecture than AArch64.

dpkg --add-architecture arm64
apt update
apt full-upgrade -y
apt install -y curl make gcc-aarch64-linux-gnu musl-tools:arm64

curl -L -O https://download.samba.org/pub/rsync/src/rsync-3.4.1.tar.gz
tar -xvf rsync-3.4.1.tar.gz
mv rsync-3.4.1 rsync-src

cd rsync-src
TARGET=aarch64-linux-musl
CC="$TARGET"-gcc ./configure --disable-openssl --disable-xxhash --disable-zstd --disable-lz4 CFLAGS="-static" --host="$TARGET"
make
cd ..
mkdir -p compiled
cp -a rsync-src/rsync compiled/rsync-"$TARGET"

cd compiled
"$("$TARGET"-gcc -dumpmachine)"-strip rsync-"$TARGET"
sha256sum * > sha256sum.txt

Native Build From AArch64 to AArch64

If we are building an AArch64 build of rsync on an AArch64 computer, use the same steps but replace the apt install line with this one:

apt install -y curl make gcc musl-tools

(I tried using the x86_64-linux-gnu-gcc compiler that comes from the gcc-x86-64-linux-gnu package, but it still attempted to call the native as, which is included in the binutils package and not installed as a dependency of that package.)

Cross-Compile to ARMv7

Use the AArch64 cross-compilation steps but with these modifications:

dpkg --add-architecture armhf
apt install -y curl make gcc-arm-linux-gnueabihf musl-tools:armhf
TARGET=arm-linux-musleabihf

Cross-Compile to Older ARM

Use the AArch64 cross-compilation steps but with these modifications:

dpkg --add-architecture armel
apt install -y curl make gcc-arm-linux-gnueabi musl-tools:armel
TARGET=arm-linux-musleabi

Option 3: Use Alpine Linux's Compiler

This is the best option for a native build (when you want to build rsync for the same architecture as what your computer uses). Alpine Linux uses musl as the default C standard library, which makes it easy to install additional libraries like zstd, lz4, or openssl.

I successfully built an x86_64 rsync binary on an x86_64 computer and an AArch64 rsync binary on an AArch64 computer.

On the Linux computer, create a new container in which we will set up the build environment:

podman run -it --name musl-cross-builder --workdir /root alpine
apk update
apk add build-base curl
apk add acl-dev acl-static attr-dev attr-static zstd-dev zstd-static lz4-dev lz4-static openssl-dev openssl-libs-static

curl -L -O https://download.samba.org/pub/rsync/src/rsync-3.4.1.tar.gz
tar -xvf rsync-3.4.1.tar.gz
mv rsync-3.4.1 rsync-src

cd rsync-src
TARGET="$(gcc -dumpmachine)"
./configure --disable-xxhash CFLAGS="-static"
make
cd ..
mkdir -p compiled
cp -a rsync-src/rsync compiled/rsync-"$TARGET"

cd compiled
strip rsync-"$TARGET"
sha256sum * > sha256sum.txt

Copy the Compiled rsync Binary

When done, exit the container (type exit or press Ctrl+D). Then copy the rsync binary and its checksum from the container to the host OS:

mkdir ./rsync-musl
podman cp musl-cross-builder:/root/compiled ./rsync-musl/
A screenshot of the Files window on the Linux computer showing the compiled rsync binary