在NDK中,android平台提供了一个非常小的C++运行时(runtime)支持库(/system/lib/libstdc++)以及相应的头文件。
默认的,'system'运行时(runtime)【没有】提供下面的功能:
。标准C++库的支持(除了几个不太重要(trivial)的头文件)
。c++异常的支持
。RTTI的支持
然而,NDK有提供很多的”帮助C++运行时(runtime)“,里面就有支持上面的那些功能,或者这些特性的子集。
选择你要用的运行时(runtime),在你的Application.mk中定义App_STL为以下中的一个值:
system -> 使用默认最小的C++运行库.
gabi++_static -> 使用GAbi++的静态运行库.
gabi++_shared -> 使用GAbi++的动态运行库.
stlport_static -> 使用STLport的静态运行库.
stlport_shared -> 使用TLport的懂态运行库.
gnustl_static -> 使用GNU的静态运行库.
gnustl_shared -> 使用GNU的动态运行库.
如果你没有在你的Application.mk中定义APP_STL,默认为‘system’运行时。下面是一个用静态GNU STL的例子,加一行像这样子的:
APP_STL := gnustd_static
对于你的Application.mk,你只需要选择一个C++运行时就可以使得你所有的代码都依赖于它了。混合动态库编译C++运行时是不可能的。
重要提示:在Android.mk中定义APP_STL是没有用的。
如果你没有使用NDK的编译系统,你还是可以用GNU STL的,更多细节,请看 STANDALONE-TOOLCHAIN 。
各个‘运行时’的能力如下所示:
C++ C++ Standard
Exceptions RTTI Library
system no no no
gabi++ yes yes no
stlport yes yes yes
gnustl yes yes yes
系统运行时只提供了非常少的C++标准头文件。
Android平台提供了相应的C++运行时。如果你使用了这个,你的C++二进制将会自动的链接到系统libstdc++。它只提供了如下的头文件:
cassert cctype cerrno cfloat climits cmath csetjmp csignal cstddef
cstdint cssdio cstdlib cstring ctime cwchar cwchar new stl_pair.h typeinfo
utility
除此之外的就不支持了,包括std::string 或者 std::vector
这是一个提供了跟系统运行时(System runtime)一样的头文件的新的简约的运行时,但是他额外的加入了对RTTI(Runtime Type Information)以及异常(exception)处理的支持。
如果你坚持(insist on)要用它,请读一下下面的”重要考虑“的“RTTI支持”和“静态运行时“部分。
这是一个可以用用在Android的STLport(http://www.stlport.org)端口。它将为你提供一个完整的C++标准库(standard library)的头文件以及 RTTI 和 对异常(exception)处理的支持。
这是因为该库中加入了GAbi++的副本.
它可以作为静态和动态库。如果你要使用它,在你的Application.mk中选择下面其中的一行:
APP_STL := stlport_shared
APP_STL := stlport_static
注意最好使用‘stlport_shared’,原因在下面的”重要考虑“的”静态运行时“里有解释。
这个是GNU标准的C++库来着(亦称为:libstdc++-v3),提供了更多的特性。注意,在其他的平台,动态库
"libstdc++.so"的文件名是"libgnustl_shared.so".
如果你要使用它,请阅读一下下面的”c++ Exception支持“,”RTTI支持“以及”静态运行时考虑“部分。
从NDK r5开始,NDK toolchain 支持c++ exceptions,然而为了兼容前面版本的所有的C++代码默认用-fno-exceptions编译(即默认没有咯)。
要使用它,在你的Android.mk中,你可以使用
LOCAL_CPP_FEATURES += exceptions
关于这个变量的更多细节到 ANDROID-MK 中查看
另一个启用的方法是在你的LOCAL_CPPFLAGS中定义(但是还是推荐用LOCAL_CPP_FEATURES更好)
LOCAL_CPPFLAGS += -fexception
更简单的是,在你的Application.mk中加入一行,它会自动应用到你项目的所有模块中:
APP_CPPFLAGS += -fexception
类似的,从NDK r5之后,NDK toolchain 也支持c++ RTTI(RunTime Type Information),然而为了兼容前面版本的所有的C++代码默认用-fno-rtti编译(即默认没有咯)。要使用它,加入下面的东西到你的模块中:
LOCAL_CPP_FEATURES += rtti
也等同于:
LOCAL_CPPFLAGS += -frtti
或者更简单的就是在你的Application.mk中这样写咯:
APP_CPPFLAGS += -frtti
请记住,一个C++静态库变量最好是只被链接到一个二进制文件。这个的意思是如果你的项目只包含一个动态库,那么你可以的链接它,如:stlport_static,然后所有的东西都运行正常。
另一方面,如果你的项目有两个动态库(如 libfoo.so 以及 libbar.so),然后它们都链接到相同的静态库,然后它们两个在最终的二进制文件中都会有那个静态库的副本。这是有问题的,因为某些全局变量/内部提供运行时重复使用。
这就有可能是代码运行结果不正确,比如:
。内存分配在一个库里面,然后被另一个库给释放掉了,或者败坏(corrupt)堆。
。在libfoo.so中抛出的异常不能被libbar.so捕获(可能程序就简单的崩溃了)
。std::cout的缓冲就不能正常的工作
换种说法,如果你的项目要求有几个动态库模块,那么C++ runtime选择动态库吧。
如果你的C++ runtime使用的是动态库,那么记住,你必须在你的应用运行时,在其它依赖该动态库之前加载完该库。
举个列子,考虑以下模块的情形
。libfoo.so
。libbar.so 被libfoo.so用到
。libstlport_shared.so被上面两个都用到
你必须按上面相反的顺序加载那些库,如下:
static {
System.loadLibrary("stlport_shared");
System.loadLibrary("bar");
System.loadLibrary("foo");
}
注意你使用System.loadLibray()时不需要加前缀'lib'的,除非你指定了整个路径(full path):
System.loadLibrary("/path/to/libstlport_shared.so")
这种用硬编码(hard-codes)的方式是不推荐的。
NDK为STLport提供了的预编译的静态库和动态库,但你可在你的环境下或你的Application.mk下定义下面的东西就可以强制使其重新编译了:
STLPORT_FORCE_REBULID := true
STLport是在BSD风格的开放源代码许可协议发布的。更多详细内容,请参见source/cxx-stl/stlport/README