NOTE: The following information is ancient info on how to compile CouchDB 1.x for Android. You probably really, really don't want this. Modern users will prefer to use https://pouchdb.com/ for almost all needs.

Another old resource that may help is at https://github.com/couchbaselabs/Android-Couchbase-SourceBuild .





Installing CouchDB on Android (from source)

Update February 27th, 2011

Below are updated instructions that produce a build that is better organized for Android, somewhat more lightweight in the final product and slightly more straightforward to understand (and with support for replications over a SSH reverse proxy!). This build requires updates to the Android installer that have not yet been pushed upstream so please don't expect this to work out-of-the-box.

Caveats

Credits

A lot of the credit should go to Aaron Miller for doing the original port upon which these instructions are based. I would also like to thank Wes and Chris C. Coulson from #jsapi and Dale Harvey, davisp and rnewson from #couchdb. Thanks to everyone else who helped, too.



Overview & Instructions

The following build instructions are intended for Android 2.2.2 and were run on Debian Squeeze. The "scripts" below were run with Bash from a single directory that I called android-build.

I used Java 1.5.0.22 to build Android from source. You will also need an SDK (I used r08).

See couch-android-launcher and libcouch-android for the end-user Android application that will use the package produced by this build.

Supporting these builds are a number of helper scripts and patches, see below.

Step 1: Build Android from Source


cd ~/software/android/sdk/sources

repo init -b froyo
repo sync

source build/envsetup.sh

export JAVA_HOME=$HOME/software/jdk1.5.0_22
export ANDROID_JAVA_HOME=$JAVA_HOME
export PATH=$JAVA_HOME/bin:$PATH

lunch
make -s


Step 2: Build cURL


VERSION=7.20.0

[[ -f curl-$VERSION.tar.bz2 ]] || wget http://curl.haxx.se/download/curl-$VERSION.tar.bz2

rm -rf curl-$VERSION
tar jxf curl-$VERSION.tar.bz2
cd curl-$VERSION

# See AndroidEnv in Installing_on_Android wiki topic
source $HOME/software/android/scripts/env
ANDROID_SDK=$HOME/software/android/sdk

CPPFLAGS="-I$ANDROID_SDK/sources/external/openssl/include -I$ANDROID_SDK/sources/external/zlib" \
CC=agcc \
./configure \
--disable-shared \
--without-random \
--host=arm-linux
--disable-tftp \
--disable-sspi \
--disable-ipv6 \
--disable-ldaps \
--disable-ldap \
--disable-telnet \
--disable-pop3 \
--disable-ftp \
--with-ssl=$ANDROID_SDK/sources/external/openssl \
--disable-imap \
--disable-smtp \
--disable-pop3 \
--disable-rtsp \
--disable-ares \
--without-ca-bundle \
--disable-warnings \
--disable-manual \
--without-nss \
--with-zlib=$ANDROID_SDK/sources/external/zlib

make -s


Step 3: Build Mozilla NSPR & Spidermonkey

The following instructions are based on the Fennec instructions for building JS/NSPR only. We used their Android NDK package for the builds.


Retrieve mozilla-current


HGREV=bb9089ae2322

[[ -f mozilla-central-$HGREV.tar.bz2 ]] || wget http://hg.mozilla.org/mozilla-central/archive/$HGREV.tar.bz2
    
rm -rf mozilla-central mozilla-central-$HGREV
tar -jxf mozilla-central-$HGREV.tar.bz2
ln -s mozilla-central-$HGREV mozilla-central

cd mozilla-central

# Use of __android_log_print and __android_log_write requires liblog.so from our
# toolchain.  However, llog also has a dependency on libstdc++.so which our toolchain
# DOES NOT have so we need to substitute for something less Androidy (apologies).
patch -p1 < ../mozilla-central.patch


NSPR

NSPR isn't technically required but it is heavily integrated into current versions of Spidermonkey and future versions will almost certainly require it.

Also, NSPR will compile against current NDKs but I choose to use the recommended one (ndk-r4c-0moz3) for the sake of consistency. The next step (Spidermonkey) requires the specified NDK version.


source $HOME/software/android/scripts/env
ANDROID_NDK=$HOME/software/android/android-ndk-r4c

cd mozilla-central/nsprpub

./configure \
--target=arm-android-eabi \
--with-android-ndk=$ANDROID_NDK \
--with-android-platform=$ANDROID_NDK/build/platforms/android-8/arch-arm \
--enable-strip

make -s

# Remove shared libraries so that Couch is built with the static ones
rm dist/lib/*so


Spidermonkey

Be aware that Spidermonkey will not build against Android NDK r5 (we haven't checked this issue recently, it may have changed).


ANDROID_NDK=$HOME/software/android/android-ndk-r4c

cd mozilla-central/js/src
autoconf2.13

./configure \
--target=arm-android-eabi \
--with-android-ndk=$ANDROID_NDK \
--with-android-sdk=$ANDROID_NDK/build/platforms/android-8 \
--with-android-version=8 \
--disable-tests \
--disable-shared \
--enable-static \
--enable-strip \
--enable-endian=little \
--with-arm-kuser \
--enable-threadsafe \
--with-nspr-cflags=-I$(pwd)/../../nsprpub/dist/include/nspr \
--with-nspr-libs="-L$(pwd)/../../nsprpub/dist/lib -lnspr4 -lplc4 -lplds4" 

make -s

##
# Remove the shared lib to force Couch to link statically
# (this isn't working due to Android toolchain difficulties)
#
#rm libmozjs.so
#mv libjs_static.a libmozjs.a

You should add --enable-debug and --disable-optimizations for development builds or when running the Futon test suite for the first time (assertions matter).


Step 4: Build Erlang/OTP

An updated port of Erlang that will work on Android would be greatly appreciated! I know there has been some work on this by the Erlang folks but I am not aware of the location of the build instructions, source code or patches.


rm -rf otp
rm -rf otp_rel
git clone git://github.com/apage43/otp.git
cd otp
git checkout origin/android

## 
# 1) Add back in support for the "beam" binary
# 2) Our default autoconf is 2.67 and we need to switch back to 2.59
#    for this operation
# 3) Environment differences between Android and UNIX (bin/sh)
#
patch -p1 < ../otp.patch

source $HOME/software/android/scripts/env
export ANDROID_SDK=$HOME/software/android/sdk
export ANDROID_SYS_ROOT=$ANDROID_SDK/sources

./otp_build autoconf
./otp_build configure --xcomp-conf=xcomp/erl-xcomp-android.conf
./otp_build boot -a
./otp_build release -a $(pwd)/../otp_rel


Step 5: Compile Couch


rm -rf couchdb
rm -rf /sdcard/*
git clone git://github.com/apache/couchdb.git
cd couchdb
git checkout 1.0.2

##
# 1) Android Build Support from https://github.com/apage43/couchdb/tree/0.11.x-android
# 2) Mozilla JS compatibility by chrisccoulson from jsapi@irc.mozilla.org
# 3) Fixes for Android by matt.adams-couch@radicaldynamic.com
#
patch -p1 < ../couchdb.patch

./bootstrap

source $HOME/software/android/scripts/env
ANDROID_SDK=$HOME/software/android/sdk

ERL=$(pwd)/../otp/bootstrap/bin/erl \
ERLC=$(pwd)/../otp/bootstrap/bin/erlc \
CC=agcc \
./configure \
--host=arm-eabi \
--prefix=/sdcard/Android/data/com.your.namespace/couchdb \
--with-android=$ANDROID_SDK/sources \
--with-android-curl=$(pwd)/../curl-7.20.0 \
--with-erlang=$(pwd)/../otp_rel/usr/include \
--with-js-include=$(pwd)/../mozilla-central/js/src/dist/include \
--with-js-lib="$(pwd)/../mozilla-central/js/src"

make -s
make install


Step 6: Package for use on Android


if [ -z "$1" ]; then
    echo "Give me a release number bub!"
    exit 1
fi

DATE=$(date +"%Y-%m-%d_%H-%M-%S")
RELEASE="release-$DATE"

mkdir -p $RELEASE/data/data/com.your.namespace

##
# Configure and package Erlang/OTP
#

cp -Rdp otp_rel otp_rel.package

cd otp_rel.package

./Install -cross -sasl /data/data/com.your.namespace/erlang
rm Install

# Necessary?
chmod -x erts-5.7.5/bin/start_erl.src erts-5.7.5/bin/start.src

# Remove unnecessary files
rm -rf erts-5.7.5/doc erts-5.7.5/include erts-5.7.5/man erts-5.7.5/src misc releases usr

# Pare lib directory
libs_to_keep="crypto-1.6.4 erts-5.7.5 inets-5.3 kernel-2.13.5 public_key-0.5 sasl-2.1.9 ssl-3.10.8 stdlib-1.16.5 xmerl-1.2.4"

cd lib
mkdir backuplib

for i in $libs_to_keep
do
    mv $i backuplib/
done

mv backuplib ../
rm -rf *

mv ../backuplib/* .
rmdir ../backuplib

# Remove vestigal files
find . -depth -name src -type d -exec rm -rf {} \;
find . -depth -name examples -type d -exec rm -rf {} \;
find . -depth -name include -type d -exec rm -rf {} \;

cd ../..

##
# Finally move things into place
#

cp -Rdp /sdcard $RELEASE/sdcard
mv otp_rel.package $RELEASE/sdcard/Android/data/com.your.namespace/erlang

# We need the shared lib because our toolchain does not support the static lib (libstdc++ stuff)
cp mozilla-central/js/src/libmozjs.so $RELEASE/sdcard/Android/data/com.your.namespace/couchdb/lib/couchdb/bin

###
# 1) DNS fixes from apage43's couchdb-android.s3.amazonaws.com/dns-fix.tgz
# 2) Create couchjs_wrapper script (because we can't link to libmozjs.a and so need LD_LIBRARY_PATH set)
# 3) Update #!/bin/sh in data/data/com.your.namespace/erlang/lib/couch-1.0.1/priv/couchspawnkillable
# 4) Reflect new locations and the Android environment
#
rm release
ln -s $RELEASE release
patch -p0 < release.patch

chmod +x $RELEASE/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs_wrapper

# Build ICU for whatever version of Android was compiled in ~/software/android/sdk/sources
source $HOME/software/android/scripts/env

agcc \
-shared \
-o $RELEASE/sdcard/Android/data/com.your.namespace/couchdb/lib/couchdb/couch_icu_driver.so couchdb/src/couchdb/priv/.libs/libcouch_icu_driver.a \
-licuuc \
-licudata \
-licui18n \
-L$HOME/projects/couch/android-build/otp_rel/erts-5.7.5/bin \
-lbeam

##
# Remove vestigal files from Couch directory
# (Futon is in www)
#
cd $RELEASE/sdcard/Android/data/com.your.namespace/couchdb
rm -rf share/couchdb/www share/doc share/man
cd ../../../../../..

##
# Archive the release
#
cd $RELEASE
# filecount. is used so we can present a progress-based indicator during install
touch filecount.$(find | wc -l)
tar -czf ../release-$1.tgz filecount.* data sdcard
cd ..



Android Environment

This script simply sets up a good environment for building with Android.


paths="
$HOME/software/android/scripts
$HOME/software/android/other/apk
$HOME/software/android/sdk/platform-tools
$HOME/software/android/sdk/platforms/android-8/tools
$HOME/software/android/sdk/sources/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin
$HOME/software/android/sdk/tools
"

for i in $paths
do
    if [[ -d $i ]]; then
        PATH=$PATH:$i
    fi
done

export PATH

# Java stuff for building Android from sources
echo "For building Android from sources:"
echo "$ export JAVA_HOME=$HOME/software/jdk1.5.0_22"
echo "$ export ANDROID_JAVA_HOME=\$JAVA_HOME"
echo "$ export PATH=\$JAVA_HOME/bin:$PATH"
echo "$ cd $HOME/software/android/sdk/sources"
echo "$ source build/envsetup.sh"
echo "$ lunch"
echo "$ make"


agcc support

The Android toolchain is a little complicated so I used http://plausible.org/andy/agcc [dead link, try https://github.com/nitomartinez/agcc instead] to simplify the process. Here is my patch against that script:


--- agcc.old    2011-01-23 19:47:49.000000000 -0700
+++ agcc        2011-01-29 15:43:58.000000000 -0700
@@ -39,7 +39,10 @@
 my $DROID = $1;
 
 my $ALIB = "$DROID/out/target/product/generic/obj/lib";
-my $TOOLCHAIN = "$DROID/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1";
+my $TOOLCHAIN = "$DROID/prebuilt/linux-x86/toolchain/arm-eabi-4.4.0";
+
+print STDERR "ALIB ........ $ALIB\n";
+print STDERR "TOOLCHAIN ... $TOOLCHAIN\n";
 
 my @include_paths = (
     "-I$DROID/system/core/include",
@@ -85,6 +88,7 @@
     "-mthumb-interwork",
     "-fpic",
     "-fno-exceptions",
+    "-fno-short-enums", # See www for why we added this
     "-ffunction-sections",
     "-funwind-tables", # static exception-like tables
     "-fstack-protector", # check guard variable before return
@@ -114,7 +118,7 @@
     "-nostdlib",
     "$ALIB/crtend_android.o",
     "$ALIB/crtbegin_dynamic.o",
-    "$TOOLCHAIN/lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a",
+    "$TOOLCHAIN/lib/gcc/arm-eabi/4.4.0/interwork/libgcc.a",
     "-lc",
     "-lm");
     
@@ -129,7 +133,7 @@
     "-lc",
     "-lm",
     "-Wl,--no-undefined",
-    "$TOOLCHAIN/lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a",
+    "$TOOLCHAIN/lib/gcc/arm-eabi/4.4.0/interwork/libgcc.a",
     "-Wl,--whole-archive"); # .a, .o input files go *after* here
 
 # Now implement a quick parser for a gcc-like command line

couchdb patch

This old patch to 1.0.2 was apparently necessary to get CouchDB to compile on Android. Your mileage may vary.

diff --git a/configure.ac b/configure.ac
index c609a08..a31bc7b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -118,6 +118,21 @@ Is the Mozilla SpiderMonkey library installed?])])])])])
 
 AC_SUBST(JS_LIB_BASE)
 
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_FreezeObject],
+    AC_DEFINE([HAVE_JS_FREEZE_OBJECT], [1], [Define whether we have JS_FreezeObject]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_NewGlobalObject],
+    AC_DEFINE([HAVE_JS_NEW_GLOBAL_OBJECT], [1], [Define whether we have JS_NewGlobalObject]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [js_fgets],
+    AC_DEFINE([HAVE_JS_FGETS], [1], [Define whether js_fgets is available to use]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_GetStringCharsAndLength],
+    AC_DEFINE([HAVE_JS_GET_STRING_CHARS_AND_LENGTH], [1], [Define whether we have JS_GetStringCharsAndLength]))
+
+AC_CHECK_LIB([$JS_LIB_BASE], [JS_NewCompartmentAndGlobalObject],
+    AC_DEFINE([HAVE_COMPARTMENTS], [1], [Define whether we have JS_NewCompartmentAndGlobalObject]))
+
 if test x${IS_WINDOWS} = xTRUE; then
     if test -f "$JS_LIB_DIR/$JS_LIB_BASE.dll"; then
         # seamonkey 1.7- build layout on Windows
@@ -189,6 +204,13 @@ AC_COMPILE_IFELSE(
 CFLAGS="$OLD_CFLAGS"
 AC_LANG_POP(C)
 
+AC_ARG_WITH([android], [AC_HELP_STRING([--with-android=PATH]
+    [set Android system build path])],[
+    ICU_CONFIG="" 
+    ICU_LOCAL_CFLAGS="-I$withval/external/icu4c/common -I$withval/external/icu4c/i18n"
+    ICU_LOCAL_LDFLAGS="-L$withval/out/target/product/generic/system/lib"
+    ICU_LOCAL_BIN=
+], [
 AC_ARG_WITH([win32-icu-binaries], [AC_HELP_STRING([--with-win32-icu-binaries=PATH],
     [set PATH to the Win32 native ICU binaries directory])], [
     ICU_CONFIG="" # supposed to be a command to query options...
@@ -200,13 +222,19 @@ AC_ARG_WITH([win32-icu-binaries], [AC_HELP_STRING([--with-win32-icu-binaries=PAT
     ICU_LOCAL_CFLAGS=`$ICU_CONFIG --cppflags-searchpath`
     ICU_LOCAL_LDFLAGS=`$ICU_CONFIG --ldflags-searchpath`
     ICU_LOCAL_BIN=
-])
+])])
 
 AC_SUBST(ICU_CONFIG)
 AC_SUBST(ICU_LOCAL_CFLAGS)
 AC_SUBST(ICU_LOCAL_LDFLAGS)
 AC_SUBST(ICU_LOCAL_BIN)
 
+AC_ARG_WITH([android-curl], [AC_HELP_STRING([--with-android-curl=PATH]
+    [set PATH to directory where curl is built for android])], [
+    CURL_CFLAGS="-I$withval/include -DCURL_STATICLIB"
+    CURL_LIBDIR="$withval/lib"
+    CURL_LDFLAGS="-L$CURL_LIBDIR -lcurl"
+], [
 AC_ARG_WITH([win32-curl], [AC_HELP_STRING([--with-win32-curl=PATH],
     [set PATH to the Win32 native curl directory])], [
     # default build on windows is a static lib, and that's what we want too
@@ -216,12 +244,15 @@ AC_ARG_WITH([win32-curl], [AC_HELP_STRING([--with-win32-curl=PATH],
 ], [
     AC_CHECK_CURL([7.18.0])
     CURL_LDFLAGS=-lcurl
-])
+])])
 
 AC_SUBST(CURL_CFLAGS)
 AC_SUBST(CURL_LIBS)
 AC_SUBST(CURL_LDFLAGS)
 
+#Probably should fix this up better in the future for cross-compiles in general
+#instead of just keeping this exception for android
+if test "x$CC" != "xagcc"; then
 case "$(uname -s)" in
   Linux)
     LIBS="$LIBS -lcrypt"
@@ -234,6 +265,7 @@ case "$(uname -s)" in
     LIBS="$LIBS -lcrypto"
   ;;
 esac
+fi
 
 AC_PATH_PROG([ERL], [erl])
 
diff --git a/src/couchdb/priv/couch_js/http.c b/src/couchdb/priv/couch_js/http.c
index 6c2a8a8..5a2112d 100644
--- a/src/couchdb/priv/couch_js/http.c
+++ b/src/couchdb/priv/couch_js/http.c
@@ -43,6 +43,10 @@ char* METHODS[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "COPY", NULL};
 #define DELETE  4
 #define COPY    5
 
+#ifdef JSFUN_CONSTRUCTOR
+#define JSFUN_FAST_NATIVE 0
+#endif
+
 static JSBool
 go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t blen);
 
@@ -50,10 +54,21 @@ static JSString*
 str_from_binary(JSContext* cx, char* data, size_t length);
 
 static JSBool
+#ifdef JSFUN_CONSTRUCTOR
+constructor(JSContext* cx, uintN argc, jsval* vp)
+#else
 constructor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+#endif
 {
     HTTPData* http = NULL;
     JSBool ret = JS_FALSE;
+#ifdef JSFUN_CONSTRUCTOR
+    JSObject* obj = JS_NewObjectForConstructor(cx, vp);
+    if(!obj) {
+        JS_ReportError(cx, "Failed to create 'this' object");
+        goto error;
+    }
+#endif
 
     http = (HTTPData*) malloc(sizeof(HTTPData));
     if(!http)
@@ -80,6 +95,9 @@ error:
     if(http) free(http);
 
 success:
+#ifdef JSFUN_CONSTRUCTOR
+    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
+#endif
     return ret;
 }
 
@@ -89,7 +107,8 @@ destructor(JSContext* cx, JSObject* obj)
     HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
     if(!http)
     {
-        fprintf(stderr, "Unable to destroy invalid CouchHTTP instance.\n");
+        // Comment out -- this messes up CouchDB and doesn't seem to be a big deal anyway
+        //fprintf(stderr, "Unable to destroy invalid CouchHTTP instance.\n");
     }
     else
     {
@@ -100,13 +119,20 @@ destructor(JSContext* cx, JSObject* obj)
 }
 
 static JSBool
-open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
-{    
+open(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSBool ret = JS_FALSE;
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    if(!obj) {
+        JS_ReportError(cx, "No 'this' object");
+        goto done;
+    }
+
     HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
     char* method = NULL;
     char* url = NULL;
-    JSBool ret = JS_FALSE;
     int methid;
+    jsval* argv = JS_ARGV(cx, vp);
 
     if(!http)
     {
@@ -174,6 +200,7 @@ open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
     // Disable Expect: 100-continue
     http->req_headers = curl_slist_append(http->req_headers, "Expect:");
 
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     ret = JS_TRUE;
 
 done:
@@ -182,14 +209,21 @@ done:
 }
 
 static JSBool
-setheader(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
-{    
+setheader(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSBool ret = JS_FALSE;
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    if(!obj) {
+        JS_ReportError(cx, "No 'this' object");
+        goto done;
+    }
+
     HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
     char* keystr = NULL;
     char* valstr = NULL;
     char* hdrbuf = NULL;
     size_t hdrlen = -1;
-    JSBool ret = JS_FALSE;
+    jsval* argv = JS_ARGV(cx, vp);
 
     if(!http)
     {
@@ -234,6 +268,7 @@ setheader(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
     snprintf(hdrbuf, hdrlen, "%s: %s", keystr, valstr);
     http->req_headers = curl_slist_append(http->req_headers, hdrbuf);
 
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     ret = JS_TRUE;
 
 done:
@@ -245,12 +280,19 @@ done:
 }
 
 static JSBool
-sendreq(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+sendreq(JSContext* cx, uintN argc, jsval* vp)
 {
+    JSBool ret = JS_FALSE;
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    if(!obj) {
+        JS_ReportError(cx, "No 'this' object");
+        goto done;
+    }
+
     HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
     char* body = NULL;
     size_t bodylen = 0;
-    JSBool ret = JS_FALSE;
+    jsval* argv = JS_ARGV(cx, vp);
     
     if(!http)
     {
@@ -270,6 +312,9 @@ sendreq(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
 
     ret = go(cx, obj, http, body, bodylen);
 
+    if (ret == JS_TRUE)
+        JS_SET_RVAL(cx, vp, JSVAL_VOID);
+
 done:
     if(body) free(body);
     return ret;
@@ -285,7 +330,12 @@ status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
         JS_ReportError(cx, "Invalid CouchHTTP instance.");
         return JS_FALSE;
     }
-    
+#ifndef INT_FITS_IN_JSVAL
+    // jsval's are 64-bits wide in mozjs >= 2.0, so a jsint
+    // can use the full 32-bits now no bits are reserved for tagging
+    *vp = INT_TO_JSVAL(http->last_status);
+    return JS_TRUE;
+#else    
     if(INT_FITS_IN_JSVAL(http->last_status))
     {
         *vp = INT_TO_JSVAL(http->last_status);
@@ -296,6 +346,7 @@ status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
         JS_ReportError(cx, "INTERNAL: Invalid last_status");
         return JS_FALSE;
     }
+#endif
 }
 
 JSClass CouchHTTPClass = {
@@ -320,9 +371,9 @@ JSPropertySpec CouchHTTPProperties[] = {
 };
 
 JSFunctionSpec CouchHTTPFunctions[] = {
-    {"_open", open, 3, 0, 0},
-    {"_setRequestHeader", setheader, 2, 0, 0},
-    {"_send", sendreq, 1, 0, 0},
+    {"_open", open, 3, JSFUN_FAST_NATIVE, 0},
+    {"_setRequestHeader", setheader, 2, JSFUN_FAST_NATIVE, 0},
+    {"_send", sendreq, 1, JSFUN_FAST_NATIVE, 0},
     {0, 0, 0, 0, 0}
 };
 
diff --git a/src/couchdb/priv/couch_js/main.c b/src/couchdb/priv/couch_js/main.c
index 376aa15..f4bef7c 100644
--- a/src/couchdb/priv/couch_js/main.c
+++ b/src/couchdb/priv/couch_js/main.c
@@ -28,14 +28,38 @@ int gExitCode = 0;
 #define FINISH_REQUEST(cx) \
     JS_EndRequest(cx); \
     JS_ClearContextThread(cx);
+#define FINISH_REQUEST_AND_DESTROY(cx) \
+    JS_EndRequest(cx); \
+    JS_DestroyContext(cx);
 #else
 #define SETUP_REQUEST(cx)
 #define FINISH_REQUEST(cx)
+#define FINISH_REQUEST_AND_DESTROY(cx) \
+    JS_DestroyContext(cx);
+#endif
+
+#ifdef JSFUN_CONSTRUCTOR
+#define JSFUN_FAST_NATIVE 0
 #endif
 
+static JSClass global_class = {
+    "GlobalClass",
+    JSCLASS_GLOBAL_FLAGS,
+    JS_PropertyStub,
+    JS_PropertyStub,
+    JS_PropertyStub,
+    JS_PropertyStub,
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    JS_FinalizeStub,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
 static JSBool
-evalcx(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+evalcx(JSContext* cx, uintN argc, jsval* vp)
 {
+    jsval* argv = JS_ARGV(cx, vp);
     JSString *str;
     JSObject *sandbox;
     JSContext *subcx;
@@ -43,6 +67,9 @@ evalcx(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
     size_t srclen;
     JSBool ret = JS_FALSE;
     jsval v;
+#ifdef HAVE_COMPARTMENTS
+    JSCrossCompartmentCall *call = NULL;
+#endif
 
     sandbox = NULL;
     if(!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sandbox))
@@ -59,42 +86,70 @@ evalcx(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
     SETUP_REQUEST(subcx);
 
+#ifdef HAVE_JS_GET_STRING_CHARS_AND_LENGTH
+    src = JS_GetStringCharsAndLength(cx, str, &srclen);
+#else
     src = JS_GetStringChars(str);
     srclen = JS_GetStringLength(str);
+#endif
 
+#ifdef HAVE_COMPARTMENTS
+    /* Re-use the compartment associated with the main context,
+     * rather than creating a new compartment */
+    JSObject *global = JS_GetGlobalObject(cx);
+    if(!global)
+    {
+       goto done;
+    }
+    call = JS_EnterCrossCompartmentCall(subcx, global);
+#endif
     if(!sandbox)
     {
+#ifdef HAVE_JS_NEW_GLOBAL_OBJECT
+        sandbox = JS_NewGlobalObject(subcx, &global_class);
+#else
         sandbox = JS_NewObject(subcx, NULL, NULL, NULL);
+#endif
         if(!sandbox || !JS_InitStandardClasses(subcx, sandbox)) goto done;
     }
 
     if(srclen == 0)
     {
-        *rval = OBJECT_TO_JSVAL(sandbox);
+        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(sandbox));
     }
     else
     {
-        JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, rval);
+        JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, &JS_RVAL(cx, vp));
     }
-    
+
     ret = JS_TRUE;
 
 done:
-    FINISH_REQUEST(subcx);
-    JS_DestroyContext(subcx);
+#ifdef HAVE_COMPARTMENTS
+    if(call)
+    {
+        JS_LeaveCrossCompartmentCall(call);
+    }
+#endif
+    /* Don't use FINISH_REQUEST before destroying a context
+     * Destroying a context without a thread asserts on threadsafe
+     * debug builds */
+    FINISH_REQUEST_AND_DESTROY(subcx);
     return ret;
 }
 
 static JSBool
-gc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+gc(JSContext* cx, uintN argc, jsval* vp)
 {
     JS_GC(cx);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+print(JSContext* cx, uintN argc, jsval* vp)
 {
+    jsval* argv = JS_ARGV(cx, vp);
     uintN i;
     char *bytes;
 
@@ -109,16 +164,52 @@ print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
 
     fputc('\n', stdout);
     fflush(stdout);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     return JS_TRUE;
 }
 
 static JSBool
-quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+quit(JSContext* cx, uintN argc, jsval* vp)
 {
+    jsval* argv = JS_ARGV(cx, vp);
     JS_ConvertArguments(cx, argc, argv, "/ i", &gExitCode);
     return JS_FALSE;
 }
 
+#ifndef HAVE_JS_FGETS
+/* js_fgets is not linkable from C consumers with libmozjs >= 2.0,
+ * so we reimplement it here */
+#undef js_fgets
+static int
+couchjs_fgets(char *buf, int size, FILE *file)
+{
+    int n, i, c;
+    JSBool crflag;
+
+    n = size - 1;
+    if (n < 0)
+        return -1;
+
+    crflag = JS_FALSE;
+    for (i = 0; i < n && (c = getc(file)) != EOF; i++) {
+        buf[i] = c;
+        if (c == '\n') {        /* any \n ends a line */
+            i++;                /* keep the \n; we know there is room for \0 */
+            break;
+        }
+        if (crflag) {           /* \r not followed by \n ends line at the \r */
+            ungetc(c, file);
+            break;              /* and overwrite c in buf with \0 */
+        }
+        crflag = (c == '\r');
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+#define js_fgets couchjs_fgets
+#endif
+
 static char*
 readfp(JSContext* cx, FILE* fp, size_t* buflen)
 {
@@ -130,7 +221,6 @@ readfp(JSContext* cx, FILE* fp, size_t* buflen)
 
     bytes = JS_malloc(cx, byteslen);
     if(bytes == NULL) return NULL;
-    
     while((readlen = js_fgets(bytes+used, byteslen-used, stdin)) > 0)
     {
         used += readlen;
@@ -157,7 +247,7 @@ readfp(JSContext* cx, FILE* fp, size_t* buflen)
 }
 
 static JSBool
-readline(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+readline(JSContext* cx, uintN argc, jsval* vp) {
     jschar *chars;
     JSString *str;
     char* bytes;
@@ -173,9 +263,10 @@ readline(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
     /* Treat the empty string specially */
     if(byteslen == 0)
     {
-        *rval = JS_GetEmptyStringValue(cx);
+        //JS_SET_RVAL(cx, vp, JS_GetEmptyStringValue(cx));
         JS_free(cx, bytes);
-        return JS_TRUE;
+        //return JS_TRUE;
+        return JS_FALSE;
     }
 
     /* Shrink the buffer to the real size */
@@ -191,22 +282,32 @@ readline(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
     JS_free(cx, bytes);
 
     if(!str) return JS_FALSE;
-
-    *rval = STRING_TO_JSVAL(str);
+    JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
 
     return JS_TRUE;
 }
 
 static JSBool
-seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+seal(JSContext* cx, uintN argc, jsval* vp) {
+    jsval* argv = JS_ARGV(cx, vp);
     JSObject *target;
     JSBool deep = JS_FALSE;
 
     if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
         return JS_FALSE;
-    if (!target)
+    if (!target) {
+        JS_SET_RVAL(cx, vp, JSVAL_VOID);
         return JS_TRUE;
-    return JS_SealObject(cx, target, deep);
+    }
+#ifdef HAVE_JS_FREEZE_OBJECT
+    JSBool res = deep ? JS_DeepFreezeObject(cx, target) : JS_FreezeObject(cx, target);
+#else
+    JSBool res = JS_SealObject(cx, target, deep);
+#endif
+    if (res == JS_TRUE)
+        JS_SET_RVAL(cx, vp, JSVAL_VOID);
+
+    return res;
 }
 
 static void
@@ -248,29 +349,15 @@ printerror(JSContext *cx, const char *mesg, JSErrorReport *report)
 }
 
 static JSFunctionSpec global_functions[] = {
-    {"evalcx", evalcx, 0, 0, 0},
-    {"gc", gc, 0, 0, 0},
-    {"print", print, 0, 0, 0},
-    {"quit", quit, 0, 0, 0},
-    {"readline", readline, 0, 0, 0},
-    {"seal", seal, 0, 0, 0},
+    {"evalcx", evalcx, 0, JSFUN_FAST_NATIVE, 0},
+    {"gc", gc, 0, JSFUN_FAST_NATIVE, 0},
+    {"print", print, 0, JSFUN_FAST_NATIVE, 0},
+    {"quit", quit, 0, JSFUN_FAST_NATIVE, 0},
+    {"readline", readline, 0, JSFUN_FAST_NATIVE, 0},
+    {"seal", seal, 0, JSFUN_FAST_NATIVE, 0},
     {0, 0, 0, 0, 0}
 };
 
-static JSClass global_class = {
-    "GlobalClass",
-    JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub,
-    JS_PropertyStub,
-    JS_PropertyStub,
-    JS_PropertyStub,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    JS_FinalizeStub,
-    JSCLASS_NO_OPTIONAL_MEMBERS
-};
-
 int
 main(int argc, const char * argv[])
 {
@@ -290,9 +377,18 @@ main(int argc, const char * argv[])
     JS_ToggleOptions(cx, JSOPTION_XML);
     
     SETUP_REQUEST(cx);
-
+#ifdef HAVE_COMPARTMENTS
+    global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
+    if (!global) return 1;
+    JSCrossCompartmentCall *call = JS_EnterCrossCompartmentCall(cx, global);
+#elif HAVE_JS_NEW_GLOBAL_OBJECT
+    global = JS_NewGlobalObject(cx, &global_class);
+    if (!global) return 1;
+#else
     global = JS_NewObject(cx, &global_class, NULL, NULL);
     if (!global) return 1;
+    JS_SetGlobalObject(cx, global);
+#endif
     if (!JS_InitStandardClasses(cx, global)) return 1;
     
     for(sp = global_functions; sp->name != NULL; sp++)
@@ -309,8 +405,6 @@ main(int argc, const char * argv[])
     {
         return 1;
     }
-    
-    JS_SetGlobalObject(cx, global);
 
     if(argc > 2)
     {
@@ -328,9 +422,15 @@ main(int argc, const char * argv[])
         execute_script(cx, global, argv[1]);
     }
 
-    FINISH_REQUEST(cx);
+#ifdef HAVE_COMPARTMENTS
+    JS_LeaveCrossCompartmentCall(call);
+#endif
+
+    /* Don't use FINISH_REQUEST before destroying a context
+     * Destroying a context without a thread asserts on threadsafe
+     * debug builds */
+    FINISH_REQUEST_AND_DESTROY(cx);
 
-    JS_DestroyContext(cx);
     JS_DestroyRuntime(rt);
     JS_ShutDown();
 
diff --git a/src/couchdb/priv/couch_js/utf8.c b/src/couchdb/priv/couch_js/utf8.c
index 699a6fe..b088020 100644
--- a/src/couchdb/priv/couch_js/utf8.c
+++ b/src/couchdb/priv/couch_js/utf8.c
@@ -12,6 +12,8 @@
 
 #include <jsapi.h>
 
+#include "config.h"
+
 static int
 enc_char(uint8 *utf8Buffer, uint32 ucs4Char)
 {
@@ -129,8 +131,12 @@ enc_string(JSContext* cx, jsval arg, size_t* buflen)
     str = JS_ValueToString(cx, arg);
     if(!str) goto error;
 
+#ifdef HAVE_JS_GET_STRING_CHARS_AND_LENGTH
+    src = JS_GetStringCharsAndLength(cx, str, &srclen);
+#else
     src = JS_GetStringChars(str);
     srclen = JS_GetStringLength(str);
+#endif
 
     if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
     
@@ -283,4 +289,4 @@ error:
 
 success:
     return str;
-}
\ No newline at end of file
+}



spidermonkey patch

The following patch was apparently necessary to get SpiderMonkey 1.8.5 to compile on Android. Your mileage may vary.

--- mozilla-central-bb9089ae2322/nsprpub/pr/src/io/prlog.c      2011-01-21 16:40:14.000000000 -0700
+++ mozilla-central-bb9089ae2322.bak/nsprpub/pr/src/io/prlog.c  2011-01-31 13:53:30.000000000 -0700
@@ -42,7 +42,7 @@
 #include "prprf.h"
 #include <string.h>
 #ifdef ANDROID
-#include <android/log.h>
+//#include <android/log.h>
 #endif
 
 /*
@@ -135,7 +135,7 @@
     if (fd == _pr_stderr) {                                  \
         char savebyte = buf[nb];                             \
         buf[nb] = '\0';                                      \
-        __android_log_write(ANDROID_LOG_INFO, "PRLog", buf); \
+        printf("PRLog: %s", buf);                            \
         buf[nb] = savebyte;                                  \
     } else {                                                 \
         PR_Write(fd, buf, nb);                               \
--- mozilla-central-bb9089ae2322/js/src/jscntxt.cpp     2011-01-21 16:40:14.000000000 -0700
+++ mozilla-central-bb9089ae2322.bak/js/src/jscntxt.cpp 2011-01-31 13:49:52.000000000 -0700
@@ -46,7 +46,7 @@
 #include <stdlib.h>
 #include <string.h>
 #ifdef ANDROID
-# include <android/log.h>
+//# include <android/log.h>
 # include <fstream>
 # include <string>
 #endif  // ANDROID
@@ -2218,12 +2218,14 @@
     // Check for the known-bad kernel version (2.6.29).
     std::ifstream osrelease("/proc/sys/kernel/osrelease");
     std::getline(osrelease, line);
-    __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'",
-                        line.c_str());
+//    __android_log_print(ANDROID_LOG_INFO, "Gecko", "Detected osrelease `%s'",
+//                        line.c_str());
+    printf("Gecko: Detected osrelease `%s'", line.c_str());
 
     if (line.npos == line.find("2.6.29")) {
         // We're using something other than 2.6.29, so the JITs should work.
-        __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken");
+//        __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are not broken");
+        printf("Gecko: JITs are not broken");
         return false;
     }
 
@@ -2243,8 +2245,9 @@
             };
             for (const char** hw = &blacklist[0]; *hw; ++hw) {
                 if (line.npos != line.find(*hw)) {
-                    __android_log_print(ANDROID_LOG_INFO, "Gecko",
-                                        "Blacklisted device `%s'", *hw);
+//                    __android_log_print(ANDROID_LOG_INFO, "Gecko",
+//                                        "Blacklisted device `%s'", *hw);
+                    printf("Gecko: Blacklisted device `%s'", *hw);
                     broken = true;
                     break;
                 }
@@ -2254,8 +2257,9 @@
         std::getline(cpuinfo, line);
     } while(!cpuinfo.fail() && !cpuinfo.eof());
 
-    __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken",
-                        broken ? "" : "not ");
+//    __android_log_print(ANDROID_LOG_INFO, "Gecko", "JITs are %sbroken",
+//                        broken ? "" : "not ");
+    printf("Gecko: JITs are %sborken", broken ? "" : "not ");
 
     return broken;
 #endif  // ifndef ANDROID
--- mozilla-central/nsprpub/pr/src/Makefile.in.bak      2011-02-02 15:39:53.000000000 -0700
+++ mozilla-central/nsprpub/pr/src/Makefile.in  2011-02-02 15:40:07.000000000 -0700
@@ -205,9 +205,9 @@
 OS_LIBS                = ws2.lib
 endif
 
-ifeq ($(OS_TARGET),Android)
-OS_LIBS                += -llog
-endif
+#ifeq ($(OS_TARGET),Android)
+#OS_LIBS               += -llog
+#endif
 
 ifeq ($(OS_TARGET),MacOSX)
 OS_LIBS                = -framework CoreServices -framework CoreFoundation
--- mozilla-central/js/src/configure.in.bak     2011-02-02 15:41:20.000000000 -0700
+++ mozilla-central/js/src/configure.in 2011-02-02 15:41:43.000000000 -0700
@@ -291,11 +291,10 @@
     CFLAGS="-mandroid -I$android_platform/usr/include -msoft-float -fno-short-enums -fno-exceptions -march=armv5te -mthumb-interwork $CFLAGS"
     CXXFLAGS="-mandroid -I$android_platform/usr/include -msoft-float -fno-short-enums -fno-exceptions -march=armv5te -mthumb-interwork $CXXFLAGS"
 
-    dnl Add -llog by default, since we use it all over the place.
     dnl Add --allow-shlib-undefined, because libGLESv2 links to an
     dnl undefined symbol (present on the hardware, just not in the
     dnl NDK.)
-    LDFLAGS="-mandroid -L$android_platform/usr/lib -Wl,-rpath-link=$android_platform/usr/lib --sysroot=$android_platform -llog -Wl,--allow-shlib-undefined $LDFLAGS"
+    LDFLAGS="-mandroid -L$android_platform/usr/lib -Wl,-rpath-link=$android_platform/usr/lib --sysroot=$android_platform -Wl,--allow-shlib-undefined $LDFLAGS"
 
     dnl prevent cross compile section from using these flags as host flags
     if test -z "$HOST_CPPFLAGS" ; then



Erlang/OTP patch

The following patch was apparently necessary to get Erlang/OTP to compile on Android. Your mileage may vary.

diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index fb8d718..4ed25c9 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -352,6 +352,7 @@ EMULATOR_EXECUTABLE = beam$(TF_MARKER).dll
 else
 ifeq ($(CC), agcc)
 EMULATOR_EXECUTABLE = libbeam$(TF_MARKER).so
+EMULATOR_EXECUTABLE_REG = beam$(TF_MARKER)
 else
 EMULATOR_EXECUTABLE = beam$(TF_MARKER)
 endif
@@ -374,7 +375,11 @@ ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no)
 all:
        @echo '*** Omitted build of emulator with smp support'
 else
+ifeq ($(CC), agcc)
+all: generate erts_lib zlib pcre $(BINDIR)/$(EMULATOR_EXECUTABLE) $(BINDIR)/$(EMULATOR_EXECUTABLE_REG) $(UNIX_ONLY_BUILDS)
+else
 all: generate erts_lib zlib pcre $(BINDIR)/$(EMULATOR_EXECUTABLE) $(UNIX_ONLY_BUILDS)
+endif
 ifeq ($(OMIT_OMIT_FP),yes)
        @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
        @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *'
@@ -453,6 +458,7 @@ release_spec: all
        $(INSTALL_DATA) $(RELEASE_INCLUDES) $(RELEASE_PATH)/usr/include
        $(INSTALL_DATA) $(RELEASE_INCLUDES) $(RELSYSDIR)/include
        $(INSTALL_PROGRAM) $(BINDIR)/$(EMULATOR_EXECUTABLE) $(RELSYSDIR)/bin
+       $(INSTALL_PROGRAM) $(BINDIR)/$(EMULATOR_EXECUTABLE_REG) $(RELSYSDIR)/bin
 ifeq ($(ERLANG_OSTYPE), unix)
        $(INSTALL_PROGRAM) $(BINDIR)/$(CS_EXECUTABLE) $(RELSYSDIR)/bin
 endif
@@ -1013,6 +1019,13 @@ ifeq ($(CC), agcc)
 $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
        $(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
        $(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(INIT_OBJS) $(OBJS) $(LIBS) -shared
+
+$(OBJDIR)/beam.o:
+       $(CC) $(CFLAGS) $(INCLUDES) -c beam/beam.c -o $(OBJDIR)/beam.o
+
+$(BINDIR)/$(EMULATOR_EXECUTABLE_REG): $(OBJDIR)/beam.o
+       $(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE_REG) \
+       $(HIPEBEAMLDFLAGS) $(LDFLAGS) $(DEXPORT) $(OBJDIR)/beam.o $(LIBS) -L$(BINDIR) -lbeam
 else
 $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS)
        $(PURIFY) $(LD) -o $(BINDIR)/$(EMULATOR_EXECUTABLE) \
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 7c6e4a2..c1a1549 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -116,7 +116,11 @@ main(int argc, char *argv[])
            execv(argv[CS_ARGV_NO_OF_ARGS],&(argv[CS_ARGV_NO_OF_ARGS + 1]));
        }
     } else {
+#ifdef ANDROID_ARM
+       execl("/system/bin/sh", "sh", "-c", argv[CS_ARGV_CMD_IX], (char *) NULL);
+#else
        execl("/bin/sh", "sh", "-c", argv[CS_ARGV_CMD_IX], (char *) NULL);
+#endif
     }
     return 1;
 }
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 31ab5d0..9a260a2 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -1539,7 +1539,11 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op
                    }
                }
            } else {
+#ifdef ANDROID_ARM
+               execle("/system/bin/sh", "sh", "-c", cmd_line, (char *) NULL, new_environ);
+#else
                execle("/bin/sh", "sh", "-c", cmd_line, (char *) NULL, new_environ);
+#endif
            }
        child_error:
            _exit(1);
@@ -1660,7 +1664,12 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op
        fcntl(i, F_SETFD, 1);
 
     qnx_spawn_options.flags = _SPAWN_SETSID;
+#ifdef ANDROID_ARM
+    /* Are we really in QNX?  Then we don't need this special case here... */
+    if ((pid = spawnl(P_NOWAIT, "/system/bin/sh", "/system/bin/sh", "-c", cmd_line, 
+#else
     if ((pid = spawnl(P_NOWAIT, "/bin/sh", "/bin/sh", "-c", cmd_line, 
+#endif
                       (char *) 0)) < 0) {
        erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
         reset_qnx_spawn();
diff --git a/erts/emulator/beam/beam.c b/erts/emulator/beam/beam.c
new file mode 100644
index 0000000..167b96e
--- /dev/null
+++ b/erts/emulator/beam/beam.c
@@ -0,0 +1,2 @@
+void erl_start(int argc, char** argv);
+int main(int argc, char** argv) { erl_start(argc, argv); }
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 0b39808..5d9658e 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -108,7 +108,7 @@ $(OBJDIR)/%.o: %.c
 
 $(LIBDIR)/crypto_drv.so: $(OBJS)
        $(INSTALL_DIR) $(LIBDIR) 
-       $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB) $(LIBS) -lbeam
+       $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB) $(LIBS) -lbeam -shared
 
 $(LIBDIR)/crypto_drv.dll: $(OBJS)
        $(INSTALL_DIR) $(LIBDIR)
diff --git a/otp_build b/otp_build
index ad9d38e..b875b38 100755
--- a/otp_build
+++ b/otp_build
@@ -284,7 +284,7 @@ do_autoconf ()
            export WANT_AUTOCONF_VER
        fi
        exp_ac_vsn=$EXPECTED_AUTOCONF_VERSION
-       ac_vsn_blob=`autoconf --version`
+       ac_vsn_blob=`autoconf2.59 --version`
        ac_vsn=`echo x$ac_vsn_blob | sed "s|[^0-9]*\([0-9][^ \t\n]*\).*|\1|"`
        case "$ac_vsn" in
            $exp_ac_vsn)
@@ -327,11 +327,11 @@ do_autoconf ()
                rm -f "$d"/autom4te.cache/*
            }
            echo "=== running autoconf in $d"
-           ( cd "$d" && autoconf ) || exit 1
+           ( cd "$d" && autoconf2.59 ) || exit 1
            chdr=`cat "$file" | sed -n "s|.*\(AC_CONFIG_HEADER\).*|\1|p"`
            [ "$chdr" = "AC_CONFIG_HEADER" ] || continue
            echo "=== running autoheader in $d"
-           ( cd "$d" && autoheader ) || exit 1
+           ( cd "$d" && autoheader2.59 ) || exit 1
        done
 
        restore_vars OVERRIDE_TARGET TARGET



Release patch

This final patch was necessary to make the release process for CouchDB work with Android 4.

diff -ru release.bak/sdcard/Android/data/com.your.namespace/couchdb/bin/couchdb release/sdcard/Android/data/com.your.namespace/couchdb/bin/couchdb
--- release.bak/sdcard/Android/data/com.your.namespace/couchdb/bin/couchdb      2011-02-05 01:26:00.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/couchdb/bin/couchdb  2011-02-08 16:42:00.000000000 -0700
@@ -12,6 +12,9 @@
 # License for the specific language governing permissions and limitations under
 # the License.
 
+export HOME=/data/data/com.your.namespace
+export LD_LIBRARY_PATH=$HOME/erlang/erts-5.7.5/bin:$HOME/couchdb/bin:$HOME/couchdb/lib/couchdb/bin
+export PATH=$HOME/erlang/bin:$HOME/couchdb/bin:$PATH
 BACKGROUND=false
 DEFAULT_CONFIG_DIR=/sdcard/Android/data/com.your.namespace/couchdb/etc/couchdb/default.d
 DEFAULT_CONFIG_FILE=/sdcard/Android/data/com.your.namespace/couchdb/etc/couchdb/default.ini
@@ -222,8 +225,8 @@
         touch $PID_FILE
         interactive_option="+Bd -noinput"
     fi
-    command="/home/matt/projects/couch/android-build/couchdb/../otp/bootstrap/bin/erl $interactive_option $ERL_START_OPTIONS \
-        -env ERL_LIBS /sdcard/Android/data/com.your.namespace/couchdb/lib/couchdb/erlang/lib -couch_ini $start_arguments -s couch"
+    command="erl $interactive_option $ERL_START_OPTIONS \
+        -env ERL_LIBS /data/data/com.your.namespace/couchdb/lib/couchdb/erlang/lib -couch_ini $start_arguments -s couch"
     if test "$BACKGROUND" = "true" -a "$RECURSED" = "false"; then
         $0 $background_start_arguments -b -r $RESPAWN_TIMEOUT -p $PID_FILE \
             -o $STDOUT_FILE -e $STDERR_FILE -R &
diff -ru release.bak/sdcard/Android/data/com.your.namespace/couchdb/etc/couchdb/local.ini release/sdcard/Android/data/com.your.namespace/couchdb/etc/couchdb/local.ini
--- release.bak/sdcard/Android/data/com.your.namespace/couchdb/etc/couchdb/local.ini    2011-02-05 01:26:00.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/couchdb/etc/couchdb/local.ini        2011-02-08 15:58:30.000000000 -0700
@@ -5,23 +5,30 @@
 ; overwritten on server upgrade.
 
 [couchdb]
+database_dir = /sdcard/Android/data/com.your.namespace/couchdb/var/lib/couchdb
+view_index_dir = /sdcard/Android/data/com.your.namespace/couchdb/var/lib/couchdb
+util_driver_dir = /data/data/com.your.namespace/couchdb/lib/couchdb
 ;max_document_size = 4294967296 ; bytes
+uri_file = /sdcard/Android/data/com.your.namespace/couchdb/var/lib/couchdb/couch.uri
 
 [httpd]
-;port = 5984
-;bind_address = 127.0.0.1
+port = 5999
+bind_address = 127.0.0.1
 ; Uncomment next line to trigger basic-auth popup on unauthorized requests.
 ;WWW-Authenticate = Basic realm="administrator"
 
+[log]
+file = /sdcard/Android/data/com.your.namespace/couchdb/var/log/couchdb/couch.log
+level = debug
+
 [couch_httpd_auth]
 ; If you set this to true, you should also uncomment the WWW-Authenticate line
 ; above. If you don't configure a WWW-Authenticate header, CouchDB will send
 ; Basic realm="server" in order to prevent you getting logged out.
 ; require_valid_user = false
 
-[log]
-;level = debug
-
+[query_servers]
+javascript = /data/data/com.your.namespace/couchdb/bin/couchjs_wrapper /data/data/com.your.namespace/couchdb/share/couchdb/server/main.js
 
 ; To enable Virtual Hosts in CouchDB, add a vhost = path directive. All requests to
 ; the Virual Host will be redirected to the path. In the example below all requests
diff -ruN release.bak/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs release/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs
--- release.bak/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs      2011-02-05 01:26:00.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs  2011-02-05 01:37:12.000000000 -0700
@@ -1,4 +1,4 @@
-#! /bin/sh -e
+#!/system/bin/sh -e
 
 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
 # use this file except in compliance with the License. You may obtain a copy of
@@ -63,7 +63,7 @@
 }
 
 run_couchjs () {
-    exec /sdcard/Android/data/com.your.namespace/couchdb/lib/couchdb/bin/couchjs $@
+    exec LD_LIBRARY_PATH=/data/data/com.your.namespace/couchdb/lib/couchdb/bin /data/data/com.your.namespace/couchdb/lib/couchdb/bin/couchjs $@
 }
 
 parse_script_option_list () {
diff -ruN release.bak/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs_wrapper release/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs_wrapper
--- release.bak/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs_wrapper      1969-12-31 17:00:00.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/couchdb/bin/couchjs_wrapper  2011-02-05 01:39:28.000000000 -0700
@@ -0,0 +1,3 @@
+#!/system/bin/sh
+export LD_LIBRARY_PATH=/data/data/com.your.namespace/couchdb/lib/couchdb/bin
+exec /data/data/com.your.namespace/couchdb/lib/couchdb/bin/couchjs $@
\ No newline at end of file
diff -ruN release.bak/sdcard/Android/data/com.your.namespace/couchdb/lib/couchdb/erlang/lib/couch-1.0.2/priv/couchspawnkillable release/sdcard/Android/data/com.your.namespace/couchdb/lib/couchdb/erlang/lib/couch-1.0.2/priv/couchspawnkillable
--- release.bak/sdcard/Android/data/com.your.namespace/couchdb/lib/couchdb/erlang/lib/couch-1.0.2/priv/couchspawnkillable       2011-02-05 01:26:00.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/couchdb/lib/couchdb/erlang/lib/couch-1.0.2/priv/couchspawnkillable   2011-02-05 01:48:49.000000000 -0700
@@ -1,4 +1,4 @@
-#! /bin/sh -e
+#!/system/bin/sh -e
 
 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
 # use this file except in compliance with the License. You may obtain a copy of
diff -ruN release.bak/sdcard/Android/data/com.your.namespace/erlang/bin/erl release/sdcard/Android/data/com.your.namespace/erlang/bin/erl
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/bin/erl   2011-02-05 01:28:07.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/bin/erl       2011-02-05 01:49:29.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 #
 # %CopyrightBegin%
 # 
@@ -21,6 +21,7 @@
 BINDIR=$ROOTDIR/erts-5.7.5/bin
 EMU=beam
 PROGNAME=`echo $0 | sed 's/.*\///'`
+export ERL_INETRC=$ROOTDIR/bin/erl_inetrc
 export EMU
 export ROOTDIR
 export BINDIR
diff -ruN release.bak/sdcard/Android/data/com.your.namespace/erlang/bin/erl_inetrc release/sdcard/Android/data/com.your.namespace/erlang/bin/erl_inetrc
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/bin/erl_inetrc    1969-12-31 17:00:00.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/bin/erl_inetrc        2011-02-05 01:49:58.000000000 -0700
@@ -0,0 +1,4 @@
+%% Use erlang's internal resolver. Native DNS on android is annoying
+{lookup, [file,dns]}.
+%% TODO: Not this,
+{nameserver, {8,8,8,8}}.
\ No newline at end of file
diff -ru release.bak/sdcard/Android/data/com.your.namespace/erlang/bin/start release/sdcard/Android/data/com.your.namespace/erlang/bin/start
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/bin/start 2011-02-05 01:57:26.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/bin/start     2011-02-05 02:05:54.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 #
 # %CopyrightBegin%
 # 
diff -ru release.bak/sdcard/Android/data/com.your.namespace/erlang/bin/start_erl release/sdcard/Android/data/com.your.namespace/erlang/bin/start_erl
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/bin/start_erl     2011-02-05 01:57:26.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/bin/start_erl 2011-02-05 02:05:48.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 #
 #
 # %CopyrightBegin%
diff -ru release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/erl release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/erl
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/erl        2011-02-05 01:57:26.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/erl    2011-02-05 02:06:04.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 #
 # %CopyrightBegin%
 # 
diff -ru release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/erl.src release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/erl.src
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/erl.src    2011-02-05 01:23:30.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/erl.src        2011-02-05 02:06:01.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 #
 # %CopyrightBegin%
 # 
diff -ru release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start      2011-02-05 01:57:26.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start  2011-02-05 02:06:09.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 #
 # %CopyrightBegin%
 # 
diff -ru release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start_erl.src release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start_erl.src
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start_erl.src      2011-02-05 01:23:30.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start_erl.src  2011-02-05 02:06:06.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 #
 #
 # %CopyrightBegin%
diff -ru release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start.src release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start.src
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start.src  2011-02-05 01:23:30.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/erts-5.7.5/bin/start.src      2011-02-05 02:05:58.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 #
 # %CopyrightBegin%
 # 
diff -ru release.bak/sdcard/Android/data/com.your.namespace/erlang/lib/inets-5.3/priv/bin/runcgi.sh release/sdcard/Android/data/com.your.namespace/erlang/lib/inets-5.3/priv/bin/runcgi.sh
--- release.bak/sdcard/Android/data/com.your.namespace/erlang/lib/inets-5.3/priv/bin/runcgi.sh  2011-02-05 01:22:58.000000000 -0700
+++ release/sdcard/Android/data/com.your.namespace/erlang/lib/inets-5.3/priv/bin/runcgi.sh      2011-02-05 02:06:14.000000000 -0700
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/system/bin/sh
 cd $1
 shift
 exec env "$@"