CMake超级构建仅执行一次的配置异常及适配方法问询
我完全懂你现在的困扰:想让超级构建只在第一次运行时自动搞定依赖和项目构建,之后默认不再触发,除非手动打开开关。但目前的代码逻辑里,明明输出显示USE_SUPERBUILD被设为off了,可主构建的CMakeCache.txt里还是on——核心问题确实是ExternalProject_Add启动的子构建和主构建用的是完全独立的缓存目录,子构建里的参数设置根本影响不到主构建的缓存。
核心解决方案:让子构建完成后直接修改主构建的缓存
要实现“首次构建后自动关闭超级构建”的效果,关键是在超级构建的子项目完成后,主动去修改主构建目录下的CMakeCache.txt,把USE_SUPERBUILD设为off。下面是具体的修改步骤:
1. 简化主CMakeLists.txt的逻辑
先把顶层CMakeLists.txt的逻辑捋清楚,只保留核心的开关判断:
# Top-Level CMakeLists.txt if(NOT DEFINED USE_SUPERBUILD) # 首次运行默认开启超级构建 set(USE_SUPERBUILD ON CACHE BOOL "Enable superbuild (runs once by default; set to ON to re-run)") endif() # 根据开关选择执行超级构建还是直接构建项目 if(USE_SUPERBUILD) include(superbuild.cmake) else() # 这里放你正常的项目构建逻辑,比如: # add_subdirectory(src) # ... 其他项目配置 endif()
2. 修改superbuild.cmake,添加POST_BUILD步骤更新主缓存
在ExternalProject_Add的配置里,新增POST_BUILD命令,直接在主构建目录执行cmake命令来修改缓存:
# superbuild.cmake ExternalProject_Add( my_proj DEPENDS ${MYPROJ_DEPENDENCIES} SOURCE_DIR ${PROJECT_SOURCE_DIR} CMAKE_ARGS -DUSE_SUPERBUILD:BOOL=off ${EXTRA_CMAKE_ARGS} INSTALL_COMMAND "" BINARY_DIR ${INSTALL_DIR} # 子构建完成后,主动修改主构建的缓存 POST_BUILD COMMAND ${CMAKE_COMMAND} -DUSE_SUPERBUILD:BOOL=off -U USE_SUPERBUILD # 先清除原有缓存项 -P ${PROJECT_SOURCE_DIR}/update_main_cache.cmake )
3. 编写update_main_cache.cmake脚本
在项目源码目录下创建这个脚本,用来确保主构建的缓存被正确更新:
# update_main_cache.cmake # 切换到主构建目录,执行cmake命令更新缓存 execute_process( COMMAND ${CMAKE_COMMAND} -DUSE_SUPERBUILD:BOOL=off . WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE UPDATE_RESULT ) if(UPDATE_RESULT EQUAL 0) message(STATUS "Successfully disabled superbuild for future runs.") else() message(WARNING "Failed to disable superbuild; you may need to manually set USE_SUPERBUILD to OFF in CMakeCache.txt.") endif()
为什么原来的方法无效?
你之前的代码里,在主CMakeLists.txt里用FORCE设置USE_SUPERBUILD,但这个操作只在主构建的配置阶段生效。而ExternalProject_Add启动的my_proj是在主构建的构建阶段执行的子构建,它的-DUSE_SUPERBUILD=off只会修改子构建目录(${INSTALL_DIR})下的CMakeCache.txt,和主构建的缓存完全没关系。所以主构建下次运行时,还是会读取自己缓存里的ON值,导致超级构建重复执行。
额外说明
- 这个方案完全满足你的需求:首次运行自动执行超级构建,之后默认关闭;如果需要重新执行超级构建,只需手动修改CMakeCache.txt里的
USE_SUPERBUILD:BOOL=ON,或者在cmake命令行加-DUSE_SUPERBUILD=ON即可。 - 确保
${CMAKE_BINARY_DIR}指向的是主构建目录,而不是子构建目录(${INSTALL_DIR}),脚本里的WORKING_DIRECTORY参数已经帮你处理了这一点。
内容的提问来源于stack exchange,提问作者Cameron Lowell Palmer

