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;
+}