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

能否让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 21:47:37