【问题标题】:Is AOSP's libc++.so the same as NDK's libc++_shared.so?AOSP 的 libc++.so 和 NDK 的 libc++_shared.so 一样吗?
【发布时间】:2017-11-12 00:43:19
【问题描述】:

我正在使用一个 Android 应用程序,其中一个共享库(我在 Android Studio 中构建,我们称之为 libA.so)动态加载供应商提供的另一个共享库提供程序(我们称之为 libB.so)。我知道我不应该在我的应用程序中使用多个 C++ 运行时库 (https://developer.android.com/ndk/guides/cpp-support.html#important_considerations),因此我们决定在两个库中都使用 c++_shared。

libB.so(供应商提供的那个)是在AOSP构建的时候编译链接的(供应商坚持用这种方式建库,无能为力)。 libB.so 的 makefile 将 STL 标志设置为 c++_shared:

LOCAL_NDK_STL_VARIANT := c++_shared

当我查看libB.so 库中的NEEDED 标记时,我可以看到对libc++.so 的依赖关系

 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc++.so] <----
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]
 0x000000000000000e (SONAME)             Library soname: [libB.so]

当我运行readelf -d libc++.so 来检查 AOSP 的 libc++ 的内容时,我得到了这个

Dynamic section at offset 0xe4b40 contains 29 entries:
  Tag        Type                         Name/Value
 0x0000000000000003 (PLTGOT)             0xe6310
 0x0000000000000002 (PLTRELSZ)           22128 (bytes)
 0x0000000000000017 (JMPREL)             0x39ff8
 0x0000000000000014 (PLTREL)             RELA
 0x0000000000000007 (RELA)               0x2ce58
 0x0000000000000008 (RELASZ)             53664 (bytes)
 0x0000000000000009 (RELAENT)            24 (bytes)
 0x000000006ffffff9 (RELACOUNT)          380
 0x0000000000000006 (SYMTAB)             0x238
 0x000000000000000b (SYMENT)             24 (bytes)
 0x0000000000000005 (STRTAB)             0xdeb8
 0x000000000000000a (STRSZ)              102917 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x270c0
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]
 0x000000000000000e (SONAME)             Library soname: [libc++.so]
 0x000000000000001a (FINI_ARRAY)         0xe08e0
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x0000000000000019 (INIT_ARRAY)         0xe5b38
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001e (FLAGS)              BIND_NOW
 0x000000006ffffffb (FLAGS_1)            Flags: NOW
 0x000000006ffffff0 (VERSYM)             0x2bb7c
 0x000000006ffffffc (VERDEF)             0x2cddc
 0x000000006ffffffd (VERDEFNUM)          1
 0x000000006ffffffe (VERNEED)            0x2cdf8
 0x000000006fffffff (VERNEEDNUM)         2
 0x0000000000000000 (NULL)               0x0

我知道 NDK 也提供了libc++.so,但是当我在 Android NDK 中分发的库中运行相同的命令时,我得到一个错误

readelf: Error: libc++.so: Failed to read file header

如果我没记错的话,那是因为在 NDK 中,libc++.so 实际上是一个链接器脚本。

libA.so(我使用我的应用构建并加载 libB.so)最终依赖于 libc++_shared.so

Dynamic section at offset 0x4bca50 contains 28 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [liblog.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc++_shared.so] <---
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x000000000000000e (SONAME)             Library soname: [libA.so]

我认为我不能(或不应该)在我的应用中同时捆绑 libc++.solibc++_shared.so

那么,AOSP 的 libc++.so 与 NDK 的 libc++_shared.so 相同吗?

有人知道为什么即使使用了LOCAL_NDK_STL_VARIANT := c++_shared,AOSP 也会向libc++.so 添加动态依赖而不是libc++_shared.so?我应该要求我的提供商链接到libc++_shared.so 吗?也许有人有更好的建议来解决这种依赖不匹配。

【问题讨论】:

  • “有人知道为什么 AOSP 会在使用 LOCAL_NDK_STL_VARIANT := c++_shared 的情况下添加动态依赖项到 libc++.so 而不是 libc++_shared.so 吗?”如果未设置 LOCAL_SDK_VERSION,则忽略 LOCAL_NDK_STL_VARIANT。

标签: android android-ndk android-source


【解决方案1】:

不,它们不相等。 AOSP 中的 libc++.so 是针对最新的(技术上是 future API 级别)API 级别构建的,并且没有 libandroid_support。它是用一组不同的标志构建的,并且可能是不同的 ABI。它使用一组架构标志构建,允许编译器使用并非在所有 Android 设备上都可用的指令。这也是与 NDK 中的版本不同的版本,但对于不同的 NDK 版本也是如此,并且在决定它们是否兼容方面不太重要。

如果供应商向您提供 libB.so 以将其包含在您的应用程序中,那么他们构建的程序不正确。正如您所注意到的,它与平台 libc++.so 链接,应用程序无法访问该平台。您这边没有解决办法;供应商需要提供适当的 NDK 库。如果他们想继续使用 AOSP 构建系统,他们需要设置LOCAL_SDK_VERSION,这样LOCAL_NDK_STL_VARIANT 就不会被忽略。

如果供应商提供的设备安装了此库到系统映像(即/system/lib64/libB.so,包含在您的应用程序中),那么@alex-中的指导科恩的回答适用。这就是像 libandroid.so 这样的官方 NDK 库的构建方式。它们链接到系统的 libc++.so,但只向应用程序公开 C ABI。只要供应商遵循这些准则,就可以了。

正如亚历克斯所提到的,您引用的文件比实际情况要严格一些。 可以在同一个程序中使用多个 STL(否则 NDK 应用程序根本无法工作,因为平台和应用程序使用不同的 STL),但它确实需要对表面进行非常仔细的管理您的 ABI 区域,并非常小心以避免违反 ODR。

【讨论】:

    【解决方案2】:

    首先,可以在一个应用中混合不同的 C++ 运行时,只要它们不交互。这意味着,C++ 对象(包括异常)不应跨越其共享库的边界。因此,如果您的 libB.so 提供 extern "C" 公共 API,您可以安全地使用为 any C++ 运行时编译的组件中的这些函数,甚至 stlport_static

    如果供应商库不导出纯 C API,则违反了体系结构规定(参见https://source.android.com/devices/architecture/images/vndk_design_android_o.pdf,第 27 页)。在这种情况下,您可能还需要构建您的依赖 libA.so 作为 AOSP 的一部分。如果您选择将库更紧密地耦合到 libB.so,则可以这样做,例如扩展它的一些类,跨 libA/libB 边界抛出异常等。

    请注意,自 Android N 起,系统链接器 protects 平台库(位于 /system/lib 和 /vendor/lib 中的)不会从用户代码中dlopen。您应该考虑将 libBlibA 或两者都添加到 whitelist

    【讨论】:

    • This 来自 Android NDK 文档的链接说,具有 2 个(或更多)与静态运行时库链接的共享库的应用程序的运行时行为“未定义,实际上会崩溃非常常见”,但您提到可以使用任何 C++ 运行时,只要 C++ 对象不跨越边界,或者如果库提供外部“C”API。 libB.so 确实提供了一个 extern "C" API,所以供应商可以安全地将他的库链接到像 gnustl_static 的静态 C++ 库(我也是)?
    • 是的,如果他们愿意,任何一方都可以使用任何静态 STL。对于供应商库,使用 system/lib 中的共享 STL 会更自然,因为这样可以节省空间。
    • 更正:我似乎误导了你。我想说可以使用任何 C++ 运行时,只要 C++ 对象不跨越边界并且库提供外部“C”API。。跨度>
    猜你喜欢
    • 1970-01-01
    • 2020-12-06
    • 2022-01-07
    • 2021-07-16
    • 1970-01-01
    • 1970-01-01
    • 2020-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多