我正在使用cmake在Android Studio中创建我的共享库。库正确构建和链接,我能够在lib / armeabi-v7a下的Apk中查看我的所有库。
图书馆链接如下:
我通过拨打System.loadLibrary("lib1");
我能够调用Lib1,但是一旦Lib1尝试访问Lib2,我收到一条传播消息,说Lib2没有被加载。
然后我想我必须加载其他库,所以我进行了以下调用,但结果是相同的传播消息" Lib2未加载"。
System.loadLibrary("lib5");
System.loadLibrary("lib4");
System.loadLibrary("lib3");
System.loadLibrary("lib2");
System.loadLibrary("lib1");
为什么Lib1无法调用Lib2?是否在导致库加载失败的位置解压缩了其他共享库?
我想请注意,在切换到使用cmake之前,我已正确加载了libs。我相信我之前手动编译我的lib并将它们存储在我的Android Studio项目的/ jniLibs和/ assets目录中,但那是不久之前所以我的内存不清楚细节。
答案 0 :(得分:3)
由于您的更改似乎正在生效,我猜这不会像将二进制文件放在错误的位置那样意外。 (我自己有时上传到jniLibs/armeabi-v7a
然后意识到我正在测试依赖jniLibs/arm64-v8a
的64位APK。或者反过来在32位Android设备上安装双架构apk时。)
我想我们也可以在加载时排除未解析的符号,因为它通常会在adb logcat
我记得在过去看到这个问题时,它通常被证明是lib2的 soname 的问题。虽然PC Linux可以使用liblib2.so.1
之类的东西,但Android似乎要求所有的sonames都以.so
要检查lib2上的soname,请运行readelf -a liblib2.so
。如果我的描述看起来不正确,请重新启动您的NDK版本并确保在链接时添加-Wl,-soname,liblib2.so
。
此外,运行readelf -a liblib1.so
并确保其对liblib2.so的引用使用新的soname,例如(NEEDED) Shared Library: [liblib2.so]
。您可能还需要重新链接liblib1.so。
我想请注意,在切换到使用cmake之前,我已正确加载了libs。
我假设CMake用于构建的NDK阶段,而不是Java,这可以解释soname的变化。
注意:你添加一个额外的" lib"有点令人困惑。在每个图书馆的名字中。如果您使用了System.loadLibrary("1")
,System.loadLibrary("2")
答案 1 :(得分:0)
取决于您的Gradle文件,这可能是因为AS仅执行externalNativeBuild
语句中列出的最后一个cmake文件。
您可以查看APK内部的内容,以检查实际上是在构建和捆绑哪些库。如果将apk扩展名更改为.zip,然后解压缩并查看lib
目录,则会发现一个构建目录列表,其中包含.so文件。如果看不到与System.loadLibrary(<libName>);
调用相对应的.so,则将收到运行时错误。
一个引起类似问题的问题对我来说是我试图通过在应用程序的Gradle版本中使用externalNativeBuild
来使用与要包含的每个库相对应的多个cmake文件像这样的文件:
externalNativeBuild {
cmake {
path "CMakeLists1.txt"
path "CMakeLists2.txt"
}
}
我注意到,只有该语句中列出的最后一个CMakeLists.txt 被执行。这导致仅一个.so文件输出到我的APK的lib
目录中,而不是两个都输出。我相信AS的意图是在该语句中仅引用一个cmake文件。如果您像我一样引用了更多内容,则可能只是构建了最后一个,因此其他(在您的情况下,“ lib1”之后的所有内容)都将丢失。