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

时间:2012-11-30 00:53:31

标签: android android-ndk static-libraries

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

以下是libA的简化Android.mk:

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

include $(BUILD_SHARED_LIBRARY)

AFAIK,链接适用于共享库的方式是:

  1. 获取B和C的所有目标文件
  2. 删除A未引用的对象文件
  3. 解决B和C中的引用
  4. 这会产生链接错误,因为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。
    6. 我选择了1,因为它是第一个有用的东西,但显然它并不好。我在问是否有更好的解决方案。

      这个问题的答案(Linking issue when prebuilt static and shared libraries with the Android NDK)让我想知道是否需要重新评估我的构建设置(链接到外部静态库的共享库)。我无法在那里发表评论,所以我在这里问自己的问题。

1 个答案:

答案 0 :(得分:6)

答案可以在 How to deal with recursive dependencies between static libraries using the binutils linker? 中找到。

LOCAL_LDLIBS := -L ../external/ -lB -lC -lB

我使用了两个库的NDK样本,并进行了微小的更改以演示技术on 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

或者,您可以使用

LOCAL_LDLIBS += -L ../external -Wl,--start-group -l B -l C -Wl,--end-group

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

LOCAL_LDLIBS := -L $(TARGET_OUT) …

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

LOCAL_LDFLAGS += -Wl,-u'extBa' -Wl,-u'extBb' -Wl,-u'extBc'

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

LOCAL_EXPORT_LDFLAGS += -Wl,-u'extBa' -Wl,-u'extBb' -Wl,-u'extBc'

现在任何使用 libC 的共享库都不会遗漏这些符号。