Build Rsync for Android Yourself

To build rsync for Android you’ll need to have the Android NDK installed already.

Then clone the rsync for android source (e.g. from CyanogenMod LineageOS) …

git clone https://github.com/LineageOS/android_external_rsync.git
cd android_external_rsync
# checkout the most recent branch
git checkout cm-14.1

… create the missing

jni/Application.mk

build file (e.g. from this Gist) and adapt it to your case

APP_ABI := armeabi-v7a arm64-v8a
APP_OPTIM := release
APP_BUILD_SCRIPT := $(NDK_PROJECT_PATH)/Android.mk
APP_PLATFORM := android-29
view raw Application.mk hosted with ❤ by GitHub

… and start the build with

export NDK_PROJECT_PATH=pwd ndk-build -d rsync

You’ll find your self-build rsync in

obj/local/*/rsync

. ?

Update 2017-10-06:

  • Updated sources from CyanogenMod to LineageOS.
  • Added links to Gist and Andoid NDK docs
  • Updated steps to work with up-to-date setups

If you get something like the following warnings and errors …

[...]
./flist.c:454:16: warning: implicit declaration of function 'major' is invalid in C99
      [-Wimplicit-function-declaration]
                        if ((uint32)major(rdev) == rdev_major)
                                    ^
./flist.c:458:41: warning: implicit declaration of function 'minor' is invalid in C99
      [-Wimplicit-function-declaration]
                        if (protocol_version < 30 && (uint32)minor(rdev) <= 0xFFu)
                                                             ^
./flist.c:467:11: warning: implicit declaration of function 'makedev' is invalid in C99
      [-Wimplicit-function-declaration]
                        rdev = MAKEDEV(major(rdev), 0);
                               ^
./rsync.h:446:36: note: expanded from macro 'MAKEDEV'
#define MAKEDEV(devmajor,devminor) makedev(devmajor,devminor)
                                   ^
3 warnings generated.
[...]
./flist.c:473: error: undefined reference to 'makedev'
./flist.c:454: error: undefined reference to 'major'
./flist.c:457: error: undefined reference to 'major'
./flist.c:458: error: undefined reference to 'minor'
./flist.c:467: error: undefined reference to 'major'
./flist.c:467: error: undefined reference to 'makedev'
./flist.c:617: error: undefined reference to 'major'
./flist.c:619: error: undefined reference to 'minor'
./flist.c:621: error: undefined reference to 'minor'
./flist.c:788: error: undefined reference to 'makedev'
./flist.c:869: error: undefined reference to 'makedev'
./flist.c:1027: error: undefined reference to 'minor'
clang++: error: linker command failed with exit code 1 (use -v to see invocation) 
make: *** [obj/local/armeabi-v7a/rsync] Error 1

… you probably need to update

config.h

and change

/* #undef MAJOR_IN_SYSMACROS */

to

#define MAJOR_IN_SYSMACROS 1

.

Synchronize directories between computers using rsync (and SSH)

https://twitter.com/climagic/status/363326283922419712

I found this command line magic gem some time ago and was using it ever since.

I started using it for synchronizing directories between computers on the same network. But it felt kind of clunky and cumbersome to get the slashes right so that it wouldn’t nest those directories and copy everything. Since both source and destination machine had the same basic directory layout, I thought ‘why not make it easier?’ … e.g. like this:

sync-to other-pc ~/Documents
sync-to other-pc ~/Music --exclude '*.wav'
sync-from other-pc ~/Music --dry-run --delete

It uses rsync for the heavy lifting but does the tedious source and destination mangling for you. 😀

You can find the code in this Gist.

#!/usr/bin/env python3
#
# Author: Riyad Preukschas <riyad@informatik.uni-bremen.de>
# License: Mozilla Public License 2.0
#
# Synchronize directories between computers using rsync (and SSH).
#
# INSTALLATION:
# Save this script as something like `sync-to` somewhere in $PATH.
# Link it to `sync-from` in the same location. (i.e. `ln sync-to sync-from`)
import os
import re
import shlex
import subprocess
import sys
PROGRAM_NAME = os.path.basename(sys.argv[0])
RSYNC = 'rsync'
RSYNC_BASIC_OPTIONS = [
'--rsh="ssh"', '--partial', '--progress', '--archive', '--human-readable']
RSYNC_EXCLUDE_PATTERNS = ['.DS_Store', '.localized']
#
# helpers
#
def print_usage_and_die():
print(re.sub(r'^[ ]{8}', '',
f"""
Synchronize directories between computers using rsync (and SSH).
Usage: {PROGRAM_NAME} HOST DIR [options]
HOST any host you'd use with SSH
DIR must be available on both the local and the remote machine
Options:
You can pass any options rsync accepts.
-v, --verbose will also print the command that'll be used to sync
Examples:
sync-to other-pc ~/Documents
sync-to other-pc ~/Music --exclude '*.wav'
sync-from other-pc ~/Music --dry-run --delete
""".strip(),
flags=re.MULTILINE
))
exit(1)
def is_verbose():
return any(
re.search(r'^--verbose|-\w*v\w*$', arg) is not None
for arg
in sys.argv
)
#
# main
#
def main():
#
# parse options
#
if len(sys.argv) < 3:
print_usage_and_die()
host = sys.argv[1]
dir = sys.argv[2]
rsync_excludes = [f"--exclude='{pattern}'" for pattern in RSYNC_EXCLUDE_PATTERNS]
rsync_user_options = sys.argv[3:]
if re.search(r'from$', PROGRAM_NAME):
rsync_src_dest = [f"{host}:{dir}/", dir]
elif re.search(r'to$', PROGRAM_NAME):
rsync_src_dest = [f"{dir}/", f"{host}:{dir}"]
else:
print('Error: unknown command')
print_usage_and_die()
#
# copy
#
exec_args = RSYNC_BASIC_OPTIONS + rsync_excludes + rsync_user_options + rsync_src_dest
if is_verbose():
print(f"{RSYNC} {' '.join(RSYNC_BASIC_OPTIONS + rsync_excludes)} {shlex.join(rsync_user_options + rsync_src_dest)}")
os.execvp(RSYNC, exec_args)
#subprocess.run([RSYNC] + exec_args)
if __name__ == '__main__':
main()
view raw sync-to-from hosted with ❤ by GitHub