CMake中如何为Android安装共享STL库libc++_shared.so?
当我们在Android项目中用CMake构建,且CMAKE_ANDROID_STL_TYPE设为c++_shared时,必须把libc++_shared.so打包进APK。但CMake 3.27里的install(RUNTIME_DEPENDENCY_SET)没法用,官方明确说file(GET_RUNTIME_DEPENDENCIES)只支持Windows、Linux和macOS,所以这个命令对Android无效。如果你之前用Python脚本实现了找对应ABI的库文件,试试下面这几个纯CMake的优雅方案:
方案1:直接通过NDK路径定位
CMake在Android构建时会自动提供CMAKE_ANDROID_NDK(NDK根路径)和CMAKE_ANDROID_ARCH_ABI(当前编译的ABI,比如armeabi-v7a、arm64-v8a)这两个变量,直接拼接路径就能找到库:
if(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_shared") set(LIBCXX_SHARED_PATH "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}/libc++_shared.so") if(EXISTS "${LIBCXX_SHARED_PATH}") install( FILES "${LIBCXX_SHARED_PATH}" DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime ) else() message(FATAL_ERROR "没找到libc++_shared.so,路径:${LIBCXX_SHARED_PATH}") endif() endif()
这个方法最直接,不需要依赖其他配置,只要NDK路径正确就能找到文件,兼容性拉满。
方案2:从目标属性中获取
如果你的库/可执行目标已经配置了c++_shared作为STL,可以直接从目标属性里拿到库的路径:
# 示例:定义你的目标 add_library(MyAppLib SHARED src/my_lib.cpp) # 给目标指定STL类型 set_target_properties(MyAppLib PROPERTIES CMAKE_ANDROID_STL_TYPE "c++_shared") # 安装libc++_shared.so if(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_shared") get_target_property(LIBCXX_SHARED_PATH MyAppLib IMPORTED_LOCATION) if(LIBCXX_SHARED_PATH) install( FILES "${LIBCXX_SHARED_PATH}" DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime ) endif() endif()
这种方式更贴合CMake的目标管理逻辑,适合项目里已经明确给目标配置了STL的场景,不用手动拼路径。
方案3:用find_library标准命令查找
用CMake自带的find_library命令来定位libc++_shared.so,符合CMake的查找规范:
if(CMAKE_ANDROID_STL_TYPE STREQUAL "c++_shared") find_library(LIBCXX_SHARED NAMES c++_shared PATHS "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${CMAKE_ANDROID_ARCH_ABI}" NO_DEFAULT_PATH ) if(LIBCXX_SHARED) install( FILES "${LIBCXX_SHARED}" DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT Runtime ) else() message(FATAL_ERROR "找不到对应ABI ${CMAKE_ANDROID_ARCH_ABI}的libc++_shared.so") endif() endif()
find_library会自动处理路径查找,比手动拼接更严谨,也能避免一些路径拼写错误。
这三个方案都是纯CMake实现,不需要额外的Python脚本依赖,直接写在CMakeLists.txt里就能生效,比脚本方案更集成化,你可以根据自己项目的结构选合适的用。
内容的提问来源于stack exchange,提问作者jpr42

