Add C++ exceptions and RTTI support.

This enables C++ exceptions and RTTI support to the NDK
toolchain through a local patch.

C++ sources are still built with -fno-exceptions and -fno-rtti
by default for compatibility purpose, so use -fexceptions and/or
-frtti in your LOCAL_CPPFLAGS to enable these features.

You will also need to link against libsupc++.a directly with:

   LOCAL_LDLIBS := -lsupc++

+ Add two device tests to check that the features work properly.

Change-Id: I41956a04997336d8135aaef291a1579267e0ad2a
diff --git a/build/tools/build-gcc.sh b/build/tools/build-gcc.sh
index 1b5d671..4b36c3c 100755
--- a/build/tools/build-gcc.sh
+++ b/build/tools/build-gcc.sh
@@ -35,7 +35,8 @@
 OPTION_BUILD_OUT=
 register_var_option "--build-out=<path>" OPTION_BUILD_OUT "Set temporary build directory" "/tmp/<random>"
 
-PLATFORM=android-3
+# Note: platform API level 9 or higher is needed for proper C++ support
+PLATFORM=android-9
 register_var_option "--platform=<name>"  PLATFORM "Specify platform name"
 
 OPTION_SYSROOT=
@@ -50,6 +51,9 @@
 JOBS=$BUILD_NUM_CPUS
 register_var_option "-j<number>" JOBS "Use <number> parallel build jobs"
 
+KEEP_LIBSTDCXX=no
+register_var_option "--keep-libstdcxx" KEEP_LIBSTDCXX "Experimental: build libstdc++"
+
 register_mingw_option
 
 extract_parameters $@
@@ -135,7 +139,7 @@
 # binaries from containing hard-coding host paths
 TOOLCHAIN_SYSROOT=$TOOLCHAIN_PATH/sysroot
 dump "Sysroot  : Copying: $SYSROOT --> $TOOLCHAIN_SYSROOT"
-mkdir -p $TOOLCHAIN_SYSROOT && (cd $SYSROOT && tar c *) | (cd $TOOLCHAIN_SYSROOT && tar x)
+mkdir -p $TOOLCHAIN_SYSROOT && (cd $SYSROOT && tar ch *) | (cd $TOOLCHAIN_SYSROOT && tar x)
 if [ $? != 0 ] ; then
     echo "Error while copying sysroot files. See $TMPLOG"
     exit 1
@@ -155,12 +159,15 @@
 rm -rf $BUILD_OUT
 OLD_ABI="${ABI}"
 export CC CXX
-mkdir -p $BUILD_OUT &&
-cd $BUILD_OUT &&
-export CC CXX &&
-export ABI=$HOST_GMP_ABI &&  # needed to build a 32-bit gmp
-export CFLAGS="-Wno-error" && # needed because gdb-6.6 uses -Werror by default and fails to build with recent GCC versions
-run \
+export CFLAGS_FOR_TARGET="$ABI_CFLAGS_FOR_TARGET"
+export CXXFLAGS_FOR_TARGET="$ABI_CXXFLAGS_FOR_TARGET"
+# Needed to build a 32-bit gmp on 64-bit systems
+export ABI=$HOST_GMP_ABI
+# -Wno-error is needed because our gdb-6.6 sources use -Werror by default
+# and fail to build with recent GCC versions.
+export CFLAGS="-Wno-error"
+#export LDFLAGS="$HOST_LDFLAGS"
+mkdir -p $BUILD_OUT && cd $BUILD_OUT && run \
 $BUILD_SRCDIR/configure --target=$ABI_CONFIGURE_TARGET \
                         --host=$ABI_CONFIGURE_HOST \
                         --build=$ABI_CONFIGURE_BUILD \
@@ -197,9 +204,27 @@
 fi
 # don't forget to copy the GPL and LGPL license files
 run cp -f $TOOLCHAIN_LICENSES/COPYING $TOOLCHAIN_LICENSES/COPYING.LIB $TOOLCHAIN_PATH
+
 # remove some unneeded files
 run rm -f $TOOLCHAIN_PATH/bin/*-gccbug
-run rm -rf $TOOLCHAIN_PATH/man $TOOLCHAIN_PATH/info
+run rm -rf $TOOLCHAIN_PATH/info
+run rm -rf $TOOLCHAIN_PATH/man
+run rm -rf $TOOLCHAIN_PATH/share
+run rm -rf $TOOLCHAIN_PATH/lib/gcc/$ABI_CONFIGURE_TARGET/*/install-tools
+run rm -rf $TOOLCHAIN_PATH/lib/gcc/$ABI_CONFIGURE_TARGET/*/plugin
+run rm -rf $TOOLCHAIN_PATH/libexec/gcc/$ABI_CONFIGURE_TARGET/*/install-tools
+run rm -rf $TOOLCHAIN_PATH/lib32/libiberty.a
+run rm -rf $TOOLCHAIN_PATH/$ABI_CONFIGURE_TARGET/lib/libiberty.a
+run rm -rf $TOOLCHAIN_PATH/$ABI_CONFIGURE_TARGET/lib/*/libiberty.a
+
+# Remove libstdc++ for now (will add it differently later)
+# We had to build it to get libsupc++ which we keep.
+if [ "$KEEP_LIBSTDCXX" = "no" ] ; then
+    run rm -rf $TOOLCHAIN_PATH/$ABI_CONFIGURE_TARGET/lib/libstdc++.*
+    run rm -rf $TOOLCHAIN_PATH/$ABI_CONFIGURE_TARGET/lib/*/libstdc++.*
+    run rm -rf $TOOLCHAIN_PATH/$ABI_CONFIGURE_TARGET/include/c++
+fi
+
 # strip binaries to reduce final package size
 run strip $TOOLCHAIN_PATH/bin/*
 run strip $TOOLCHAIN_PATH/$ABI_CONFIGURE_TARGET/bin/*
diff --git a/build/tools/prebuilt-common.sh b/build/tools/prebuilt-common.sh
index 3c37e23..b463209 100644
--- a/build/tools/prebuilt-common.sh
+++ b/build/tools/prebuilt-common.sh
@@ -414,6 +414,23 @@
     fi
 }
 
+# Use the check for the availability of a compatibility SDK in Darwin
+# this can be used to generate binaries compatible with either Tiger or
+# Leopard.
+#
+# $1: SDK root path
+# $2: MacOS X minimum version (e.g. 10.4)
+check_darwin_sdk ()
+{
+    if [ -d "$1" ] ; then
+        HOST_CFLAGS="-isysroot $1 -mmacosx-version-min=$2 -DMAXOSX_DEPLOYEMENT_TARGET=$2"
+        HOST_LDFLAGS="-Wl,-syslibroot,$sdk -mmacosx-version-min=$2"
+        return 0  # success
+    fi
+    return 1
+}
+
+
 prepare_host_flags ()
 {
     # detect build tag
@@ -446,7 +463,22 @@
     CC=${CC:-gcc}
     CXX=${CXX:-g++}
     case $HOST_TAG in
+        darwin-*)
+            # Try to build with Tiger SDK if available
+            if check_darwin_sdk /Developer/SDKs/MacOSX10.4.sdku 10.4; then
+                log "Generating Tiger-compatible binaries!"
+            # Otherwise with Leopard SDK
+            elif check_darwin_sdk /Developer/SDKs/MacOSX10.5.sdk 10.5; then
+                log "Generating Leopard-compatible binaries!"
+            else
+                local version=`sw_vers -productVersion`
+                log "Generating $version-compatible binaries!"
+            fi
+            ;;
         *-x86_64)
+            # NOTE: We need to modify the definitions of CC and CXX directly
+            #        here. Just changing the value of CFLAGS / HOST_CFLAGS
+            #        will not work well with the GCC toolchain scripts.
             CC="$CC -m32"
             CXX="$CXX -m32"
             HOST_GMP_ABI="32"
@@ -478,6 +510,9 @@
         exit 1
     fi
 
+    ABI_CFLAGS_FOR_TARGET=
+    ABI_CXXFLAGS_FOR_TARGET=
+
     # Determine ABI based on toolchain name
     #
     case "$TOOLCHAIN" in
@@ -490,9 +525,15 @@
         ABI_CONFIGURE_TARGET="arm-linux-androideabi"
         ABI_CONFIGURE_EXTRA_FLAGS="--with-gmp-version=4.2.4 --with-mpfr-version=2.4.1
 --with-arch=armv5te"
-        # Disabled until Gold is fixed for Cortex-A8 CPU bug
-        #ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-gold=both/gold"
-        GDB_VERSION=7.1.x
+        # Enable ARM Gold linker
+        ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-gold=both/gold"
+        # Enable C++ exceptions, RTTI and GNU libstdc++ at the same time
+        # You can't really build these separately at the moment.
+        ABI_CFLAGS_FOR_TARGET="-fexceptions"
+        ABI_CXXFLAGS_FOR_TARGET="-frtti"
+        ABI_CONFIGURE_EXTRA_FLAGS="$ABI_CONFIGURE_EXTRA_FLAGS --enable-libstdc__-v3"
+        # Stick to 6.6 for now.
+        # GDB_VERSION=7.1.x
         ;;
     x86-*)
         ARCH="x86"
diff --git a/build/tools/toolchain-patches/gcc/0001-Enable-C-exceptions-and-RTTI-by-default.patch b/build/tools/toolchain-patches/gcc/0001-Enable-C-exceptions-and-RTTI-by-default.patch
new file mode 100644
index 0000000..58a07e8
--- /dev/null
+++ b/build/tools/toolchain-patches/gcc/0001-Enable-C-exceptions-and-RTTI-by-default.patch
@@ -0,0 +1,31 @@
+From ac8ac691023b7f2b2c21330fef1f28ef56aeba65 Mon Sep 17 00:00:00 2001
+From: David 'Digit' Turner <digit@android.com>
+Date: Wed, 24 Nov 2010 14:26:38 +0100
+Subject: [PATCH] Enable C++ exceptions and RTTI by default.
+
+With this change, -fexceptions and -frtti become default options
+when compiling C++ sources.
+
+Change-Id: Ie136fc1dd57d15dfa062730118c2f8496d25cc62
+---
+ gcc-4.4.3/gcc/config/linux-android.h |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/gcc-4.4.3/gcc/config/linux-android.h b/gcc-4.4.3/gcc/config/linux-android.h
+index a43bab5..353baf0 100644
+--- a/gcc-4.4.3/gcc/config/linux-android.h
++++ b/gcc-4.4.3/gcc/config/linux-android.h
+@@ -40,8 +40,8 @@
+   "%{!fno-pic:%{!fno-PIC:%{!fpic:%{!fPIC: -fPIC}}}}"
+ 
+ #define ANDROID_CC1PLUS_SPEC						\
+-  "%{!fexceptions:%{!fno-exceptions: -fno-exceptions}} "		\
+-  "%{!frtti:%{!fno-rtti: -fno-rtti}}"
++  "%{!fexceptions:%{!fno-exceptions: -fexceptions}} "		\
++  "%{!frtti:%{!fno-rtti: -frtti}}"
+ 
+ #define ANDROID_LIB_SPEC \
+   "%{!static: -ldl}"
+-- 
+1.7.3.1
+
diff --git a/docs/CHANGES.html b/docs/CHANGES.html
index cb09431..1f6d5e1 100644
--- a/docs/CHANGES.html
+++ b/docs/CHANGES.html
@@ -80,10 +80,13 @@
     Note that they still correspond to our minimal C++ runtime, no new feature
     was introduced here.
 
-- Add sources and prebuilt binaries for a port of the STLport C++ Standard
-  Library (www.stlport.org), and an easy way to use it at build time by
-  defining APP_STL in your Application.mk. See docs/APPLICATION-MK.html and
-  docs/STL-SUPPORT.html for all details.
+- Support for C++ exceptions and RTTI. See docs/CPLUSPLUS-SUPPORT.html for
+  all details (and limitations).
+
+- STLport implementation: Add sources and prebuilt binaries for a port of
+  the STLport C++ Standard Library (www.stlport.org), and an easy way to use
+  it at build time by defining APP_STL in your Application.mk. See
+  docs/APPLICATION-MK.html and docs/CPLUSPLUS-SUPPORT.html for all details.
 
 - Add support for prebuilt libraries with the PREBUILT_SHARED_LIBRARY and
   PREBUILT_STATIC_LIBRARIES build scripts. See the new documentation
diff --git a/docs/CPLUSPLUS-SUPPORT.html b/docs/CPLUSPLUS-SUPPORT.html
new file mode 100644
index 0000000..6f255f5
--- /dev/null
+++ b/docs/CPLUSPLUS-SUPPORT.html
@@ -0,0 +1,122 @@
+<html><body><pre>
+C++ support with the Android NDK
+================================
+
+
+The Android platform provides a very minimal C++ runtime support library
+(/system/lib/libstdc++) and corresponding headers for it in the NDK.
+
+I. C++ Exceptions support:
+--------------------------
+
+The NDK toolchain supports C++ exceptions, since NDK r5, however all C++
+sources are compiled with -fno-exceptions support by default, for
+compatibility reasons with previous releases.
+
+To enable it, use the '-fexceptions' C++ compiler flag. This can be done
+by adding the following to every module definition in your Android.mk:
+
+    LOCAL_CPPFLAGS += -fexceptions
+
+More simply, add a single line to your Application.mk, the setting will
+automatically apply to all your project's NDK modules:
+
+    APP_CPPFLAGS += -fexceptions
+
+NOTE: The obsolete "arm-eabi-4.4.0" toolchain provided for backwards
+      compatibility with this NDK does not support exceptions!
+
+
+II. RTTI support:
+------------------
+
+Similarly, the NDK toolchain supports C++ RTTI (RunTime Type Information)
+since NDK r5, but all C++ sources are built with -fno-rtti by default for
+compatibility reasons. To enable it, add the following to your module
+declarations:
+
+    LOCAL_CPPFLAGS += -frtti
+
+Or more simply to your Application.mk:
+
+    APP_CPPFLAGS += -frtti
+
+
+NOTE: The obsolete "arm-eabi-4.4.0" toolchain provided for backwards
+      compatibility with this NDK does not support RTTI!
+
+
+III. Selecting the C++ Standard Library Implementation:
+-------------------------------------------------------
+
+By default, the headers and libraries for the minimal C++ runtime system
+library (/system/lib/libstdc++.so) are used when building C++ sources.
+
+You can however select a different implementation by setting the variable
+APP_STL to something else in your Application.mk, for example:
+
+  APP_STL := stlport_static
+
+To select the static STLport implementation provided with this NDK.
+Value APP_STL values are the following:
+
+   system              -> Use the default minimal C++ runtime library.
+   stlport_static      -> Use STLport built as a static library.
+   stlport_shared      -> Use STLport built as a shared library.
+
+WARNING: IMPORTANT CAVEAT
+
+     AT THE MOMENT, OUR STLPORT IMPLEMENTATION DOES NOT SUPPORT EXCEPTIONS
+     AND RTTI. PLEASE BE SURE TO NOT USE -fexceptions OR -frtti IN ALL
+     MODULES THAT USE IT.
+
+WARNING: END OF IMPORTANT CAVEAT
+
+  "stlport_shared" is preferred if you have several shared libraries in your
+  project that use the C++ STL, because it avoids duplication of functions
+  and more importantly of global variables (e.g. std::cout) in each one of
+  them, which can have surprising results.
+
+  On the other hand, you will have to load it explicitely when starting your
+  application, as in the following example:
+
+     static {
+         System.loadLibrary("stlport_shared");
+         System.loadLibrary("foo");
+         System.loadLibrary("bar");
+     }
+
+  Where both "libfoo.so" and "libbar.so" depend on "libstlport_shared.so".
+
+  Note that the shared library's name if "libstlport_shared.so" to avoid
+  naming conflicts with certain Android system images which include a
+  system-level libstlport.so (which happens to not be ABI-stable and
+  cannot be used from NDK-generated machine code).
+
+  "stlport_static" is preferred if you have only one shared library in your
+  project: only the STL functions and variables you actually need will be
+  linked to your machine code, reducing its code size, and you won't need
+  to load the dynamic stlport_shared at startup.
+
+
+IV. STLport-specific issues:
+----------------------------
+
+This NDK provides prebuilt static and shared libraries for STLport,
+but you can force it to be rebuilt from sources by defining the following
+in your environment or your Application.mk before building:
+
+    STLPORT_FORCE_REBUILD := true
+
+STLport is licensed under a BSD-style open-source license. See
+sources/android/stlport/README for more details about the library.
+
+
+V. Future Plans:
+----------------
+
+  - Make STLport compatible with C++ exceptions and RTTI
+  - Full GNU libstdc++ support
+  - uSTL support?
+
+</pre></body></html>
diff --git a/docs/STANDALONE-TOOLCHAIN.html b/docs/STANDALONE-TOOLCHAIN.html
index dd93e5f..1fba9aa 100644
--- a/docs/STANDALONE-TOOLCHAIN.html
+++ b/docs/STANDALONE-TOOLCHAIN.html
@@ -1,4 +1,5 @@
-<pre>        USING THE ANDROID TOOLCHAIN AS A STANDALONE COMPILER
+<html><body><pre>
+USING THE ANDROID TOOLCHAIN AS A STANDALONE COMPILER
        ======================================================
 
    WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
@@ -172,6 +173,15 @@
 5.3/ Exceptions and RTTI:
 - - - - - - - - - - - - -
 
-The toolchain binaries currently do *not* support C++ exceptions and RTTI.
-Support for these features is planned for a future NDK release.
-</pre>
\ No newline at end of file
+The toolchain binaries *do* support C++ exceptions and RTTI by default.
+However, it does not come with a full libstdc++, and you will need to
+explicitely link to libsupc++.a to use these features in your code. As in:
+
+    arm-linux-androideabi-g++ .... -lsupc++
+
+Proper toolchain configuration to avoid this is planned for the future.
+
+If you don't need these features, consider using -fno-exceptions and -fno-rtti
+to generate smaller machine code.
+
+</pre></body></html>
\ No newline at end of file
diff --git a/tests/device/test-basic-exceptions/README b/tests/device/test-basic-exceptions/README
new file mode 100644
index 0000000..6861466
--- /dev/null
+++ b/tests/device/test-basic-exceptions/README
@@ -0,0 +1,11 @@
+This test is meant to test the most basic level of exception support
+even if you are not using a regular C++ STL. No <stdexcept> required.
+
+Normally, the only thing needed is adding -fexceptions to your LOCAL_CFLAGS
+and that's it. Alternatively, use it in APP_CFLAGS to add the flag to all your
+modules at the same time.
+
+This is really a way to check that the C++ compiler properly links against
+libsupc++.a without any kind of conflict, and that the try / throw / catch
+features do really work.
+
diff --git a/tests/device/test-basic-exceptions/jni/Android.mk b/tests/device/test-basic-exceptions/jni/Android.mk
new file mode 100644
index 0000000..5afbbdd
--- /dev/null
+++ b/tests/device/test-basic-exceptions/jni/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_basic_exceptions
+LOCAL_SRC_FILES := test_basic_exceptions.cpp
+LOCAL_CPPFLAGS := -fexceptions
+LOCAL_LDLIBS := -lsupc++
+include $(BUILD_EXECUTABLE)
diff --git a/tests/device/test-basic-exceptions/jni/test_basic_exceptions.cpp b/tests/device/test-basic-exceptions/jni/test_basic_exceptions.cpp
new file mode 100644
index 0000000..8edca94
--- /dev/null
+++ b/tests/device/test-basic-exceptions/jni/test_basic_exceptions.cpp
@@ -0,0 +1,20 @@
+#include <cstdio>
+#include <new>
+
+int main()
+{
+    char *buf;
+    try
+    {
+        buf = new char[512];
+        throw "Memory allocation failure!";
+
+        std::fprintf(stderr,"KO: Exception *not* raised!\n");
+        return 1;
+    }
+    catch( char const* str )
+    {
+        std::printf("OK: Exception raised: %s\n", str);
+    }
+    return 0;
+}
diff --git a/tests/device/test-basic-rtti/README b/tests/device/test-basic-rtti/README
new file mode 100644
index 0000000..d33e2b2
--- /dev/null
+++ b/tests/device/test-basic-rtti/README
@@ -0,0 +1,7 @@
+This test is meant to test the most basic level of RTTI support
+even if you are not using a regular C++ STL. No <typeinfo> required.
+
+This is really a way to check that the C++ compiler properly links against
+libsupc++.a without any kind of conflict, and that the dynamic_cast<>
+really works.
+
diff --git a/tests/device/test-basic-rtti/jni/Android.mk b/tests/device/test-basic-rtti/jni/Android.mk
new file mode 100644
index 0000000..e562c87
--- /dev/null
+++ b/tests/device/test-basic-rtti/jni/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := test_basic_rtti
+LOCAL_SRC_FILES := test_basic_rtti.cpp
+LOCAL_CPPFLAGS := -frtti
+LOCAL_LDLIBS := -lsupc++
+include $(BUILD_EXECUTABLE)
diff --git a/tests/device/test-basic-rtti/jni/test_basic_rtti.cpp b/tests/device/test-basic-rtti/jni/test_basic_rtti.cpp
new file mode 100644
index 0000000..22b51f7
--- /dev/null
+++ b/tests/device/test-basic-rtti/jni/test_basic_rtti.cpp
@@ -0,0 +1,37 @@
+#include <cstdio>
+
+class Foo
+{
+public:
+  virtual ~Foo() { }
+  virtual void print()
+  {
+    std::printf("in Foo!\n");
+  }
+};
+
+class Bar: public Foo
+{
+  public:
+  void print()
+  {
+    std::printf("in Bar!\n");
+  }
+};
+
+int main()
+{
+    Foo* foo = new Bar();
+    Bar* bar;
+
+    bar = dynamic_cast<Bar*>(foo);
+    if (bar != NULL) {
+        printf("OK: 'foo' is pointing to a Bar class instance.\n");
+    } else {
+        fprintf(stderr, "KO: Could not dynamically cast 'foo' to a 'Bar*'\n");
+        return 1;
+    }
+
+    delete foo;
+    return 0;
+}