田海立@CSDN 2020-11-22
《Android源码中的c++ STL》中讲到Android Source中有内置的LLVM c++ STL和NDK的c++ STL,使用到这两个stl的时候如何区分呢?c++是用namespace隔离的,stl也是这样隔离的。本文逐步分析STL中如何用namespace隔离这两个STL,这也同时可以解惑stl使用者使用时找不到stl中的标号的问题的原因。
应用使用stl,首先要有STL的原型,这些在各个stl的头文件里;而源文件被编译成库(动态.so/静态.a)。头文件与对应的库应该匹配使用。
1. STL c++头文件和源文件
Android中根据选择的stl会有不同的路径:
ndk: prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/include/
aosp: external/libcxx/include/
STL中的头文件和源文件前后都会用下面的宏来包含:
_LIBCPP_BEGIN_NAMESPACE_STD
// sources or headers
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_BEGIN_NAMESPACE_STD和_LIBCPP_END_NAMESPACE_STD定义在文件__config中,这些不同的STL路径下都会包含各自的__config文件。
2. _LIBCPP_BEGIN_NAMESPACE_STD和_LIBCPP_END_NAMESPACE_STD的定义【__config中】
_LIBCPP_BEGIN_NAMESPACE_STD和_LIBCPP_END_NAMESPACE_STD定义在文件__config中
#define _LIBCPP_BEGIN_NAMESPACE_STD namespace std {inline namespace _LIBCPP_NAMESPACE {
#define _LIBCPP_END_NAMESPACE_STD } }
2.1 _LIBCPP_NAMESPACE的定义
//__config: [external/libcxx/include/]
#define _LIBCPP_NAMESPACE _LIBCPP_CONCAT(__,_LIBCPP_ABI_VERSION)
//__config: [prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/include/]
#define _LIBCPP_NAMESPACE _LIBCPP_CONCAT(__ndk,_LIBCPP_ABI_VERSION)
2.1.1 _LIBCPP_CONCAT
#define _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_X##_LIBCPP_Y
#define _LIBCPP_CONCAT(_LIBCPP_X,_LIBCPP_Y) _LIBCPP_CONCAT1(_LIBCPP_X,_LIBCPP_Y)
2.1.2 _LIBCPP_ABI_VERSION
#ifndef _LIBCPP_ABI_VERSION
#define _LIBCPP_ABI_VERSION 1
#endif
所以,在Android源码中_LIBCPP_NAMESPACE有两个定义:
- in libc++.so: __1
- in libc++_shared: __ndk1
_LIBCPP_BEGIN_NAMESPACE_STD也就有两个定义:
- in libc++.so: namespace std {inline namespace __1 {
- in libc++_shared.so: namespace std {inline namespace __ndk1 {
3. 结论
Android源码中的STLs:
namespace in libc++【头文件: external/libcxx/include/】:
std::__1
namespace in libc++_shared【头文件: prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/include/】:
std::__ndk1
所以,在编译链接时出现找不到STL中的变量/函数等错误(特别出现了namespace “std::__1”,“std::__ndk1”等字眼),要考虑使用STL的头文件路径/链接库等原因了。这会在诸如你的不同编译单元之前是单独编译的,而它们使用了的不一致的STL时出现。而如果使用到第三方库,需要与他们沟通使用一致的STL,不然等到运行时再出现莫名其妙的问题调试起来就更麻烦了。