我在我的原生android应用程序中使用了许多静态预构建的静态库,一切正常。现在我想将我的一个静态库切换为.so。我成功地能够通过在其android.mk中用BUILD_SHARED_LIBRARY替换BUILD_STATIC_LIBRARY并添加所需的依赖项来构建.so库。
我还可以通过在其android.mk中用PREBUILT_SHARED_LIBRARY替换相应的PREBUILT_STATIC_LIBRARY来构建我的应用程序。生成的应用程序现在无法启动。我甚至无法指出调试器附加到应用程序的位置。
除此之外,我不明白的是构建系统如何知道应该从库中导入该函数。我的库应该导出一个函数,但我没有将它声明为dllexport / import或其他东西。我的应用程序中仍然没有未解析的符号(当我从列表中删除预构建的库时,未解析的符号按预期显示)。
另一个问题是我看到生成了两个.so文件。 obj / local / $(TARGET_ARCH_ABI)文件夹中的一个大文件和libs / $(TARGET_ARCH_ABI)中的另一个小文件。在声明我的预建库时,我引用了libs文件夹中的第二个。
我确实尝试在stackoverflow中搜索答案,并找到了不少相关帖子:
但我不知道这些帖子与我的问题有什么关系,因为我可以成功构建甚至链接我的应用程序。
答案 0 :(得分:4)
您需要在java代码中以反向依赖顺序加载库。你以前可能有这样的事情:
System.loadLibrary("mylib");
现在,如果您的预构建库(以前是静态库,现在是共享库)名为dependencylib
,则需要更改用于将库加载到此的代码:
System.loadLibrary("dependencylib");
System.loadLibrary("mylib");
关于你的问题链接器如何解决它;链接libmylib.so
时,它会在您指定的所有其他库中查找所有未定义的符号(即在libdependencylib.so
和libc.so
以及其他系统库中)。只要在某处找到所有未定义的符号,链接器就可以了。然后在运行时,加载libmylib.so
时,它再次执行相同的例程;在当前进程中加载的符号列表中查找所有未定义的符号。在linux上,您通常不需要像在Windows上那样手动将符号标记为dllexport - 默认情况下会导出所有非静态符号。
答案 1 :(得分:2)
更改STATIC -> SHARED
后,应用无法启动可能有两个原因。
未安装预构建的库。连接设备后,运行adb ls -l /data/your.package.name/lib/
。你看到那里的图书馆吗?
未加载预构建的库。在主Java类中,尝试
static {
System.loadLibrary("prebuiltname");
System.loadLibrary("yourlib");
}
这是一个静态构造函数,是加载JNI库的最安全的地方。
答案 2 :(得分:1)
如果您使用的是Linux,则会看到使用nm -D
导出的符号。例如nm -D libzip.so:
...
0000000000009dc0 T zip_unchange
0000000000009dd0 T zip_unchange_all
0000000000009e30 T zip_unchange_archive
0000000000009e60 T _zip_unchange_data
如果要控制函数的可见性,请使用__attribute__ ((visibility ("default")))
和命令行-fvisibility = hidden。更多信息here。
答案 3 :(得分:0)
现在我想将我的一个静态库切换为.so。我成功地能够通过在其android.mk中用BUILD_SHARED_LIBRARY替换BUILD_STATIC_LIBRARY并添加所需的依赖项来构建.so库。
我认为你不能如果它是一个C ++库。来自<doc>/CPLUSPLUS-SUPPORT.html
:
请记住给定C ++的静态库变体 运行时只能连接到单个二进制文件中以获得最佳效果 条件。
这意味着如果你的项目包含一个 单个共享库,您可以链接到例如stlport_static和 一切都会正常工作。
另一方面,如果你有两个 项目中的共享库(例如libfoo.so和libbar.so) 两者都链接到相同的静态运行时,每一个都会 在最终的二进制映像中包含运行时代码的副本。这个 是有问题的,因为使用/提供了某些全局变量 内部由运行时复制。
这可能导致代码无法正常工作,例如:
*在一个库中分配的内存,在另一个库中释放的内存会泄漏 甚至腐败堆。
* libfoo.so中引发的异常无法在libbar.so中捕获(并且可能 只是让程序崩溃) * cout的缓冲不能正常工作
如果要链接可执行文件和共享,也会发生此问题 库到同一个静态库。
换句话说,如果您的项目需要多个共享库模块, 然后使用C ++运行时的共享库变体。
从上面来看,这意味着所有需要链接到相同的C ++标准运行时共享对象。