The cross-compilation process is fairly straight-forward using the Android NDK tools. Anything before libzmq 4.0 requires an additional step of cross-compiling libuuid for Android.
Preparing the build environment
In order to build software for Android the NDK package is required:
cd /tmp
wget http://dl.google.com/android/ndk/android-ndk-r6-linux-x86.tar.bz2
tar xfj android-ndk-r6-linux-x86.tar.bz2
In addition to downloading the NDK there is a build step for preparing the environment:
/tmp/android-ndk-r6/build/tools/make-standalone-toolchain.sh --platform=android-5 --install-dir=/opt/android-toolchain
After installation of the toolchain, the PATH variable needs to be modified to contain the newly installed tools:
export PATH=/opt/android-toolchain/bin:$PATH
Cross-compiling libuuid
The first step is to acquire the libuuid sources for the cross-compilation.
cd /tmp
git clone git://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
After downloading e2fsprogs, the config.guess and config.sub shipped with the standard installation need to be updated to recognise Android build.
cd /tmp/e2fsprogs/config
wget http://git.savannah.gnu.org/cgit/config.git/plain/config.guess -O config.guess
wget http://git.savannah.gnu.org/cgit/config.git/plain/config.sub -O config.sub
The next step is to build the libuuid library for Android platform. Because we only need to install libuuid, there is no need to build the whole package.
cd /tmp/e2fsprogs
./configure --target=arm-linux-androideabi --host=arm-linux-androideabi --prefix=/opt/android-root
cd lib/uuid/
make
make install
This step should create directories in /opt/android-root, which now contain the libraries and headers needed to build ZeroMQ.
Cross-compiling ZeroMQ
Android file access modes doesn't contain S_IWRITE symbol definition. Until this patch is accepted and applied to zeromq master branch this extra step will be necessary.
- Download or clone git zeromq on your /tmp folder.
- Download the patch
cd /tmp/zeromq2-1
patch -p0 < zmq_android.patch
For an unreleased branch, run "sh ./autogen.sh".
When the source is ready for configuring we need to update config.sub and config.guess inside the ZeroMQ package:
# cd /tmp/zeromq2-1/config
# wget http://git.savannah.gnu.org/cgit/config.git/plain/config.guess -O config.guess
# wget http://git.savannah.gnu.org/cgit/config.git/plain/config.sub -O config.sub
Next step is to build ZeroMQ.
# cd /tmp/zeromq2-1
# ./configure --target=arm-linux-androideabi --host=arm-linux-androideabi \
LDFLAGS="-L/opt/android-root/lib" \
CPPFLAGS="-I/opt/android-root/include" \
--prefix=/opt/android-root
# make
# make install
If everything went according to the plan you should now have ZeroMQ installed in /opt/android-root.
Alternative build process
The file builds/android/builds.sh (may not be in the current development master) will build Android.
Sverre's previous instructions
To build zeromq for the Android platform, you will need an unofficial NDK, with full STL support.
See the comments in the create.sh script from the package azmq.tar.bz2. The zmq sources were only slightly modified as seen in the .patch file in the package to disable two POSIX optimization functions not (directly) available on Android. A precompiled version of the library and a minimalist test program is also available in the output folder.
Download: azmq.tar.bz2
What I did to get this running on android with java bindings:
First:
Download the ndk as explained in the create.sh script.
I had to modify in the ndk the file NDK_ROOT/build/core/add-application.mk with the default platform to android-8, maybe I misunderstood the text in create.sh because I first thought this was not needed.
Then I executed the script so you are sure this works. I also tested the test app in the android emulator shell as explained in the create.sh
So far so good.
Getting the java bindings and including it in an android project:
I cloned the git jzmq branch head (last commit was 522d7474effe8c96dfaece51e739eda9189bad45 23 Feb 13.55.57)
I executed the autogen.sh and configure commands (This is a potential pitfall I think, as this configure was run against my linux host box and not the android development tools)
The configure resulted in the config.hpp header being generated in the src folder.
Now I moved the org folder (jzmq/src/org) to my src folder in the android project I wanted it included in.
I modified the ZMQ.java file changing the System.loadLibrary("jzmq") to System.loadLibrary("ajzmq")
Then I made a jni folder in the android project folder and copied the source files in the jzmq/src folder there, I also copied the zmq folder and uuid folder from the azmq.tar.bz2 file into the jni folder.
I removed the Android.mk file in the zmq and uuid folder and created a new one placed in the jni folder.
The new Android.mk file:
BASE_PATH := $(call my-dir)
APP_PLATFORM = android-8
# build uuid
include $(CLEAR_VARS)
LOCAL_PATH := $(BASE_PATH)/uuid/
LOCAL_MODULE := uuid
LOCAL_SRC_FILES := compare.c gen_uuid.c isnull.c parse.c unpack.c clear.c copy.c pack.c unparse.c uuid_time.c
include $(BUILD_STATIC_LIBRARY)
# build zmq
include $(CLEAR_VARS)
LOCAL_PATH := $(BASE_PATH)/zmq/
LOCAL_MODULE := zmq
LOCAL_SRC_FILES := clock.cpp options.cpp socket_base.cpp command.cpp own.cpp streamer.cpp connect_session.cpp pair.cpp sub.cpp ctx.cpp pgm_receiver.cpp swap.cpp decoder.cpp pgm_sender.cpp tcp_connecter.cpp devpoll.cpp pgm_socket.cpp tcp_listener.cpp encoder.cpp pipe.cpp tcp_socket.cpp epoll.cpp poll.cpp thread.cpp err.cpp poller_base.cpp transient_session.cpp forwarder.cpp pub.cpp trie.cpp fq.cpp pull.cpp uuid.cpp io_object.cpp push.cpp xrep.cpp io_thread.cpp queue.cpp xreq.cpp ip.cpp rep.cpp zmq_connecter.cpp kqueue.cpp req.cpp zmq.cpp lb.cpp select.cpp zmq_engine.cpp named_session.cpp session.cpp zmq_init.cpp object.cpp zmq_listener.cpp mailbox.cpp
include $(BUILD_STATIC_LIBRARY)
# build Android Java Bindings for zmq
include $(CLEAR_VARS)
LOCAL_PATH := $(BASE_PATH)
LOCAL_MODULE := ajzmq
LOCAL_PRELINK_MODULE := false
LOCAL_SRC_FILES := ZMQ.cpp Context.cpp Socket.cpp Poller.cpp util.cpp
LOCAL_STATIC_LIBRARIES := zmq uuid
LOCAL_LDLIBS := -lc -lm -lstdc++
include $(BUILD_SHARED_LIBRARY)
With this in place I also made a script file (in the android project root) for building the libajzmq.so file.
#!/bin/bash
cd bin
javah -jni org.zeromq.ZMQ
mv *.h ../jni/
cd ..
~/project/android-ndk/android-ndk-r4-crystax/ndk-build
Executing this script should compile the libajzmq.so and place it in the folder libs/armeabi/ in the android project.
The header files for the zmq and uuid was copied into the ndk when the create.sh script was executed, so I did not do this again.
Now you have to remember to set <uses-permission android:name="android.permission.INTERNET"/> in the AndroidManifest.xml file.
With this and a port routing through the emulator I managed to communicate with a python process on my linux box.
