Android 从 .lib 切换到 .so 后应用崩溃

Android app crashes after switching from .lib to .so

我在我的原生 android 应用程序中使用了一些静态的预构建静态库,一切正常。现在我想将我的静态库之一切换为 .so。通过在 android.mk 中用 BUILD_SHARED_LIBRARY 替换 BUILD_STATIC_LIBRARY 并添加所需的依赖项,我成功地构建了 .so 库。

我还能够通过在其 android.mk 中将相应的 PREBUILT_STATIC_LIBRARY 替换为 PREBUILT_SHARED_LIBRARY 来构建我的应用程序。生成的应用程序现在无法启动。我什至无法指出调试器附加到应用程序的位置。

除此之外,我不明白的是构建系统如何知道应该从库中导入函数。我的 so 库应该导出一个函数,但我没有将它声明为 dllexport/import 之类的。我的应用程序中仍然没有未解析的符号(当我从列表中删除我的预构建库时,未解析的符号按预期出现)。

另一个问题是我看到生成了两个 .so 文件。 obj/local/$(TARGET_ARCH_ABI) 文件夹中的一个大文件和 libs/$(TARGET_ARCH_ABI) 中的另一个小文件。在声明我的预建库时,我引用了 libs 文件夹中的第二个库。

我确实尝试在 Whosebug 上搜索答案并找到了很多相关帖子:

但我看不出这些帖子与我的问题有什么关系,因为我可以成功构建甚至 link 我的应用程序。

如果您使用 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.

Now I want to switch one of my static libraries to be .so. I was successfully able to build .so library by replacing BUILD_STATIC_LIBRARY with BUILD_SHARED_LIBRARY in its android.mk and adding required dependencies.

如果它是一个 C++ 库,我认为你做不到 。来自 <doc>/CPLUSPLUS-SUPPORT.html:

Please keep in mind that the static library variant of a given C++ runtime SHALL ONLY BE LINKED INTO A SINGLE BINARY for optimal conditions.

What this means is that if your project consists of a single shared library, you can link against, e.g., stlport_static, and everything will work correctly.

On the other hand, if you have two shared libraries in your project (e.g. libfoo.so and libbar.so) which both link against the same static runtime, each one of them will include a copy of the runtime's code in its final binary image. This is problematic because certain global variables used/provided internally by the runtime are duplicated.

This is likely to result in code that doesn't work correctly, for example:

* memory allocated in one library, and freed in the other would leak or even corrupt the heap.
* exceptions raised in libfoo.so cannot be caught in libbar.so (and may simply crash the program).
* the buffering of cout not working properly

This problem also happens if you want to link an executable and a shared library to the same static library.

In other words, if your project requires several shared library modules, then use the shared library variant of your C++ runtime.

从上面看,这意味着一切都需要 link 针对同一个 C++ 标准运行时共享对象。

您需要在 java 代码中以反向依赖顺序加载库。你以前可能有这样的事情:

System.loadLibrary("mylib");

现在,如果您的预建库(以前是静态库,现在是共享库)被命名为 dependencylib,您需要更改将库加载到此的代码:

System.loadLibrary("dependencylib");
System.loadLibrary("mylib");

至于你的问题链接器是怎么算出来的;当链接 libmylib.so 时,它会在您指定的所有其他库中查找所有未定义的符号(即在 libdependencylib.solibc.so 以及其他系统库中)。只要在某处找到所有未定义的符号,链接器就可以了。然后在运行时,当 libmylib.so 被加载时,它再次执行相同的例程;所有未定义的符号都在当前进程加载的符号列表中查找。在 linux 上,您通常不需要像在 windows 上那样手动将符号标记为 dllexport - 默认情况下会导出所有非静态符号。

STATIC -> SHARED更改后应用启动失败可能有两种原因。

  1. 未安装预建库。连接您的设备后,运行 adb ls -l /data/your.package.name/lib/。你看到那里的图书馆了吗?

  2. 未加载预建库。在你的主 Java class 中,试试

    static { System.loadLibrary("prebuiltname"); System.loadLibrary("yourlib"); }

    这是一个静态构造函数,是加载JNI库最安全的地方。