I've been wanting to get Wasp running on Android and Gonk (the low level Android layer of Firefox OS) for debugging and small applications. One of the nice features of Wasp is being able to have a minimal interpreter running on a platform and send byte code from another system to that interpreter which is loaded and run. You can even send the bytecode compiler itself to be loaded and run in the interpreter to get a full system on the target. This is the basis of how MOSREF works where the drone gets sent code to run from the console system.
Building Wasp for Android requires generating a standalone toolchain from the Android NDK. This results in a vesion of
gcc and libraries that can be run from conventional makefiles and configure scripts.
To generate a standalone toolchain to build Wasp I used:
$NDK_ROOT/build/tools/make-standalone-toolchain.sh \ --platform=android-8 \ --install-dir=$STK_ROOT
NDK_ROOT with the path to the Android SDK and
STK_ROOT with the destination where you want the standalone toolkit installed. The
android-8 in the platform makes the standalone toolkit generate applications for FroYo and above (See STABLE-APIS.html.
$STK_ROOT/bin to the
PATH will make the compiler available:
Building libevent for Android
The Wasp virtual machine uses libevent to enable asynchronous operations. Building this for Android using the standalone toolkit is straightforward:
wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz tar xvf libevent-2.0.21-stable.tar.gz cd libevent-2.0.21-stable ./configure --host=arm-linux-androideabi --prefix=$STK_ROOT make make install
libevent to be built using the ARM compilers in the standalone toolkit and to install the resulting libraries in the same install location as the toolkit. This makes it easy for other applications to find and link with the library.
Building the Wasp stub for Android
A Wasp VM stub file is used for generating Wasp applications. The bytecode for an application is appended to the stub file and the result made to be executable. By having stubs for various operating systems and architectures you can create executables specific to them easily. To build the Android stub:
git clone git://github.com/swdunlop/WaspVM.git cd WaspVM STRIP=arm-linux-androideabi-strip \ CC=arm-linux-androideabi-gcc \ CFLAGS="-I $STK_ROOT/include -L $STK_ROOT/lib" \ ARCH=arm-linux \ OS=android \ make
To build we define the correct version of the build programs to compile for ARM and set the architecture and OS to stop the build system from picking up the host system version of these. The result is a
waspvm-android-arm-linux stub in the
Creating the host Wasp programs
To easily create Wasp programs for different platforms we'll need versions of them for the host we are running on. By doing a 'clean' followed by a 'make' on the host we'll clean out the Android build files and rebuild what's needed for the host. The 'clean' process doesn't remove the stub file we created in the previous step which still allows us to do android Wasp programs.
make clean make
This produces a
waspvm-linux-x86_64 stub in my
stubs directory. To generate the Wasp interpreter and other programs:
Exit out of the repl with
(exit) and there will be a
waspld program for the host system. Now we can make a version of
wasp for Android:
cd mod ../waspc -exe ../awasp -platform android-arm-linux bin/wasp.ms
waspc command takes a stub file (defined by the
stub argument) and appends the bytecode resulting from the compilation of the Wasp lisp code given as an argument.
wasp.ms is the source for the intepreter. The output is set as
awasp which is our executable for running on Android. We can use a similar command for producing Android versions of the other Wasp programs. MOSREF for example:
../waspc -exe ../amosref -platform android-arm-linux bin/mosref.ms
Running on Android
Running these executables on Android involves pushing them to somewhere writeable on the phone. If you have a rooted Android device (or a Firefox OS device) you can push them pretty much anywhere. On my non-rooted Jellybean Galaxy Note 2 I'm limited to just
adb push awasp /data/local/tmp adb shell cd /data/local/tmp chmod 0755 awasp ./awasp >> (+ 1 2 3) :: 6
This gives you a running Wasp interpreter. To develop and do interesting things on the phone you really need the Wasp
mod files and the stub files copied over:
adb push mod /data/local/tmp adb push stubs /data/local/tmp adb shell cd /data/local/tmp ./awasp >> (import "lib/http-client") :: #t >> (http-response-body (http-get "http://icanhazip.com/")) :: "xxx.xxx.xxx.xxx\n" >> (exit)
MOSREF Android drone
It's simple now to create a MOSREF drone that runs on Android. Make sure the MOSREF console has a
stubs directory containing the Android stub then create the drone as:
console> drone drone1 myphone android-arm-linux Drone executable created. Listening for drone on 10000...
Copy the created
drone1 onto the phone and run it:
adb push mod/drone1 /data/local/tmp adb shell cd /data/local/tmp chmod 0755 drone1 ./drone1
Now on the console you can see the drone on the phone:
console> nodes NODES: console online address: 192.168.1.101 port: 10000 myphone online console> on myphone sh ls ...directory listing... console on myphone do (print "hello\n") ...prints hello on the phone 'adb shell' session... console> on myphone load lib/http-file-server.ms :: spawn-http-file-server console> on myphone do (offer-http-file 8080 "/test" "text/plain" "Hello world!") :: [queue 1F5DD00]
load command shown above loads and compiles the Wasp lisp file on the host and sends the compiled bytecode to the drone on the phone. We then run the lisp code on the phone to start an HTTP server to serve data.