CMake拆分静态库后target_link_libraries重复链接库的问题及解决
问题解答
一、重复链接公共库是否会引发问题?
这种重复配置不会带来实质性的构建负担或运行时问题,具体原因如下:
- 对于Eigen这类头文件-only库:本身没有编译产物,仅提供头文件。重复引用只会让CMake多次处理路径,但编译时头文件自带保护宏,不会重复编译代码,也不会增加编译耗时。
- 对于yaml-cpp、pinocchio这类预编译库:CMake在处理链接时会自动去重,不会将这些库的目标文件多次打包进最终产物;且这类库的构建是独立的,只会在首次构建时编译一次,后续均复用已生成的二进制文件,不会因多目标引用重复编译。
- 静态库的特性:静态库只是目标文件的归档集合,将公共库链接到A、B、C时,仅记录依赖关系,不会把公共库代码复制到A、B、C中,只有最终链接可执行文件时才会合并所需代码,因此不会导致静态库体积膨胀。
不过你的代码里存在冗余的全局include_directories设置,这类全局配置会作用于所有目标,虽不影响功能,但不如target_include_directories的PUBLIC/PRIVATE/INTERFACE语义清晰,易造成不必要的路径暴露。
二、优化方案:消除重复配置
方案1:用INTERFACE库封装公共依赖
创建INTERFACE库集中管理公共依赖、编译选项与include路径,再让A、B、C链接该库,彻底消除重复代码:
# 封装公共依赖的INTERFACE库 add_library(CommonDependencies INTERFACE) # 公共编译选项 target_compile_options(CommonDependencies INTERFACE -Wall) # 公共include路径 target_include_directories(CommonDependencies INTERFACE ${CMAKE_SOURCE_DIR}/include ${EIGEN3_INCLUDE_DIRS} ${pinocchio_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../thirdParty/ ${YAML_INCLUDE_DIRS} ) # 公共链接库 target_link_libraries(CommonDependencies INTERFACE Eigen3::Eigen ${pinocchio_LIBRARIES} ${YAML_CPP_LIBRARIES} ) # 配置各目标 target_link_libraries(A PUBLIC CommonDependencies qpSWIFT) target_include_directories(A PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) # A的专属include路径 target_link_libraries(B PUBLIC CommonDependencies) target_link_libraries(C PUBLIC CommonDependencies)
方案2:用CMake函数批量配置目标
如果有多个同类型静态库,可自定义函数批量设置属性:
function(configure_my_library TARGET_NAME ADDITIONAL_LIBS) target_compile_options(${TARGET_NAME} PUBLIC -Wall) target_include_directories(${TARGET_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/include ${EIGEN3_INCLUDE_DIRS} ${pinocchio_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../thirdParty/ ${YAML_INCLUDE_DIRS} ) target_link_libraries(${TARGET_NAME} PUBLIC Eigen3::Eigen ${pinocchio_LIBRARIES} ${YAML_CPP_LIBRARIES} ${ADDITIONAL_LIBS} ) endfunction() # 调用函数配置各库 configure_my_library(A qpSWIFT) target_include_directories(A PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) # A的专属include路径 configure_my_library(B "") configure_my_library(C "")
方案3:利用依赖传递简化配置
如果A、B、C之间存在依赖关系(比如B依赖A),可让依赖链自动传递公共库:只需给A配置公共依赖,B通过链接A即可继承A的PUBLIC依赖,无需重复配置。此方案需结合项目实际结构判断是否适用。
额外建议:尽量替换file(GLOB_RECURSE),GLOB在新增文件时可能无法自动触发CMake重新配置,最好手动列出源文件;若必须使用GLOB,需确保CONFIGURE_DEPENDS在所用CMake版本中正常生效。
内容的提问来源于stack exchange,提问作者Junie
相关产品推荐
相关产品推荐

