Android NDK:如何链接多个第三方库

foo*_*o64 4 android static-libraries android-ndk

假设我们正在构建一个共享库A,它需要链接到2个外部静态库B和C.你所拥有的只是libB.a和libC.a,以及它们的头文件.

这是libA的简化Android.mk:

LOCAL_LDLIBS := ../external/libB.a ../external/libC.a

include $(BUILD_SHARED_LIBRARY)
Run Code Online (Sandbox Code Playgroud)

AFAIK,链接共享库的工作方式是:

  1. 获取B和C的所有目标文件
  2. 去掉A没有引用的目标文件
  3. 解决B和C中的引用

这会产生链接错误,因为B和C互相调用,特别是它们调用在步骤2中被删除的函数,因为A没有调用它们.

如果我们自己构建静态库,那么只需用LOCAL_WHOLE_STATIC_LIBRARIES替换LOCAL_STATIC_LIBRARIES就可以防止代码剥离(代码大小).在引擎盖下,它将--whole-archive传递给链接器.

由于我们没有构建B和C(甚至没有重建它们的源),有哪些选择?

  1. 从A手动引用缺失的函数,以便它们不会被剥离
  2. 弄清楚如何将--whole-archive传递给外部静态库的链接器
  3. 使用PREBUILT_STATIC_LIBRARY(看到它提到,但从未使用它,根据文档,它听起来不适用于这种情况)
  4. 构建可执行文件而不是共享库(不会以相同的方式剥离代码)
  5. 移动/重命名外部库以欺骗NDK构建系统认为它们是我的,以便我可以将它们添加到LOCAL_WHOLE_STATIC_LIBRARIES.

我已经选择了1,因为它是第一个有用的东西,但显然它不是很好.我在问是否有更好的解决方案.

这个问题的答案(当使用Android NDK预构建静态和共享库时链接问题)让我想知道是否需要重新评估我的构建设置(链接到外部静态库的共享库).我无法在那里发表评论,所以我在这里问自己的问题.

Ale*_*ohn 6

答案可以在如何使用binutils链接器处理静态库之间的递归依赖关系中找到答案.

LOCAL_LDLIBS := -L ../external/ -lB -lC -lB
Run Code Online (Sandbox Code Playgroud)

我采用了两个库的NDK样本,并进行了微小的改动以在GitHub上演示该技术.

更新(2017年):自2012年以来,NDK的规则变得更加严格,现在它会抱怨LOCAL_LDLIBS包含非系统库:

Android NDK:警告:Android.module:链接器标志中的非系统库:-la -lb
Android NDK:这可能导致不正确的构建.尝试使用LOCAL_STATIC_LIBRARIES
Android NDK:或LOCAL_SHARED_LIBRARIES来列出
Android NDK 的库依赖项:当前模块

这只是一个警告,所以你可以忽略它.

或者在-l智能NDK保护后增加空间:

LOCAL_LDLIBS := -L ../external/ -l B -l C -l B
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用

LOCAL_LDLIBS += -L ../external -Wl,--start-group -l B -l C -Wl,--end-group
Run Code Online (Sandbox Code Playgroud)

如果涉及的库不是预构建的,则无需猜测它们的位置(使用Android Studio NDK集成时可能特别棘手).使用

LOCAL_LDLIBS := -L $(TARGET_OUT) …
Run Code Online (Sandbox Code Playgroud)

存在一种替代方法,其不使用"递归"链接.但它涉及迭代.首先,尝试以通常的方式构建共享库.如果此操作因未解析的符号而失败,请将所有这些符号复制到剪贴板,然后将其粘贴到Android.mk中.假设这些符号是extBa,, extBbextBc(在上面的场景中,我相信libC的某个对象没有找到在libB中定义的这些符号,这就是链接失败的原因).你现在需要什么,补充一下

LOCAL_LDFLAGS += -Wl,-u'extBa' -Wl,-u'extBb' -Wl,-u'extBc'
Run Code Online (Sandbox Code Playgroud)

您可以进行下一步,并将所有内容与libC捆绑在一起:

LOCAL_EXPORT_LDFLAGS += -Wl,-u'extBa' -Wl,-u'extBb' -Wl,-u'extBc'
Run Code Online (Sandbox Code Playgroud)

现在任何使用libC的共享库都不会错过这些符号.