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

CMake跨相邻项目依赖:避免重复构建与冗余编译

解决CMake多项目依赖重复构建与冗余编译问题

问题描述

现有两个相邻仓库分别包含projectA和projectB:

  • projectA通过CMake构建3个静态库(lib1、lib2、lib3),单独构建时会在build目录生成各自的*.a文件
  • projectB通过CMake构建可执行文件,仅依赖projectA的lib1和lib3

当前采用add_subdirectory(${CMAKE_SOURCE_DIR}/../projectA projectA)引入依赖,再用target_link_libraries(${PROJECT_NAME} lib1 lib3)链接,但存在两个问题:

  1. 新增projectC时会重复构建projectA的库
  2. 构建projectB/C时会编译projectA中未被使用的lib2

需求:让projectA的库仅在自身目录构建,同时projectB/C可按需构建所需的库(仅构建未完成或源码变更的目标)

解决方案

1. 让projectA支持单独构建并生成可复用的安装包

在projectA的CMakeLists.txt中添加安装规则,将库文件、头文件和CMake配置模块统一安装到指定目录(比如项目内的install子目录):

# projectA/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(projectA)

# 构建lib1
add_library(lib1 STATIC src/lib1.cpp)
target_include_directories(lib1 PUBLIC include)

# 构建lib2
add_library(lib2 STATIC src/lib2.cpp)
target_include_directories(lib2 PUBLIC include)

# 构建lib3
add_library(lib3 STATIC src/lib3.cpp)
target_include_directories(lib3 PUBLIC include)

# 配置安装路径与规则
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/install)
# 安装库文件到lib目录
install(TARGETS lib1 lib2 lib3
        ARCHIVE DESTINATION lib)
# 安装头文件到include目录
install(DIRECTORY include/ DESTINATION include)
# 导出CMake目标配置,供其他项目查找
install(EXPORT projectATargets
        FILE projectATargets.cmake
        DESTINATION lib/cmake/projectA)

# 生成Config.cmake文件,让其他项目能通过find_package识别projectA
include(CMakePackageConfigHelpers)
configure_package_config_file(
    ${PROJECT_SOURCE_DIR}/Config.cmake.in
    ${PROJECT_BINARY_DIR}/projectAConfig.cmake
    INSTALL_DESTINATION lib/cmake/projectA
)
install(FILES ${PROJECT_BINARY_DIR}/projectAConfig.cmake
        DESTINATION lib/cmake/projectA)

同时在projectA根目录创建Config.cmake.in文件(内容为空即可,后续可按需添加配置逻辑)。

完成配置后,在projectA目录下单独构建并安装:

mkdir build && cd build
cmake ..
make
make install

2. 在projectB/C中通过find_package按需引入依赖

在projectB的CMakeLists.txt中,通过find_package定位projectA的安装包,仅链接自身需要的库:

# projectB/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(projectB)

# 指定projectA的CMake配置文件路径
set(projectA_DIR ${CMAKE_SOURCE_DIR}/../projectA/install/lib/cmake/projectA)
# 查找并导入projectA的配置
find_package(projectA REQUIRED)

# 构建可执行文件
add_executable(projectB src/main.cpp)
# 仅链接需要的lib1和lib3
target_link_libraries(projectB PRIVATE lib1 lib3)

projectC的配置逻辑与projectB一致,只需修改项目名称和需要链接的库即可。

3. 可选:用ExternalProject实现自动按需构建依赖

如果不想手动提前构建projectA,可以借助ExternalProject让projectB/C在需要时自动触发projectA的指定库构建,同时复用已有产物:

# projectB/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(projectB)

include(ExternalProject)
ExternalProject_Add(
    projectA
    SOURCE_DIR ${CMAKE_SOURCE_DIR}/../projectA
    BINARY_DIR ${CMAKE_SOURCE_DIR}/../projectA/build
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_SOURCE_DIR}/../projectA/install
    INSTALL_COMMAND make install
    BUILD_COMMAND make lib1 lib3  # 仅构建当前需要的库
)

# 导入projectA的库配置
set(projectA_DIR ${CMAKE_SOURCE_DIR}/../projectA/install/lib/cmake/projectA)
find_package(projectA REQUIRED)

add_executable(projectB src/main.cpp)
target_link_libraries(projectB PRIVATE lib1 lib3)
# 让projectB的构建依赖projectA的指定目标
add_dependencies(projectB projectA)

这样构建projectB时,只会编译projectA的lib1和lib3,且projectA的构建产物会被所有依赖项目复用,新增projectC时不会重复构建已完成的库。

关键原理

  • 通过install和find_package实现依赖的全局共享,避免每个项目重复构建projectA
  • 利用CMake的目标依赖机制,仅触发当前项目需要的库构建,跳过未使用的lib2
  • ExternalProject可自动触发依赖构建,同时支持指定构建目标,减少冗余编译

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 10:00:03