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

如何解决CMake构建阶段Python脚本生成源文件首次编译失败问题

CMake构建阶段自动生成源文件并编译的问题解决

问题原因

你之前用add_custom_command(TARGET ...)绑定到目标执行脚本的方式,不管是POST_BUILD还是PRE_LINK阶段,执行时机都太晚了:

  • sub_folder下的库目标在CMake配置阶段就通过file(GLOB)扫描了源文件,首次构建时脚本还没运行,生成的文件不存在,自然不会被加入编译列表
  • 第二次构建时文件已经存在,但如果没重新运行CMake,CMake缓存里还是旧的扫描结果,只有重新配置或者构建系统检测到目录变化才会重新扫描(不同构建系统行为有差异),这才导致第二次构建能成功。

而execute_process能正常工作,是因为它在配置阶段就运行脚本生成了文件,后续的file(GLOB)能直接扫描到这些文件,构建时自然会编译。

解决方案

方案1:配置阶段生成文件(最简单可靠)

如果你的Python脚本不需要依赖构建阶段的产物,直接用execute_process在配置阶段生成文件即可,这样sub_folder的file(GLOB)能直接扫到所有生成的文件。

在ROOT/build/CMakeLists.txt中添加:

# 运行Python脚本生成文件
execute_process(
    COMMAND ${CMAKE_COMMAND} -E env ${PYTHON3} ${CMAKE_CURRENT_SOURCE_DIR}/my_python_script.py
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    RESULT_VARIABLE SCRIPT_RUN_RESULT
)

# 检查脚本执行是否成功
if(NOT SCRIPT_RUN_RESULT EQUAL 0)
    message(FATAL_ERROR "自动生成源文件的Python脚本执行失败")
endif()

方案2:构建阶段生成文件(需适配动态文件名)

如果必须在构建阶段生成文件(比如脚本需要依赖构建过程中生成的中间产物),要解决两个核心问题:确保脚本在库目标编译前运行,让CMake能追踪到动态生成的文件。

步骤如下:

  1. 修改Python脚本:生成源文件后,在sub_folder/auto_gen_dir目录下输出一个包含所有生成源文件路径的文本文件(比如generated_sources.txt),每行一个文件路径。
  2. 在ROOT/build/CMakeLists.txt中定义生成目标:
# 定义生成文件的输出列表文件路径
set(GENERATED_FILE_LIST ${CMAKE_CURRENT_SOURCE_DIR}/../sub_folder/auto_gen_dir/generated_sources.txt)
set(GENERATED_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../sub_folder/auto_gen_dir)

# 定义自定义命令:运行脚本生成文件,并输出文件列表
add_custom_command(
    OUTPUT ${GENERATED_FILE_LIST}
    COMMAND ${CMAKE_COMMAND} -E env ${PYTHON3} ${CMAKE_CURRENT_SOURCE_DIR}/my_python_script.py
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMENT "正在自动生成源文件..."
    VERBATIM
)

# 创建自定义目标,确保脚本在构建阶段执行
add_custom_target(generate_auto_sources ALL DEPENDS ${GENERATED_FILE_LIST})
  1. 在sub_folder/build/CMakeLists.txt中绑定依赖并添加源文件:
set(GENERATED_FILE_LIST ${CMAKE_CURRENT_SOURCE_DIR}/../auto_gen_dir/generated_sources.txt)

# 读取生成的源文件列表
file(READ ${GENERATED_FILE_LIST} GENERATED_SOURCES_CONTENT)
string(REPLACE "\n" ";" GENERATED_SOURCES ${GENERATED_SOURCES_CONTENT})
# 过滤空行
list(FILTER GENERATED_SOURCES EXCLUDE REGEX "^$")

# 创建库目标
add_library(amdb_core STATIC)
# 添加生成的源文件
target_sources(amdb_core PRIVATE ${GENERATED_SOURCES})
# 让库目标依赖生成脚本的目标,确保先生成文件再编译
add_dependencies(amdb_core generate_auto_sources)

这种方式避免了依赖file(GLOB)的配置阶段扫描,直接通过脚本输出的文件列表添加源文件,同时通过add_dependencies确保生成步骤先于编译执行。

总结

  • 优先选择方案1,配置阶段生成文件,实现简单且不易出错
  • 若必须在构建阶段生成,采用方案2,通过脚本输出文件列表的方式让CMake追踪动态生成的文件,避免依赖file(GLOB)的局限性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:33:14