如何通过CMake自动合并静态库及其依赖库?
解决CMake合并静态库时libtool将多个依赖库识别为单个文件的问题
修正后的CMake函数实现
function(get_dependencies TARGET) get_target_property(target_type ${TARGET} TYPE) if (NOT target_type STREQUAL "STATIC_LIBRARY") return() endif() # 避免重复添加已处理过的库 list(FIND TARGET_DEPENDENCIES ${TARGET} VISITED) if (NOT ${VISITED} EQUAL -1) return() endif() list(APPEND TARGET_DEPENDENCIES ${TARGET}) get_target_property(IMPORTED ${TARGET} IMPORTED) if (IMPORTED) get_target_property(LIBS ${TARGET} INTERFACE_LINK_LIBRARIES) else() get_target_property(LIBS ${TARGET} LINK_LIBRARIES) endif() # 递归处理依赖的目标 foreach(LIB ${LIBS}) if (TARGET ${LIB}) get_dependencies(${LIB}) endif() endforeach() set(TARGET_DEPENDENCIES ${TARGET_DEPENDENCIES} PARENT_SCOPE) endfunction() function(merge_libraries target destination) get_dependencies(${target}) # 将每个目标转换为对应的静态库文件路径 set(LIBRARY_PATHS "") foreach(DEP ${TARGET_DEPENDENCIES}) list(APPEND LIBRARY_PATHS "$<TARGET_FILE:${DEP}>") endforeach() add_custom_target(Merge${target}Libraries COMMAND libtool -static -o "${destination}" ${LIBRARY_PATHS} COMMAND_EXPAND_LISTS DEPENDS ${TARGET_DEPENDENCIES} COMMENT "Merging static libraries into ${destination}" ) endfunction()
关键修改说明
- 修复依赖去重逻辑:在
get_dependencies开头添加重复检查,避免同一库被多次添加到依赖列表。 - 取消错误的字符串拼接:移除
JOIN和GENEX_EVAL的使用,直接将库路径列表作为libtool的参数传递。CMake会自动将列表元素解析为独立的命令行参数,避免所有路径被当成单个文件名。 - 显式依赖所有目标:将
DEPENDS改为依赖所有收集到的静态库目标,确保合并操作在所有依赖库构建完成后执行。 - 添加构建状态提示:增加
COMMENT字段,方便查看合并操作的实时状态。
问题根源分析
你之前的代码用$<JOIN:${TARGET_DEPENDENCIES}, >将所有库路径拼接成单个字符串,经GENEX_EVAL展开后被当成一个完整参数传给libtool,导致工具误判为超长文件名。而CMake的COMMAND原生支持列表参数,每个列表元素会被解析为独立的命令行参数,这才是传递多个库路径的正确方式。
额外注意事项
- 跨平台适配:如果在Linux环境下执行,需将
libtool命令替换为ar rcs "${destination}" ${LIBRARY_PATHS}。 - 非目标依赖处理:若库依赖了非CMake目标的静态库(如系统库),需在
get_dependencies中添加逻辑直接将库路径加入列表。 - XCFramework打包:若后续要将合并后的静态库打包为XCFramework,可在合并完成后添加自定义命令生成对应结构。
内容的提问来源于stack exchange,提问作者Marco Giglio
相关产品推荐
相关产品推荐

