Android

ZeroMQ build for Android

Introduction : JeroMQ for Java

This page was originally helping to build and cross-compile JZMQ using a JNI bridge to the native library.
The process is risky, difficult, bad for code portability; only use it if you have very specific needs and strong reasons to do so.

For everybody using Java, especially with Android, it is STRONGLY recommended to use the pure-java implementation of ZeroMQ : JeroMQ instead.

According to many benchmarks it is also faster than using a JNI bridge.

Go download it : JeroMQ repository

Advanced users : Native build of JZMQ

This page will explain you how to build ZeroMQ along with Jzmq and its JAR, to be directly usable in Android and loaded into an APK file. It gives some preliminary solution for pyzmq as well.

The tutorial will be divided in two parts: one for ZeroMQ > 3.0 (where libuuid is no longer a dependency, thus making the whole process a lot easier) and another one, kept for reference, that will explain how to cope with older versions. For info where to put the final files in Eclipse, read the part Final thoughts at the end of the article.

General Prerequisites

Get Android NDK and use it to generate a standalone ARM toolchain.

cd /tmp
wget http://dl.google.com/android/ndk/android-ndk-r8-linux-x86.tar.bz2
tar xvfj android-ndk-r8-linux-x86.tar.bz2
sudo ./android-ndk-r8/build/tools/make-standalone-toolchain.sh --install-dir=/opt/android-toolchain
export PATH=/opt/android-toolchain/bin:$PATH

The above sudo is only there to write into /opt, if you choose another folder it may not be necessary.

Export the desired output directory in a dedicated variable; a folder that is writable by you is preferred, or you'll face issues at install time.

export OUTPUT_DIR=/tmp/zeromq-android

ZeroMQ 4.x

Use the following command lines:

cd /tmp/
git clone https://github.com/zeromq/libzmq.git
cd libzmq/
./autogen.sh
./configure --enable-static --disable-shared --host=arm-linux-androideabi --prefix=$OUTPUT_DIR LDFLAGS="-L$OUTPUT_DIR/lib" CPPFLAGS="-fPIC -I$OUTPUT_DIR/include" LIBS="-lgcc"
make
make install

Now download Jzmq from Github.

cd /tmp/
git clone https://github.com/zeromq/jzmq.git
cd jzmq/
./autogen.sh
./configure --host=arm-linux-androideabi --prefix=$OUTPUT_DIR --with-zeromq=$OUTPUT_DIR CPPFLAGS="-fPIC -I$OUTPUT_DIR/include" LDFLAGS="-L$OUTPUT_DIR/lib" --disable-version LIBS="-lpthread -lrt"
make
make install

The disable-version, enable-static and disable-shared flags ensure you'll generate a single libjzmq.so binary without version information, which is required to embed it into an APK. On newer systems, the parameter 'LIBS="-lpthread -lrt"' produces errors and has to be omited, because these librarys are already included.
If you're having problem on java environment, which will cause the configure failed with 'configure: error: cannot find zmq.h' or similar jni.h not found error , try to export the JAVA_HOME into your PATH environment:

export PATH=$JAVA_HOME/bin:$PATH

please make sure you have JAVA_HOME environment variable setup first:

echo $(/usr/libexec/java_home)
/Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home

Moreover, you'll have the zmq.jar archive that will help you use ZeroMQ directly. Here's the generated output :

[victor@Q]</tmp/jzmq> tree /tmp/zeromq-android/
/tmp/zeromq-android/
├── include
│   ├── zmq.h
│   └── zmq_utils.h
├── lib
│   ├── libjzmq.a
│   ├── libjzmq.la
│   ├── libjzmq.so
│   ├── libzmq.a
│   ├── libzmq.la
│   └── pkgconfig
│       └── libzmq.pc
└── share
    ├── java
    │   └── zmq.jar
    └── man
        ├── man3
        └── man7

8 directories, 9 files

ZeroMQ < 3.0

Complexity is increased because of the libuuid dependency. Follow this carefully.

First, before anything, download libuuid, inside the e2fsprogs package.

cd /tmp/
git clone git://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
cd e2fsprogs/
./configure --host=arm-linux-androideabi --prefix=$OUTPUT_DIR CFLAGS="-fPIC" 
cd lib/uuid
make
make install

Then, download and build ZeroMQ itself.

cd /tmp/
tar xzf zeromq-2.2.0.tar.gz
cd zeromq-2.2.0/
./autogen.sh
./configure --enable-static --disable-shared --host=arm-linux-androideabi --prefix=$OUTPUT_DIR --with-uuid=$OUTPUT_DIR LDFLAGS="-L$OUTPUT_DIR/lib" CPPFLAGS="-fPIC -I$OUTPUT_DIR/include" LIBS="-lgcc"
make
make install

See, the configure line is quite a bit longer. Now with Jzmq:

cd /tmp/
git clone https://github.com/zeromq/jzmq.git
cd jzmq/
./autogen.sh
./configure --host=arm-linux-androideabi --prefix=$OUTPUT_DIR --with-zeromq=$OUTPUT_DIR CPPFLAGS="-fPIC -I$OUTPUT_DIR/include" LDFLAGS="-L$OUTPUT_DIR/lib" --disable-version LIBS="-luuid"
make
make install

And there you are.

[victor@Q]</tmp> tree zeromq-android/
zeromq-android/
├── include
│   ├── uuid
│   │   └── uuid.h
│   ├── zmq.h
│   ├── zmq.hpp
│   └── zmq_utils.h
├── lib
│   ├── libjzmq.a
│   ├── libjzmq.la
│   ├── libjzmq.so
│   ├── libuuid.a
│   ├── libzmq.a
│   ├── libzmq.la
│   └── pkgconfig
│       ├── libzmq.pc
│       └── uuid.pc
└── share
    ├── java
    │   └── zmq.jar
    └── man
        ├── man3
        │   ├── uuid.3
        │   ├── uuid_clear.3
        │   ├── uuid_compare.3
        │   ├── uuid_copy.3
        │   ├── uuid_generate.3
        │   ├── uuid_generate_random.3
        │   ├── uuid_generate_time.3
        │   ├── uuid_is_null.3
        │   ├── uuid_parse.3
        │   ├── uuid_time.3
        │   ├── uuid_unparse.3
        │   ├── zmq_bind.3
        │   ├── zmq_close.3
        │   ├── zmq_connect.3
        │   ├── zmq_device.3
        │   ├── zmq_errno.3
        │   ├── zmq_getsockopt.3
        │   ├── zmq_init.3
        │   ├── zmq_msg_close.3
        │   ├── zmq_msg_copy.3
        │   ├── zmq_msg_data.3
        │   ├── zmq_msg_init.3
        │   ├── zmq_msg_init_data.3
        │   ├── zmq_msg_init_size.3
        │   ├── zmq_msg_move.3
        │   ├── zmq_msg_size.3
        │   ├── zmq_poll.3
        │   ├── zmq_recv.3
        │   ├── zmq_send.3
        │   ├── zmq_setsockopt.3
        │   ├── zmq_socket.3
        │   ├── zmq_strerror.3
        │   ├── zmq_term.3
        │   └── zmq_version.3
        └── man7
            ├── zmq.7
            ├── zmq_cpp.7
            ├── zmq_epgm.7
            ├── zmq_inproc.7
            ├── zmq_ipc.7
            ├── zmq_pgm.7
            └── zmq_tcp.7

9 directories, 54 files

Final thoughts

You should only have to take the built zmq.jar, place it in your application's in the libs/ folder. Add it to your build path in Eclipse if you're using Eclipse; ant should detect it nicely.
Then take the libjzmq.so file and put it in the libs/armeabi/ folder of your application, if your target has been armeabi since the beginning. Some users may want to put it in the armeabi-v7e folder instead.
Build your project with Eclipse or Ant, and it should work fine.

Remember that you will often have to activate special permissions to your app, for instance the android.permission.INTERNET for ZeroMQ's tcp transport protocol.

As a last word, if the generated binary us too huge (between 2.3 and 2.7 Mb) a good move is to strio/optimize it. To be straightforward, that means at least running

arm-linux-androideabi-strip --strip-all libjzmq.so

which reduces the binary size to about 600Kb, but you can also gain a few more Kb if using -ffunction-sections -fdata-sections -Wl,—gc-sections as additionnal CPPFLAGS.

And if you ever want to try pyzmq on Android, have a look at https://github.com/zeromq/pyzmq/issues/227

Notes

Please get Jzmq code using a fresh github's clone, since code prior to 06/06/2012 doesn't embed the necessary configure flags. If ever you had to use prior versions, have a look at:

https://github.com/vperron/android-jzeromq

… which is a quick&dirty collection of scripts to build Jzmq+ZeroMQ the same way. Adapt them, it may be helpful in those special cases.