Unison on Android

Posted on January 4, 2016

I’ve been using the excellent Unison tool for quite a while to keep my files in sync between a number of devices. If you follow the manual, the tool works nicely. One partricular thing you should be aware of is the following:

A new version of Unison will sometimes introduce a different format for the archive files used to remember information about the previous state of the replicas.

OK, so you have to use the same Unison version on all devices. Sounds fair.

After a while I’ve also started to make use of Unison on my Android devices. Thanks to Daniel Roggen’s build, this worked flawlessly. I built a setup for keeping my music, notes and PDFs in sync between my Android devices and my laptops. So far, everything went well. However, a couple of OS updates later, I got a strange error message on my phone: Uncaught exception Failure("input_value: bad bigarray kind") It turns out that this is due to an update in the serialization format in OCaml 4.0.2: The Unison packages I’m using on my laptops are compiled with OCaml 4.0.2 and therefore make use of the new serialization format. The Android version doesn’t understand that and hence throws the above exception. After ignoring the problem for a while, I decided to finally fix it.

I decided to just set up an OCaml cross compiler targeting Android and to build unison myself. This tutorial worked out awesomely well. Follow the tutorial to get an OCaml cross compiler targeting Android. Please don’t forget to select a proper cross compiler version (i.e., 4.02 or higher):

opam switch 4.02.3+32bit
eval `opam config env`

Now for actually compiling Unison. I’m (still) using Unison-2.40.102 and I didn’t bother testing other versions - you’ve been warned ;)

Once you got the cross compiler running, download Unison-2.40.102. Then please apply the following patch:

diff --new-file -u unison-2.40.102/Makefile.OCaml unison-2.40.102-android/Makefile.OCaml
--- unison-2.40.102/Makefile.OCaml	2014-12-30 02:48:18.000000000 +0100
+++ unison-2.40.102-android/Makefile.OCaml	2016-01-04 12:24:22.149979203 +0100
@@ -136,7 +136,9 @@
     # openpty is in the libutil library
     ifneq ($(OSARCH),solaris)
       ifneq ($(OSARCH),osx)
-        CLIBS+=-cclib -lutil
+        ifneq ($(OSCOMP),android)
+          CLIBS+=-cclib -lutil
+        endif
       endif
     endif
     buildexecutable::
diff --new-file -u unison-2.40.102/opam unison-2.40.102-android/opam
--- unison-2.40.102/opam	1970-01-01 01:00:00.000000000 +0100
+++ unison-2.40.102-android/opam	2016-01-04 13:04:00.047154073 +0100
@@ -0,0 +1,11 @@
+opam-version: "1"
+maintainer: "code@gregorkopf.de"
+build: [
+  ["make" "UISTYLE=text"
+      "OCAMLOPT=ocamlfind -toolchain android ocamlopt -ccopt '-fPIC -pie'" "OSCOMP=android"]
+  ["cp" "unison" "%{prefix}%/arm-linux-androideabi/bin/"]
+]
+remove: [
+  ["rm" "%{prefix}%/arm-linux-androideabi/bin/unison"]
+]
+depends: ["ocaml-android"]
diff --new-file -u unison-2.40.102/pty.c unison-2.40.102-android/pty.c
--- unison-2.40.102/pty.c	2010-04-15 19:29:31.000000000 +0200
+++ unison-2.40.102-android/pty.c	2016-01-04 12:24:22.149979203 +0100
@@ -10,7 +10,7 @@
 extern void uerror (char * cmdname, value arg) Noreturn;
 
 // openpty
-#if defined(__linux)
+#if defined(__linux) && !defined(__ANDROID__)
 #include <pty.h>
 #define HAS_OPENPTY 1
 #endif

In a next step, change to the directory with the patched Unison source and type opam pin add android-unison .. This should build and install an Android version of Unison-2.40.102. The binary can be found in ~/.opam/4.02.3+32bit/arm-linux-androideabi/bin/unison. And that’s it.