Couchbase Lite on Raspberry Pi

I’ve used .NET for many years and I am pretty confident about almost everything dealing with it, so I decided to challenge myself and see what I can figure out about Java and Gradle.  A lot of Couchbase Lite users have been asking about how to run Couchbase Lite on their raspberry pi devices, and the answer is we’ve basically never tried it (we did once back around May 2014 but that was before I joined the company).  In theory it is simple, but in practice it is confusing but in the end pretty simple.

The core of the problem is that we rely on some unmanaged libraries as part of Couchbase Lite on both Java and .NET.  That means that it’s not just a simple matter of having the Java runtime (or .NET runtime) installed on the target device, but also compiling the unmanaged libraries for the target architecture.  In this case, we’ll be running ARM on Linux.  You might think that sounds exactly like Android, but copying the libraries from Android does not work (The ABI is different, I believe).  So the easiest thing to do would be to try to set up Gradle (the build system for our Java and Android projects) to compile this native library for us.  That means we need a cross compiler that will generate the correct architecture and ABI.  Luckily, if we have a Linux machine or VM then it is already available.  So really it is just a matter of pointing the gradle script in the right direction.  This is what I managed to do, on our Java native repo.

Gradle, by default, does not know about ARM targets for Java and so we need to explicitly tell it.  If you see in the ‘arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin’ folder all of our compilers, linkers, and everything we need for the build process is here.  We just need to say “USE THIS PLEASE.”  The way we do that is as follows:

You may notice a section that looks like this:

toolChains {
        visualCpp(VisualCpp)
        gcc(Gcc)
        clang(Clang)
}

These are the toolchains (default) available to Gradle.  However, we can override this based on the target we are building.  You may also notice above that we have a whole list of entries like this:

linux_x86 {
      architecture "x86"
      operatingSystem "linux"
}

So let’s add another one:

linux_arm {
      architecture "arm"
      operatingSystem "linux"
}

Now we can use this new linux_arm target to override the names of the tools we use to compile, link, etc.

toolChains {
        visualCpp(VisualCpp)
        gcc(Gcc) {
            target("linux_arm") {
                cppCompiler.executable = 'arm-linux-gnueabihf-g++'
                cCompiler.executable = 'arm-linux-gnueabihf-gcc'
                assembler.executable = 'arm-linux-gnueabihf-as'
                linker.executable = 'arm-linux-gnueabihf-g++'
                staticLibArchiver.executable = 'arm-linux-gnueabihf-ar'
            }
        }
        clang(Clang)
}

After that, before building, we just need to modify the PATH variable to include the location of the binaries we downloaded (i.e. export PATH=<path/to/tools>/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin:$PATH)

That’s all the setup we need for the compilation of the main native library for the Java project, but there is a wrinkle.  It is linked against other libraries that are precompiled, and those precompiled libraries are not available for ARM.  For now, we can safely discard all of the ICU libraries and just be careful not to use non-ASCII characters.  To do this sipmly comment out the lines:

lib library: 'libicui18n', linkage: 'static'
lib library: 'libicuuc',   linkage: 'static'
lib library: 'libicudata', linkage: 'static'

However, we still need SQLite.  Luckily, there is a build file there are well so if we repeat these steps for SQLite’s gradle script we can get the appropriate binary in the exact same way.  Once that is done, run the build-linux.sh script in the ‘vendor/sqlite’ subdirectory and then run gradlew -Pspec=java build in the ‘sqlite-custom’ directory.

Note that I opted in the end to split the top level gradle script out from regular java and name it build-cross.gradle so to run it use gradlew -Pspec=cross build instead.  This setup requires either a linux machine, or a build of the raspberry pi toolchain for whatever system you are running on.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s