链接时出现错误:
/home/huangzhen/work/ffv2/projects/tcl/a3agl/vendor/focaltech/src/ff_hal/src/service/hidlservice.cpp:39: error: undefined reference to 'vendor::mediatek::hardware::focalfingerprint::V1_0::IFocalFingerprint::registerAsService(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> > const&)'
而查看vendor.mediatek.hardware.focalfingerprint@1.0_vendor.so的符号表,该so为a3agl项目下编译得出:
huangzhen@FPRSVR02:~/work/ffv2/prebuilts/android/8.x/libs/32$ nm -CD vendor.mediatek.hardware.focalfingerprint@1.0_vendor.so | grep registerAs*
0000d171 T vendor::mediatek::hardware::focalfingerprint::V1_0::IFocalFingerprint::registerAsService(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
注意绿色部分.ffv2在链接时使用的命名空间为std::__ndk1
而编译so时使用的命名空间为 std::__1
stackoverflow上的问题:
Q:
undefined reference to 'webrtc::CreateSessionDescription(std::__ndk1::basic_string, std::__ndk1::allocator > const&, std::__ndk1::basic_string, std::__ndk1::allocator > const&, webrtc::SdpParseError*)'
After updating android ndk revision 11, I get some problems. I could not build my project because of above it.
In Android Developer, I found that 'Changed libc++’s inline namespace to std::__ndk1 to prevent ODR issues with platform libc++.', but I cannot understand.
How can I fix it?
Thanks for helping me.
A:
I think my way is more or less tricky, but it works. I went into /ndk-root-path//sources/cxx-stl/llvm-libc++/libcxx/include, there is a file named '__config'. open it and find out all lines with '_LIBCPP_BEGIN_NAMESPACE_STD', this is where the inline namespace '__ndk1' added. So I just comment out all inline namespaces, like:
352 #define _LIBCPP_BEGIN_NAMESPACE_STD namespace std {//inline namespace _LIBCPP_NAMESPACE { 353 #define _LIBCPP_END_NAMESPACE_STD } //} 354 #define _VSTD std//::_LIBCPP_NAMESPACE 356 namespace std { // inline namespace _LIBCPP_NAMESPACE { // } }
There should be 4 or 5 pieces of these codes. after comment that, you can rebuild your ndk project, it should works.
Q:
I have some pre-compiled so files, so who knows what flags were used to generate them. I'm curious to know which runtime/version of the STL they were compiled with (gnustl_shared? stlport_shared?) to avoid clashes with my own code.
How can I find out from the compiled so files which runtime they were compiled to use?
This is all Android NDK C++ code.
A:
Another trick that can help you identify if libc++ was used even if it was c++_static: readelf -sW path/to/lib | grep __ndk1. All the libc++ symbols are in an internal namespace (std::__ndk1 instead of just std) to support versioning the STL and avoiding clashes with the system STL. If it's a very old (r10 or older) libc++, it will be just __1. I don't know of a good way to spot gnustl vs stlport, but that will help with libc++ vs not-libc++.
这里需要判断a3a项目中使用libc++版本,使用的namespace是__ndk1还是__1.
A:
Like Alex said, you can use readelf to figure out some of this. The following can let you know if the library depends on a shared STL, and which one:
$ readelf -dW path/to/libfoo.so | grep NEEDED 0x00000001 (NEEDED) Shared library: [libc++_shared.so] 0x00000001 (NEEDED) Shared library: [libc.so] 0x00000001 (NEEDED) Shared library: [libm.so] 0x00000001 (NEEDED) Shared library: [libstdc++.so] 0x00000001 (NEEDED) Shared library: [libdl.so]
As you can see, this library depends on libc++_shared. Ignore the libstdc++.so that you also see. That's https://github.com/android-ndk/ndk/issues/105.
If it depends on a static STL (or your library is a static library) and wasn't built with -fvisibility=hidden, that method won't work. In this case you can still identify if the library was built against libc++ or not-libc++. All the libc++ symbols are in an internal namespace (std::__ndk1instead of just std) to support versioning the STL and avoiding clashes with the system STL. If it's a very old (r10 or older) libc++, it will be just __1.
$ readelf -sW path/to/libfoo.so | grep __ndk1 6: 000008bf 86 FUNC WEAK DEFAULT 12 _ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6__initEPKcj 7: 000008a9 22 FUNC WEAK DEFAULT 12 _ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED2Ev
If you're trying to figure out which version of the NDK a library was built with, you can usehttps://android.googlesource.com/platform/ndk/+/master/parse_elfnote.py.
$ python parse_elfnote.py foo/libs/armeabi-v7a/libfoo.so ----------ABI INFO---------- ABI_NOTETYPE: 1 ABI_VENDOR: Android ABI_ANDROID_API: 14 ABI_NDK_VERSION: r17-canary ABI_NDK_BUILD_NUMBER: dev
Most of this information will only be available for libraries built with a relatively new NDK (r14? I don't remember when we added this).
应该是ffv2的编译使用了libstdc++.so的缘故
解决办法:
1.依靠stackoverflow的方式,修改NDK的命名空间配置:
下__config文件:
改为
2.为了适配客户,hidl的库不在android项目中产生,将hidl-gen自动生成的XXXXAll.cpp文件以及相关头文件导入到ffv2项目中
通过NDK产生
1)使用hidl-gen工具,通过IBase,IServiceManager hal文件生成模块所需的头文件
生成的头文件位于:
2)使用hidl-gen工具,通过IFocalFingerprintService.hal与type.hal文件生成types.cpp与FocalFingerprintServiceAll.cpp文件和相关头文件.并参加编译.
3)以上两步骤相当于在项目中编译生成vendor.mediatek.hardware.focalfingerprintservice@1.0.so
所以修改ndk配置的目的主要在于适配诸如libhidl.so之类来自于a3agl项目的so库.