aboutsummaryrefslogtreecommitdiff
path: root/rsync/build.sh
blob: ae4026a93392d0aa9da119b04a6e7e107eb4d520 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/bin/sh
# Build rsync for each Android ABI from pinned source via the NDK. Output is a
# stripped PIE executable named lib*.so, packaged inside the APK and exec'd from
# nativeLibraryDir. Optional dependencies are disabled so the binary needs
# nothing outside Bionic; zlib and popt come from rsync's bundled copies.
set -eu

root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
# shellcheck source=versions
. "$root/versions"

command -v bash >/dev/null 2>&1 || {
	echo "rsync: bash is required by the Android NDK compiler launchers" >&2
	exit 1
}

# Locate the NDK toolchain.
ndk=${ANDROID_NDK_HOME:-${ANDROID_NDK_ROOT:-}}
if [ -z "$ndk" ] && [ -n "${ANDROID_HOME:-}" ]; then
	ndk="$ANDROID_HOME/ndk/$ANDROID_NDK"
fi
if [ -z "$ndk" ] || [ ! -d "$ndk" ]; then
	echo "rsync: Android NDK not found; set ANDROID_NDK_HOME" >&2
	exit 1
fi
# NDK prebuilt toolchains are named by build host, not target; the target ABI is
# selected separately below. ci/setup-toolchain.sh provisions Linux x86_64 only,
# so that is the only host tag worth naming here.
if [ "$(uname -s)" != Linux ] || [ "$(uname -m)" != x86_64 ]; then
	echo "rsync: only Linux x86_64 build hosts are supported" >&2
	exit 1
fi
tc="$ndk/toolchains/llvm/prebuilt/linux-x86_64/bin"
if [ ! -d "$tc" ]; then
	echo "rsync: NDK toolchain not found at $tc" >&2
	exit 1
fi

work="$root/rsync/work"
tarball="$root/rsync/rsync-${RSYNC_VERSION}.tar.gz"
src="$work/rsync-${RSYNC_VERSION}"
part="$tarball.part.$$"
output=
trap 'if [ -n "$part" ]; then rm -f "$part"; fi; if [ -n "$output" ]; then rm -f "$output"; fi' 0 1 2 3 15

# Fetch and verify the pinned source tarball.
mkdir -p "$work"
if [ -f "$tarball" ] && ! ( cd "$root/rsync" && sha256sum -c "rsync-${RSYNC_VERSION}.tar.gz.sha256" >/dev/null 2>&1 ); then
	echo "rsync: removing corrupt $(basename "$tarball")" >&2
	rm -f "$tarball"
fi
if [ ! -f "$tarball" ]; then
	echo "rsync: fetching $RSYNC_URL"
	# Download aside and rename, so an interrupted fetch leaves no truncated
	# tarball for the next run to pick up. Verify before publishing it.
	curl --fail --silent --show-error --location --retry 3 \
		--connect-timeout 30 --speed-limit 1024 --speed-time 60 \
		"$RSYNC_URL" -o "$part"
	want=$(awk 'NR == 1 { print $1 }' "$root/rsync/rsync-${RSYNC_VERSION}.tar.gz.sha256")
	actual=$(sha256sum "$part")
	[ "${actual%% *}" = "$want" ] || {
		echo "rsync: checksum failed for $(basename "$tarball")" >&2
		exit 1
	}
	mv "$part" "$tarball"
	part=
fi
echo "rsync: verifying sha256"
( cd "$root/rsync" && sha256sum -c "rsync-${RSYNC_VERSION}.tar.gz.sha256" )

for abi in $ABIS; do
	case "$abi" in
	arm64-v8a) host=aarch64-linux-android cc="aarch64-linux-android${ANDROID_MIN_SDK}-clang" ;;
	x86_64)    host=x86_64-linux-android  cc="x86_64-linux-android${ANDROID_MIN_SDK}-clang" ;;
	*) echo "rsync: unknown ABI $abi" >&2; exit 1 ;;
	esac

	# Fresh build tree per ABI.
	rm -rf "$src"
	tar xzf "$tarball" -C "$work"

	# CXX must be pinned like CC: rsync's SIMD checksum is C++, and configure
	# otherwise falls back to the host g++, leaking a host-compiled object
	# into the target binary (or failing where the host lacks ifunc).
	echo "rsync: configuring $abi"
	( cd "$src" &&
		# No system libraries, generated docs, iconv, ACLs, or xattrs.
		set -- --disable-md2man --disable-openssl --disable-xxhash \
			--disable-zstd --disable-lz4 --disable-iconv \
			--disable-acl-support --disable-xattr-support \
			--with-included-popt --with-included-zlib \
			--with-nobody-user=nobody --with-nobody-group=nobody
		# NDK r27 needs both page-size flags for 16 KB Android devices.
		# rsync parses peer-controlled data in C. Keep the compiler defenses
		# explicit rather than relying on whichever defaults an NDK release
		# happens to select.
		CC="$tc/$cc" CXX="$tc/${cc}++" AR="$tc/llvm-ar" RANLIB="$tc/llvm-ranlib" \
			rsync_cv_HAVE_SECURE_MKSTEMP=yes \
			CFLAGS="-O2 -fPIE -fstack-protector-strong -D_FORTIFY_SOURCE=2 -ffile-prefix-map=$src=." \
			CXXFLAGS="-O2 -fPIE -fstack-protector-strong -D_FORTIFY_SOURCE=2 -ffile-prefix-map=$src=." \
			LDFLAGS="-pie -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384" \
			./configure --host="$host" "$@" >/dev/null )

	# Bundled popt leaves conditional variables unused on Android. Append the
	# two narrow suppressions after rsync's own -Wall flags.
	build_cflags=$(sed -n 's/^CFLAGS=//p' "$src/Makefile")
	if [ -z "$build_cflags" ]; then
		echo "rsync: generated Makefile has no CFLAGS" >&2
		exit 1
	fi
	echo "rsync: building $abi"
	( cd "$src" && make -s CFLAGS="$build_cflags -Wno-unused-variable -Wno-unused-but-set-variable" rsync )

	dest="$root/app/src/main/jniLibs/$abi"
	mkdir -p "$dest"
	output="$dest/libxrsync.so.part.$$"
	cp "$src/rsync" "$output"
	"$tc/llvm-strip" "$output"
	mv "$output" "$dest/libxrsync.so"
	output=
	echo "rsync: $abi -> jniLibs/$abi/libxrsync.so"
done