You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

CMake优化:如何避免每次构建项目时重新构建所有依赖项

解决每次构建主项目时触发所有ExternalProject依赖检查的问题

从你的描述和构建输出来看,问题核心在于ExternalProject的默认行为以及项目依赖关系的设置——每次构建主项目时,CMake都会强制触发ExternalProject的更新、配置等冗余步骤,哪怕这些依赖已经完全是最新状态。下面是几个针对性的优化方案,一步步帮你解决这个问题:

1. 给ExternalProject添加UPDATE_DISCONNECTED ON参数

这个参数会告诉CMake:除非你手动触发更新(比如删除依赖的构建目录),否则不会去检查Git仓库的更新,直接跳过耗时的update步骤。这能省去每次构建时拉取仓库、校验HEAD的时间。

修改你的GLFW和GLAD的ExternalProject_Add配置:

# SETUP GLFW
set(libGLFW glfw)
ExternalProject_Add(${libGLFW}
    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}
    GIT_REPOSITORY https://github.com/glfw/glfw.git
    GIT_TAG 3.3.4
    GIT_SHALLOW ON
    UPDATE_DISCONNECTED ON  # 新增这一行
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}/install
               -DGLFW_BUILD_DOCS:BOOL=OFF
               -DGLFW_BUILD_EXAMPLES:BOOL=OFF
               -DGLFW_BUILD_TESTS:BOOL=OFF
)

# SETUP GLAD
set(libGLAD glad)
ExternalProject_Add(${libGLAD}
    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}
    GIT_REPOSITORY https://github.com/Dav1dde/glad.git
    GIT_TAG origin/master
    GIT_SHALLOW ON
    UPDATE_DISCONNECTED ON  # 新增这一行
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}/install
               -DGLAD_INSTALL:BOOL=ON
               -DGLAD_PROFILE:STRING="core"
               -DGLAD_ALL_EXTENSIONS:BOOL=ON
               -DUSE_MSVC_RUNTIME_LIBRARY_DLL:BOOL=OFF
)

2. 调整依赖关系:让导入库依赖ExternalProject,而非主项目直接依赖

你当前用add_dependencies(${PROJECT_NAME} ${libGLFW} ${libGLAD})让主项目直接绑定ExternalProject目标,这会导致每次构建主项目时都要先跑一遍ExternalProject的全流程。正确的做法是让导入的静态库目标(GLFW_LIBRARYGLAD_LIBRARY)依赖ExternalProject目标,这样只有当导入库的文件不存在时,才会触发依赖的构建。

修改这部分代码:

# 删除原来的 add_dependencies(${PROJECT_NAME} ${libGLFW} ${libGLAD})

# 改为让导入库依赖ExternalProject目标
add_dependencies(GLFW_LIBRARY ${libGLFW})
add_dependencies(GLAD_LIBRARY ${libGLAD})

这样主项目只依赖GLFW_LIBRARYGLAD_LIBRARY这两个导入库,而导入库只会在自身的导入文件缺失时,才会触发对应的ExternalProject构建,不会每次主项目构建都跑一遍依赖的冗余流程。

3. 优化ZERO_CHECK项目(可选,进一步提升体验)

Visual Studio中的ZERO_CHECK项目是CMake用来检查CMakeLists.txt是否有变化的,默认每次构建都会运行它。如果你不想每次构建都检查CMake配置,可以在生成VS项目时添加参数:

cmake .. -DCMAKE_SUPPRESS_REGENERATION=ON

这样只有当你手动修改了CMakeLists.txt后,才会触发重新生成配置,否则ZERO_CHECK会直接跳过。

修改后的完整CMakeLists.txt

把上面的修改整合后,你的CMakeLists.txt会变成这样:

cmake_minimum_required(VERSION 3.20.0)
# Define our project name
set(PROJECT_NAME test)
project(${PROJECT_NAME})

if(MSVC)
    get_filename_component(_vs_bin_path "${CMAKE_LINKER}" DIRECTORY)
    set(libexe "${_vs_bin_path}/lib.exe")
    message("LOOKHERE3:${libexe}")
endif()

# Make sure binary directory is not the same as source directory
if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
    message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there.")
endif()

# This Project Depends on External Project(s)
include(ExternalProject)

# SETUP GLFW
set(libGLFW glfw)
ExternalProject_Add(${libGLFW}
    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}
    GIT_REPOSITORY https://github.com/glfw/glfw.git
    GIT_TAG 3.3.4
    GIT_SHALLOW ON
    UPDATE_DISCONNECTED ON
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}/install
               -DGLFW_BUILD_DOCS:BOOL=OFF
               -DGLFW_BUILD_EXAMPLES:BOOL=OFF
               -DGLFW_BUILD_TESTS:BOOL=OFF
)
set(GLFW_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLFW}/install)
add_library(GLFW_LIBRARY STATIC IMPORTED)
set_target_properties(GLFW_LIBRARY PROPERTIES
    IMPORTED_LOCATION ${GLFW_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}glfw3${CMAKE_STATIC_LIBRARY_SUFFIX}
)
add_dependencies(GLFW_LIBRARY ${libGLFW})  # 新增依赖

# SETUP GLAD
set(libGLAD glad)
ExternalProject_Add(${libGLAD}
    PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}
    GIT_REPOSITORY https://github.com/Dav1dde/glad.git
    GIT_TAG origin/master
    GIT_SHALLOW ON
    UPDATE_DISCONNECTED ON
    CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}/install
               -DGLAD_INSTALL:BOOL=ON
               -DGLAD_PROFILE:STRING="core"
               -DGLAD_ALL_EXTENSIONS:BOOL=ON
               -DUSE_MSVC_RUNTIME_LIBRARY_DLL:BOOL=OFF
)
set(GLAD_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dep/${libGLAD}/install)
add_library(GLAD_LIBRARY STATIC IMPORTED)
set_target_properties(GLAD_LIBRARY PROPERTIES
    IMPORTED_LOCATION ${GLAD_INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}glad${CMAKE_STATIC_LIBRARY_SUFFIX}
)
add_dependencies(GLAD_LIBRARY ${libGLAD})  # 新增依赖

# CREATE OUR LIBRARY
file(GLOB_RECURSE headers CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/inc/*.h")
file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
add_library(${PROJECT_NAME} STATIC ${headers} ${sources})

# Add all include file paths
target_include_directories(${PROJECT_NAME}
    PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inc
    PUBLIC ${GLFW_INSTALL_DIR}/include
    PUBLIC ${GLAD_INSTALL_DIR}/include
)

# JOIN ALL LIBS
set(LIBNAME "${CMAKE_CURRENT_BINARY_DIR}/final/combinedLib.lib")
add_custom_command(
    OUTPUT ${LIBNAME}
    COMMAND ${libexe} /OUT:${LIBNAME} $<TARGET_FILE:GLFW_LIBRARY> $<TARGET_FILE:GLAD_LIBRARY> $<TARGET_FILE:${PROJECT_NAME}>
    DEPENDS GLFW_LIBRARY GLAD_LIBRARY ${PROJECT_NAME}
    COMMENT "Combining libs..."
)
add_custom_target(combinedLibGenerator DEPENDS ${LIBNAME} )
add_library(combinedLib STATIC IMPORTED)
set_property(TARGET combinedLib PROPERTY IMPORTED_LOCATION ${LIBNAME})
add_dependencies(combinedLib combinedLibGenerator)

验证效果

修改后,当你再次修改主项目的源码(比如添加cout输出)并构建时,VS只会构建test项目和combinedLibGenerator,不会再跑glad和glfw的update、configure、build步骤——除非你删除了对应的依赖安装目录,或者手动触发了依赖的更新。

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

火山引擎 最新活动