如何递归获取CMake依赖目标属性以收集Android APK所需共享库
解决方案
核心思路是实现一个递归收集所有依赖目标的自定义CMake函数,遍历所有依赖提取ANDROID_NATIVE_LIB_DEPENDENCIES属性后合并到顶层目标的属性中,无需使用全局属性即可适配多顶层目标场景。
首先定义通用的递归依赖收集函数,可放在顶层CMakeLists的公共配置段:
# 递归获取目标的所有链接依赖(含间接依赖) function(get_all_dependencies TARGET OUTPUT_VAR) # 防止重复处理同一个目标,规避循环依赖导致的死循环 set(VISITED_TARGETS "" CACHE INTERNAL "Visited targets for dependency collection" FORCE) function(_collect_deps CURRENT_TARGET) if(NOT TARGET ${CURRENT_TARGET} OR ${CURRENT_TARGET} IN_LIST VISITED_TARGETS) return() endif() list(APPEND VISITED_TARGETS ${CURRENT_TARGET}) set(VISITED_TARGETS ${VISITED_TARGETS} CACHE INTERNAL "Visited targets for dependency collection" FORCE) # 获取当前目标的直接链接依赖 get_target_property(DIRECT_DEPS ${CURRENT_TARGET} LINK_LIBRARIES) foreach(DEP ${DIRECT_DEPS}) # 过滤非目标类的链接项(比如-lpthread这类系统库、生成器表达式等) if(TARGET ${DEP}) _collect_deps(${DEP}) endif() endforeach() endfunction() _collect_deps(${TARGET}) # 移除目标自身,仅返回依赖列表 list(REMOVE_ITEM VISITED_TARGETS ${TARGET}) set(${OUTPUT_VAR} ${VISITED_TARGETS} PARENT_SCOPE) endfunction()
在顶层应用目标的CMake配置段调用该函数即可完成属性合并:
if(ANDROID) # 1. 递归获取MyApp的所有依赖目标(示例中的Lib1、Lib2、Lib3都会被收集) get_all_dependencies(MyApp ALL_DEPS) # 2. 遍历所有依赖,收集ANDROID_NATIVE_LIB_DEPENDENCIES属性值 set(ALL_NATIVE_LIBS "") foreach(DEP ${ALL_DEPS}) get_target_property(DEP_LIBS ${DEP} ANDROID_NATIVE_LIB_DEPENDENCIES) if(DEP_LIBS) list(APPEND ALL_NATIVE_LIBS ${DEP_LIBS}) endif() endforeach() # 3. 去重后赋值给顶层目标的原生依赖属性 if(ALL_NATIVE_LIBS) list(REMOVE_DUPLICATES ALL_NATIVE_LIBS) set_target_properties(MyApp PROPERTIES ANDROID_NATIVE_LIB_DEPENDENCIES "${ALL_NATIVE_LIBS}") endif() endif()
该方案优势:
- 完美适配多顶层目标场景,每个顶层目标单独调用一次函数即可,不同目标的依赖不会互相混淆
- 无需修改子依赖库的CMake配置,子依赖仍正常使用原生
ANDROID_NATIVE_LIB_DEPENDENCIES属性即可,侵入性极低 - 自动处理任意层级的嵌套依赖,你示例中的Lib3的属性会被正常识别收集
内容的提问来源于stack exchange,提问作者rdowell
相关产品推荐
相关产品推荐

