【问题标题】:Confustion about Android NDK libc++ libc++_shared, libstdc++关于Android NDK libc++ libc++_shared、libstdc++的困惑
【发布时间】:2022-01-07 00:19:37
【问题描述】:

尝试使用 Android NDK 23 (23.1.7779620) 构建一个简单的 C++ 库时,我感到非常困惑。我正在使用 CMake,这是一个非常简单的程序:

# CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(mf) 
add_library(mf lib.cpp)

// lib.hpp
#pragma once
#include <string>
std::string foo(std::string);

// lib.cpp
#include "lib.hpp"
std::string foo(std::string str) {
  return std::string{"test"} + str;
}

这是要构建的命令行:

cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DANDROID_STL=c++_shared -DANDROID_ABI=arm64-v8a -DANDROID_PLATFORM=android-29  -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake .. 
cmake --build . -v
  • 第一个问题是我希望链接到libc++.so 而不是libc++_shared.so。它们之间有什么区别?我读了this article。但是仍然没有解释libc++libc++_shared之间的区别
  • 第二个问题更严重,看来我用的是libstdc++!
  • 第三点,我认为clang 的c++ 实现在命名空间std::__1 下,但我找不到类似的东西。

我知道 libc++_shared 是因为这个命令而被使用的:

$ readelf -d libmf.so

Dynamic section at offset 0x76e0 contains 26 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [libm.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc++_shared.so]
 0x0000000000000001 (NEEDED)             Shared library: [libdl.so]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so]
 0x000000000000000e (SONAME)             Library soname: [libmf.so]

运行 nm 似乎我正在使用来自 libstdc++ 的符号:

$ nm -gDC libmf.so | grep '__ndk1'
0000000000003af0 T foo(std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >)
                 U std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >::append(char const*, unsigned long)
$ nm -gDC libmf.so | grep '__1'
$

更新

在这篇文章中解释了libc++.solibc++_shared.so之间的区别

【问题讨论】:

  • (1) 不清楚您为什么认为libc++_shared.so 被使用。你有建议它的构建日志吗? (2) 不清楚你为什么认为你在使用libstdc++。此符号模式不是libstdc++ 的特征。 __1 也不一定存在于libc++ 的所有安装中。 1 in __1what _LIBCPP_ABI_VERSION 扩展为,但可以配置为扩展为任何内容。
  • 感谢您的反馈,我更新了我的问题
  • 这些绝对不是来自 libstdc++ 的符号。在 libstdc++ 中有一个名为 __cxx11 的 ABI 命名空间,但它 (1) 是硬编码的,并且 (2) 不适用于所有符号,尤其不适用于 allocatorchar_traits
  • 那么libc++.solibc++_shared.so有什么区别,为什么Android ndk不允许“轻松”“只”使用libc++.so
  • 这个我不知道。

标签: c++ android-ndk libc++


【解决方案1】:

通过将 -DANDROID_STL=c++_shared 传递给 CMake 调用,您明确要求共享运行时而不是默认运行时。

正如the documentation 中所述,规则很简单:

  1. 如果全部您的本机代码位于单个库中,请使用静态 libc++(默认),这样可以删除未使用的代码,并且您拥有尽可能小的应用程序包。
  2. 一旦您包含了一个额外的库 - 无论是因为您包含了来自其他地方的预编译库,还是包含了恰好包含本机代码的 Android AAR 文件 - 您必须切换到共享运行时.

规则的基本原理很简单:C++ 运行时具有某些全局数据结构,必须初始化一次,并且必须在内存中只存在一次。如果您不小心加载了两个静态链接 C++ 运行时的库,那么您(例如)有两个冲突的内存分配器。 当您 freedelete 由其他库分配内存时,或者如果您跨库边界传递像 std::string 这样的 C++ STL 对象时,这将导致崩溃。

为了完整起见,在较旧的 NDK 中,libstdc++(GNU C++ 运行时)也包含在 NDK 中,但从 NDK r18 开始不再是这种情况。

【讨论】:

  • 我仍然很困惑,因为在我的板上,库链接到 libc++.so,但是当我使用 ndk 时,我链接到 libc++_shared.so。这个库不在目标中,我也需要部署它......我不能只链接到libc++.so吗?有办法吗?
  • 链接页面上的第二条注释非常明确:“注意:libc++不是系统库。如果你使用libc++_shared.so,它必须包含在你的应用程序中。如果你'使用 Gradle 重新构建您的应用程序,这是自动处理的。”换句话说:不管你的板上有什么,APK都会打包自己的libc++_shared.so
  • “一旦你包含了一个额外的库——无论是因为你从其他地方包含了一个预编译的库,或者你包含了一个恰好包含本机代码的 Android AAR 文件——你必须切换到共享运行时”。不必要。见stackoverflow.com/a/52389560/1524450
  • 好话。我认为 Android 文档和我都偏向于谨慎的简单建议。
猜你喜欢
  • 2022-01-14
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
  • 2012-02-18
相关资源
最近更新 更多