当前问题的场景:
1,我有一个共享库sharedlibrary.so, 这个共享库是使用c++语言编写的,我使用Android studio 编出来的,这个共享库里有很多函数:function1,function2,function3等等。
2,现在需要搞出一个app,来验证该共享库的功能,于是我使用AS新建了一个支持c++的工程。在工程中的native-lib.cpp文件中,我包含了sharedlibrary.so,对应的头文件,将sharedlibrary.so中对外的方法在native-lib.cpp文件中使用jni进行封装,以便java层能调用相关函数,使用sharedlibrary.so提供的功能。另外我开发Android相关的界面,用来展示数据。
3,编译apk时,提示link失败,在native-lib.cpp文件中找不到sharedlibrary.so对应的函数,log如下:
[1/2] Building CXX object CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o
[2/2] Linking CXX shared library ..\..\..\..\build\intermediates\cmake\release\obj\armeabi-v7a\libnative-lib.so
FAILED: cmd.exe /C "cd . && E:\Android\SDK\ndk-bundle\toolchains\llvm\prebuilt\windows-x86_64\bin\clang++.exe --target=armv7-none-linux-androideabi --gcc-toolchain=E:/Android/SDK/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64 --sysroot=E:/Android/SDK/ndk-bundle/sysroot -fPIC -isystem E:/Android/SDK/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=19 -g -DANDROID -ffunction-sections -funwind-tables -fstack-protector-strong -no-canonical-prefixes -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -mthumb -Wa,--noexecstack -Wformat -Werror=format-security -std=c++11 -std=c++11 -frtti -fexceptions -Os -DNDEBUG -Wl,--exclude-libs,libgcc.a -Wl,--exclude-libs,libatomic.a -nostdlib++ --sysroot E:/Android/SDK/ndk-bundle/platforms/android-19/arch-arm -Wl,--build-id -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--fix-cortex-a8 -Wl,--exclude-libs,libunwind.a -LE:/Android/SDK/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -Wl,--no-undefined -Wl,-z,noexecstack -Qunused-arguments -Wl,-z,relro -Wl,-z,now -shared -Wl,-soname,libnative-lib.so -o ..\..\..\..\build\intermediates\cmake\release\obj\armeabi-v7a\libnative-lib.so CMakeFiles/native-lib.dir/src/main/cpp/native-lib.cpp.o -llog -latomic -lm "E:/Android/SDK/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_static.a" "E:/Android/SDK/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++abi.a" "E:/Android/SDK/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libandroid_support.a" "E:/Android/SDK/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libunwind.a" "-ldl" && cd ."
E:\CodeFromNewServer\NativeSkeletonDemo\app\src\main\cpp/native-lib.cpp:37: error: undefined reference to 'function1'
E:\CodeFromNewServer\NativeSkeletonDemo\app\src\main\cpp/native-lib.cpp:47: error: undefined reference to 'function2'
E:\CodeFromNewServer\NativeSkeletonDemo\app\src\main\cpp/native-lib.cpp:54: error: undefined reference to 'function3'
E:\CodeFromNewServer\NativeSkeletonDemo\app\src\main\cpp/native-lib.cpp:60: error: undefined reference to 'function...'
问题原因:
问题的原因是没有在sharedlibrary.so中导出function1,function2,function3等相关的符号,
这个可以通过Android sdk中自带的工具aarch64-linux-android-nm.exe -D sharedlibrary.so,来确认,执行上述命令之后发现在输出的符号中找不到function1,function2,function3等相关的符号。
在代码中的函数前面没有加__attribute__ ((visibility ("default")))。
具体到我的情况,我是使用VERSION_SCRIPT 脚本来控制符号的导出,在脚本中没有function1,function2,function3等相关的符号。
解决方法:
在VERSION_SCRIPT脚本中添加要导出的符号function1,function2,function3等。
在这个问题的解决过程中查看了几个比较好的博客:
https://www.cnblogs.com/zzqcn/p/3640353.html:这篇博客中提到,在实际工作中,许多软件模块是以动态库的方式提供的。作为模块开发人员,我们不仅要掌握如何编写和构建动态库,还要了解如何控制动态库的导出接口,这样,我们可以像模块的用户仅导出必要的接口,而另一些内部接口,为了安全或其它考虑,可以不必导出。当需要导出C++类时,问题显得更复杂一些,不过我认为不应导出C++类成员,而只应导出纯C接口。
随后,博客中通过代码实例展示了如何导出和使用动态库中的C++类成员。
https://blog.csdn.net/henry860916/article/details/50434228:博客中提到了另一种可能出现这个问题的情况,作者用c语言写的so库,应该在对应头文件中加
#ifdef __cplusplus
extern "C"
{
#endif 标识如果c++程序调用这些函数,需按照c编译器的规则生成符号。
https://blog.csdn.net/stpeace/article/details/73302833
https://blog.csdn.net/github_38075367/article/details/75036135
最后还有一种情况是没有在CMakeLists.txt 中去链接
target_link_libraries( # Specifies the target library.
native-lib
sharedlibrary 如果不链接这个库,也会出现上面的问题
# Links the target library to the log library
# included in the NDK.
${log-lib} )