1. Android NDK
NDK开发过程中常用的库定义在android-ndk-r25c/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android
如libc++_shared.so
libc++_static.a
libstdc++.a
库
ndk工具链下载:./bin/sdkmanager --install "ndk;25.0.8775105"
2. 链接问题
问题背景
给定第三方依赖库头文件和实现库,现在需要集成到自己的工程中。
第三方库ThirdLib.h
如下:
实现库libthirdparty.so
给外部调用的符号表如下:
集成代码如下:
对应的Android.bp
编译时会遇到如下错误:
问题分析
在编译main.cpp时出现符号找不到,需要链接的符号如下:
函数名为makeRandomString
,正是libthirdparty.so
提供的符号,但是libthirdparty.so
提供的符号为:
可以发现符号确实不一样,一个是std::__1
前缀,另一个是std::__ndk1
前缀。
第三方库的实现库没法改变,那么只能在集成端生成std::__ndk1
前缀的库进行调用,根据提示,std::__1
符号找不到,是否意味着本地生成的默认就是std::__1
前缀的符号呢?编写如下代码进行分析:
查看生成的符号表:
本地生成的符号确实就是std::__1
前缀,接下来可以借助IDE的力量查看根据什么条件决定这个前缀,前提是需要使用vscode + clangd配置好代码跳转环境,可以参考我的另一篇文章: Android配置C++开发环境 根据提示,我们输入以下符号:
点击__1
进行跳转,以下代码使用的是Android12代码环境:
跟踪代码发现,std::__1
其中的1
是通过_LIBCPP_ABI_VERSION
宏定义的,默认值就是1
,那么只要提前将_LIBCPP_ABI_VERSION
定义为ndk1
就可以按照std::__ndk1
进行编译。
但是需要找到提供这种符号实现的库,根据ndk字眼猜测是NDK工具链中提供的,在android_sdk/ndk/25.0.8775105/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib
目录下使用android_find_symbols.sh
搜索std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >
,具体搜索可以参考我的另一篇文章: Android定位需要引用的动态库 得到如下结果:
接下来我们就可以写一个中间层,向下对接第三方库,提供std::__ndk1
符号;向上对接本地代码,因为中间层代码实现时不可能同时提供std::__1
和std::__ndk1
符号,所以向上对接时需要替换为char*
。
编写中间层代码,用于实现char*
和std::__ndk1
之间的转换:
最后需要提供一个包装库可以给本地代码直接调用:
最后,本地集成的代码:
完整的demo可以参考: ndk_string_test.zip