能否让CMake add_subdirectory按顺序编译,使后续find_package识别前置子目录?
解决方案
方法一:用ExternalProject_Add管控依赖顺序(推荐)
放弃直接使用add_subdirectory,改用ExternalProject_Add分别管理每个子项目的构建流程,明确指定bar依赖foo,确保bar的配置阶段在foo的安装完成后执行:
cmake_minimum_required(VERSION 3.14) project(MyProject) include(ExternalProject) # 构建foo并安装到本地构建目录 ExternalProject_Add( foo SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/foo BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/foo INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/install/foo CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> ) # 构建bar,依赖foo,同时指定foo的配置文件路径 ExternalProject_Add( bar SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/bar BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bar INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/install/bar CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR> -Dfoo_DIR=${CMAKE_CURRENT_BINARY_DIR}/install/foo/lib/cmake/foo # 路径需匹配foo实际生成config的位置 DEPENDS foo )
这种方式完全隔离了子项目的配置与构建流程,bar的find_package(foo)会直接找到foo安装目录下的完整配置文件,无需修改任何子项目代码。
方法二:在配置阶段提前触发foo的构建
如果坚持使用add_subdirectory,可以在顶层CMake中先强制构建foo的安装/export目标,生成所需的配置文件后再配置bar:
cmake_minimum_required(VERSION 3.14) project(MyProject) # 添加foo子目录 add_subdirectory(foo) # 手动触发foo的install目标,生成配置文件到指定目录 execute_process( COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/foo --target install WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/foo RESULT_VARIABLE FOO_BUILD_RESULT ) if(NOT FOO_BUILD_RESULT EQUAL 0) message(FATAL_ERROR "Failed to build foo") endif() # 指定foo的配置文件路径 set(foo_DIR ${CMAKE_CURRENT_BINARY_DIR}/install/foo/lib/cmake/foo) # 再添加bar子目录 add_subdirectory(bar)
注意:这种方式会在CMake配置阶段就执行foo的构建,可能会影响增量构建效率,但能保证bar配置时foo的文件已存在。
方法三:利用CMAKE_CONFIGURE_DEPENDS自动触发重配置
如果foo的CMakeLists中使用了export(EXPORT)生成本地配置文件(而非仅install时生成),可以通过让CMake监控该文件的生成,自动重新配置:
cmake_minimum_required(VERSION 3.14) project(MyProject) add_subdirectory(foo) set(FOO_TARGETS_FILE ${CMAKE_CURRENT_BINARY_DIR}/foo/foo-targets.cmake) # 让CMake监控该文件,文件生成后自动重新配置 set(CMAKE_CONFIGURE_DEPENDS ${CMAKE_CONFIGURE_DEPENDS} ${FOO_TARGETS_FILE}) # 如果文件已存在,提前导入foo的目标 if(EXISTS ${FOO_TARGETS_FILE}) include(${FOO_TARGETS_FILE}) endif() set(foo_DIR ${CMAKE_CURRENT_BINARY_DIR}/foo) add_subdirectory(bar)
第一次配置时可能会因文件不存在报错,但当foo构建完成生成foo-targets.cmake后,CMake会自动重新运行配置流程,此时bar的find_package就能成功找到依赖。
内容的提问来源于stack exchange,提问作者JWCS
相关产品推荐
相关产品推荐

