You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android NDK 23编译C++库时libc++、libc++_shared与libstdc++相关疑问

Android NDK 23 C++库构建相关问题解答

基础配置与复现流程

工程代码

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

验证结果

readelf动态依赖输出

$ 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 -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++.so实际依赖libc++_shared.so,二者有什么区别?
    答:首先你构建时指定了-DANDROID_STL=c++_shared,产物链接libc++_shared.so是符合预期的。二者的核心差异是:Android NDK的命名规则和桌面端LLVM不同,系统分区内置的、专供系统框架使用的LLVM libc动态库命名为libc++.so,NDK不会开放给第三方APP链接使用;NDK提供给开发者的动态版LLVM libc命名为libc++_shared.so,对应的静态版本为libc++.a,这套命名规则是为了避免APP打包运行时和系统自带的libc++.so产生混淆和加载冲突。
  • 问:是不是实际使用了libstdc++?
    答:没有使用libstdc++。首先你的动态依赖列表里没有任何libstdc相关的库,其次libstdc的标准库符号不会带有__ndk1前缀,你看到的符号特征完全符合NDK版libc++的特征。
  • 问:为什么找不到std::__1前缀的符号?
    答:NDK从r18版本开始对自带的LLVM libc做了定制修改,将上游LLVM默认的内联命名空间__1改成了__ndk1,目的是避免NDK编译的产物和其他自带LLVM libc的第三方库产生符号冲突,你在产物中看到std::__ndk1前缀属于正常现象,符合NDK的设计预期。

内容的提问来源于stack exchange,提问作者Elvis Dukaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 00:36:09