Android NDK:如何链接多个第三方库 [英] Android NDK: how to link multiple 3rd party libraries

查看:355
本文介绍了Android NDK:如何链接多个第三方库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's say we're building a shared library A that needs to link to 2 external static libs B and C. All you've got are libB.a and libC.a, along with their header files.

这是libA的简化版Android.mk:

Here's a simplified Android.mk for libA:

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

include $(BUILD_SHARED_LIBRARY)

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

AFAIK, the way linking works for shared libraries is:

  1. 抓取B和C的所有目标文件
  2. 去除A没有引用的目标文件
  3. 解析B和C中的引用

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

This gives link errors because B and C call each other, specifically they call functions that got stripped out in step 2 because A didn't call them.

如果我们自己构建静态库,则只需将LOCAL_STATIC_LIBRARIES替换为LOCAL_WHOLE_STATIC_LIBRARIES,就可以防止代码剥离(以代码大小为代价).在后台,它将--whole-archive传递给链接器.

If we built the static libs ourselves, then it's simply a matter of replacing LOCAL_STATIC_LIBRARIES with LOCAL_WHOLE_STATIC_LIBRARIES, which prevents code stripping (at the expense of code size). Under the hood, it passes --whole-archive to the linker.

由于我们没有构建B和C(甚至都没有重建它们的源代码),所以有什么选择?

Since we didn't build B and C (and don't even have the source to rebuild them), what are the options?

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

我选择了选项1,因为它是第一个有效的方法,但显然效果不佳.我在问是否有更好的解决方案.

I've gone with option 1 because it's the first thing that worked, but obviously it's not great. I'm asking whether there's a better solution.

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

The answer to this question ( Linking issue when prebuilt static and shared libraries with the Android NDK ) made me wonder if I need to re-evaluate my build setup (shared library linking to external static library). I'm unable to comment there, so I asked my own question here.

推荐答案

答案可以在

The answer can be found in How to deal with recursive dependencies between static libraries using the binutils linker?.

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

我采用了两库NDK示例,并做了最小的改动以演示该技术

I took the two-libs NDK sample, and made minimal change to demonstrate the technique on GitHub.

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

Update (2017): since 2012, the rules of NDK became more strict, and now it will complain that LOCAL_LDLIBS contains non-system libraries:

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

Android NDK: WARNING:Android.module: non-system libraries in linker flags: -la -lb
Android NDK: This is likely to result in incorrect builds. Try using LOCAL_STATIC_LIBRARIES
Android NDK: or LOCAL_SHARED_LIBRARIES instead to list the library dependencies of the
Android NDK: current module

这只是一个警告,因此您可以忽略它.

This is just a warning, so you can ignore it.

或在-l之后添加空格以使NDK保护更精明:

Or add space after -l to outsmart the NDK protection:

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集成时,这可能特别棘手).使用

If the libraries that are involved are not prebuilt, you don't need to guess their location (which may be especially tricky when using Android Studio NDK integration). Use

LOCAL_LDLIBS := -L $(TARGET_OUT) …

存在另一种方法,该方法不使用递归"链接.但是它涉及迭代.首先,尝试以通常的方式构建共享库.如果无法解析的符号失败,请将所有这些符号复制到剪贴板,然后将其粘贴到您的 Android.mk .假设这些符号是extBaextBbextBc(在上述情况下为,我相信 libC 的某些对象找不到在 libB ,这就是链接失败的原因).现在需要什么,添加

There exists an alternative approach, which does not use 'recursive' linking. But it involves iterations. First, try to build your shared library the usual way. When this fails with unresolved symbols, copy all these symbols to clipboard, and paste them your Android.mk. Let's say these symbols are extBa, extBb, and extBc (in the above scenario, I believe that some object of libC does not find these symbols that are defined somewhere in libB, that's why the link fails). What you need now, add

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

您可以进行下一步,并将其与 libC 捆绑在一起:

You can make the next step, and have this all bundled with libC:

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

现在,任何使用 libC 的共享库都不会丢失这些符号.

Now any shared lib that uses libC will not miss these symbols.

这篇关于Android NDK:如何链接多个第三方库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆