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

CMake中add_dependencies等命令协同失效问题及解法疑问

问题:CMake生成文件后无法正确构建可执行文件

我想用CMake实现一个简单流程:用脚本生成文件,再基于这些生成文件构建可执行文件。查了文档和资料后按预期配置,但项目始终无法正常构建。

预期执行步骤

  • 配置阶段:生成带正确路径的generate_files.sh脚本
  • 构建阶段:先构建gen自定义目标,再构建test可执行目标

步骤1能正常完成,但步骤2失效。CMake报错test目标的源文件不存在,尽管逻辑上应该先构建gen生成这些源文件。

目录结构

.
├── build
├── CMakeLists.txt
├── config
│   └── generate_files.sh.in
├── extern
│   ├── CMakeLists.txt
│   └── gen
├── scripts
└── src
    ├── CMakeLists.txt
    └── main.cpp

各文件内容

顶层CMakeLists.txt

cmake_minimum_required(VERSION 3.13)
project(test VERSION 0.1.0.0)

add_subdirectory(src)
add_subdirectory(extern)

configure_file("${CMAKE_SOURCE_DIR}/config/generate_files.sh.in" "${CMAKE_SOURCE_DIR}/scripts/generate_files.sh")

src/CMakeLists.txt

add_executable(test main.cpp)

extern/CMakeLists.txt(原失效配置)

set(generated_sources
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated.h
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_1.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_2.cpp
    )

set(generated_directories
    ${CMAKE_CURRENT_SOURCE_DIR}/gen)

add_custom_command(
    OUTPUT ${generated_sources}
    COMMAND "${CMAKE_SOURCE_DIR}/scripts/generate_files.sh"
    )

add_custom_target(gen
    DEPENDS ${generated_sources}
    )

add_dependencies(test gen)

target_sources(test
    PRIVATE
        ${generated_sources}
)

target_include_directories(test
    PRIVATE
        ${generated_directories}
)

config/generate_files.sh.in

#! /bin/bash

echo " const int get_trouble_code();
const int get_higher_trouble_code();" > ${CMAKE_SOURCE_DIR}/extern/gen/generated.h
echo " #include \"generated.h\"
const int get_trouble_code(){return 1;}" > ${CMAKE_SOURCE_DIR}/extern/gen/generated_1.cpp
echo " #include \"generated.h\"
const int get_higher_trouble_code(){return 1+1;}" > ${CMAKE_SOURCE_DIR}/extern/gen/generated_2.cpp

src/main.cpp

#include "generated.h"

int main()
{
  get_trouble_code();
  get_higher_trouble_code();

  return 0;
}

编辑:找到可行方案但有疑问

把生成文件打包成库而非自定义目标后就能正常工作,修改后的extern/CMakeLists.txt如下,求解释原因:

set(generated_sources
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated.h
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_1.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_2.cpp
    )

set(generated_directories
    ${CMAKE_CURRENT_SOURCE_DIR}/gen)

add_custom_command(
    OUTPUT ${generated_sources}
    COMMAND "${CMAKE_SOURCE_DIR}/scripts/generate_files.sh"
    )

# 注释掉原来的自定义目标相关代码
#add_custom_target(gen
#   DEPENDS ${generated_sources}
#    )
#
#add_dependencies(test gen)
#
#target_sources(test
#    PRIVATE
#        ${generated_sources}
#)

# 改为生成库
add_library(gen ${generated_sources})
target_link_libraries(test PRIVATE gen)

target_include_directories(test
    PRIVATE
        ${generated_directories}
)

解答

原配置失效的原因

CMake在配置阶段就会检查目标的源文件是否存在(除非明确标记为生成文件)。你原配置中,虽然给test添加了对gen自定义目标的依赖,但直接把生成的源文件通过target_sources加到test时,CMake无法把这些源文件和add_custom_command的输出关联起来——它只会认为这些是普通的、必须预先存在的源文件,所以配置阶段就会报错找不到文件。

add_dependencies(test gen)只是告诉CMake:构建test之前要先构建gen,但这并不能让CMake意识到generated_sources是由gen目标生成的,因为自定义目标和生成文件的关联没有传递到test目标上。

改用库可行的原因

当你用add_library(gen ${generated_sources})时,CMake会自动把add_custom_command的输出(generated_sources)和这个库目标关联起来:

  1. CMake识别到这些源文件是add_custom_command的输出,知道它们需要在构建库之前生成
  2. 当test链接这个库时,CMake会自动处理依赖链:先运行add_custom_command生成源文件,再构建gen库,最后构建test可执行文件
  3. 这种方式下,生成文件的依赖关系被封装在库目标内部,CMake能正确追踪整个流程,不会在配置阶段就报错源文件不存在

原配置的修复方案(不用库的话)

如果不想用库,只需修改原extern/CMakeLists.txt,把add_custom_command的输出直接关联到test目标,而不是通过中间自定义目标:

set(generated_sources
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated.h
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_1.cpp
    ${CMAKE_CURRENT_SOURCE_DIR}/gen/generated_2.cpp
    )

set(generated_directories
    ${CMAKE_CURRENT_SOURCE_DIR}/gen)

# 直接为test目标添加生成源文件的自定义命令
add_custom_command(
    OUTPUT ${generated_sources}
    COMMAND "${CMAKE_SOURCE_DIR}/scripts/generate_files.sh"
    # 可选:指定DEPENDS,如果脚本依赖其他文件的话
    # DEPENDS "${CMAKE_SOURCE_DIR}/config/generate_files.sh.in"
    )

# 直接把生成文件加到test,CMake会自动关联自定义命令的依赖
target_sources(test
    PRIVATE
        ${generated_sources}
)

target_include_directories(test
    PRIVATE
        ${generated_directories}
)

这样CMake就能识别到这些源文件是生成的,会在构建test之前自动运行add_custom_command生成它们,不需要额外的自定义目标和add_dependencies。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:55:50