Saturday, October 30, 2010

Gambit Scheme on Android

After a bit of work and research I've finally made gambit scheme (v4.6) work on android. I had to modify the source code a little bit to make it compile, my changes are as follows:


In lib/os_tty.c

add the following to the list of includes at the top of the file

#include <asm/termios.h>
#include <termios.h>
#include <signal.h>



on line ~790 comment out ctermid (term_name); /* get controlling terminal's name */

change line ~788 to char term_name[L_ctermid] = "/dev/tty";



In lib/os_io.c

add the following to the list of includes at the top of the file


#include <signal.h>
#include <asm/termios.h>
#include <termios.h>




on line ~6438 comment out <stropts.h>



comment out lines ~6503 to ~6509

The lines in question are:


if (!isastream (fd) || 
(ioctl (fd, I_PUSH, "ptem") >= 0 &&
ioctl (fd, I_PUSH, "ldterm") >= 0))
{
*slave_fd = fd;
return 0;
}




In lib/os.c

add #include <asm/signal.h> to the list of includes at the top of the file



In lib/os_time.c

add #include <asm/signal.h> to the list of includes at the top of the file





Now it's ready to compile. I used the crystax ndk to compile, I did have troubled with the official ndk but I'm unsure if another change I did fixed the issue or if it's a general ndk issue. I wrote a small build script to automate the task, the contents as follow:

export ANDROID_ROOT=/home/sean/dev/android-ndk-r4-crystax/build
export PATH=$PATH:$ANDROID_ROOT/prebuilt/linux-x86/arm-eabi-4.4.0/bin/
export LD=arm-eabi-ld
export AR=arm-eabi-ar
export STRIP=arm-eabi-strip
export RANLIB=arm-eabi-ranlib
export CC=arm-eabi-gcc
export CXX=arm-eabi-g++
export PREFIX=$ANDROID_ROOT/../gambc
./configure --enable-single-host --prefix=$PREFIX -host=arm-eabi CC=arm-eabi-gcc CPPFLAGS="-I$ANDROID_ROOT/platforms/android-5/arch-arm/usr/include/ -fno-short-enums" CFLAGS="-fno-short-enums -I$ANDROID_ROOT/platforms/android-5/arch-arm/usr/include/ -nostdlib" LDFLAGS="-fno-short-enums -Wl,-rpath-link=$ANDROID_ROOT/platforms/android-5/arch-arm/usr/lib/ -L$ANDROID_ROOT/platforms/android-5/arch-arm/usr/lib" LIBS="-lc -ldl"
make & make install



You will want to save this to the extracted gambit source directory, I called it build.sh . You will want to edit the paths in this to your liking, specifically PREFIX and ANDROID_ROOT. Now that gambit has been cross compile to android we can make a project.



I started with hello-jni sample project from the official ndk. There are three things that needed to be done; edit the Android.mk file, edit the jni c file and compile the scheme sources to c.



For compiling the scheme sources you just use "gsc -link file.scm" and it will spit out two files, file.c and file_.c. Here is my Android.mk file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := test
LOCAL_SRC_FILES := test-jni.c fib.c fib_.c
LOCAL_CFLAGS := -I./depends -fno-short-enums
LOCAL_LDLIBS := -ldl -fno-short-enums -lc -L./depends -lgambc

include $(BUILD_SHARED_LIBRARY)



you will want to change the CFLAGS and LDFLAGS to where the gambc include and lib directories are. In the jni folder I made a directory named depends and put the gambit.h and libgambc.a in it.



Here is my code for test-jni.c:


#define ___VERSION 406000

#include "test_test_test.h"
#include
#include
#include
#include "gambit.h"

#define LINKER ____20_fib__

___BEGIN_C_LINKAGE
extern ___mod_or_lnk LINKER (___global_state_struct*);
___END_C_LINKAGE

___setup_params_struct setup_params;

int fib(int x);

jstring Java_test_test_test_stringFromJNI (JNIEnv *env, jobject obj)
{
// Taken from gambit, lib/main.c.
int debug_settings = ___DEBUG_SETTINGS_INITIAL;

// -:d- (force repl io to be stdin/stdout since terminal isn't
// -attached)
debug_settings =
(debug_settings
& ~___DEBUG_SETTINGS_REPL_MASK)
| (___DEBUG_SETTINGS_REPL_STDIO
<< ___DEBUG_SETTINGS_REPL_SHIFT);
// -:da
debug_settings =
(debug_settings
& ~___DEBUG_SETTINGS_UNCAUGHT_MASK)
| (___DEBUG_SETTINGS_UNCAUGHT_ALL
<< ___DEBUG_SETTINGS_UNCAUGHT_SHIFT);
// -:dr
debug_settings =
(debug_settings
& ~___DEBUG_SETTINGS_ERROR_MASK)
| (___DEBUG_SETTINGS_ERROR_REPL
<< ___DEBUG_SETTINGS_ERROR_SHIFT);

___setup_params_reset (&setup_params);
setup_params.version = ___VERSION;
setup_params.linker = LINKER;
setup_params.debug_settings = debug_settings;

___setup(&setup_params);

char buffer[100];
int n = sprintf(buffer, "fib of 10 is: %d", fib(10));

return (*env)->NewStringUTF(env, buffer);
}



You will notice there is quite a bit extra in there, which is required for calling scheme functions from c without having scheme as the main entry point. The one thing that will have to change if you have a different scheme file is LINKER ____20_fib__, you will need to replace fib with the name of the main file you are compiling to scheme.



Now we can just build ndk library with ndk-build and then build the java portion and run. All my example does is output the string "fib of 10 is: 55".



For clarity I've upload a sample project to github. It also includes the precompiled libgambc.a so you won't need to recompile it yourself.



I'm hoping that this will be a nice way to develop games in scheme on my desktop and then port them to android. Anyways, have fun.

12 comments:

  1. Cool, thank you for sharing!

    Ravi

    ReplyDelete
  2. Via the gambit mailing list

    It appears someone ported Gambit to the Android...

    http://seanchapel.blogspot.com/2010/10/gambit-scheme-on-android.html

    Sean Chapel, if you are listening... can you make a reasonably clean patch I can add to the Gambit distribution? That way interested users will be able to compile Gambit on the Android "out-of-the-box". Also... did you get TCP networking to work? This would be useful for remote debugging.

    Marc

    ReplyDelete
  3. Thanks for the heads up on the mailing list, I'm continuing the discussion there and hope to get a patch going.

    ReplyDelete
  4. Hi Sean:
    Cool stuff.
    Is there any chance that I could get a copy of the Kore.zip file with the source from the
    SDL:Tutorials:Complete 2D Engine Graphics Core article? The link doesn't work any more.
    The tutorial is great, but the source would help me to understand better.
    Thanks,
    John memo21@jgssoftware.com

    ReplyDelete
  5. John,

    you can get it here: http://gpwiki.org/images/1/1c/Kore.zip .

    ReplyDelete
  6. Not sure if this will get to you Sean. I really loved your tutorials but am having some troubles with them, I have tried all of the links to get to the source so I can see a complete version of the engine, but they all seem to be dead. Including the one you referenced here. Is there any other location I could find it? Thanks for your time.

    ReplyDelete
  7. Not sure what you mean by engine. Perhaps this was suppose to be on another post?

    This post is about running gambit scheme on android. The above is also no longer necessary as it's been merged into gambit now.

    ReplyDelete
  8. I'm sorry for not being more clear. I was also refereeing to the same files John was after. The Kore.zip.

    ReplyDelete
  9. the gpwiki servers have moved, try here: http://content.gpwiki.org/images/1/1c/Kore.zip

    ReplyDelete
  10. Thank you very much sir. Sorry to snatch your post. Your tutorials are invaluable! You should post more often :)!

    ReplyDelete
  11. Is this the same as http://www.appszoom.com/android_applications/tools/gambit-for-android_bbyts.html ?

    ReplyDelete
  12. No. That's an android application for using the repl. This post is before gambit had android support out of the box and what I did to make it work.

    ReplyDelete