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

CMake项目中如何在文件夹文件变更时自动执行自定义脚本?

解决CMake GLOB+自定义命令无法自动响应文件增删的问题

问题根源

用file(GLOB CONFIGURE_DEPENDS)确实能让CMake在手动重新配置时更新文件列表,但构建阶段(比如make)不会自动触发CMake重新配置。这就导致:

  • 增删图片后,Makefile里的自定义命令依赖还是旧的文件列表,不会触发脚本重新运行
  • 即使CMake打印GLOB mismatch!,也只是提醒你需要重新配置,不会自动执行

解决方案:两种可靠实现方式

方式一:让脚本自己判断是否需要更新(推荐)

核心思路:让自定义命令同时依赖图片文件和目录本身(目录的修改时间在增删文件时会变化),然后在脚本里对比文件列表的哈希或者目录时间,只在需要的时候重新生成generated.h。

修改CMake配置

set(IMAGE_DIR ${CMAKE_SOURCE_DIR}/images)
set(OUT_FILE ${CMAKE_BINARY_DIR}/generated.h)

# 保留CONFIGURE_DEPENDS确保配置时更新文件列表
file(GLOB IN_FILES CONFIGURE_DEPENDS ${IMAGE_DIR}/*.png)

add_custom_command(
    OUTPUT ${OUT_FILE}
    # 把目录、输出文件、当前图片列表传给脚本
    COMMAND ${CMAKE_SOURCE_DIR}/command-to-generate-build-artifact.sh 
        ${IMAGE_DIR} ${OUT_FILE} ${IN_FILES}
    # 同时依赖图片文件和目录本身,目录变化时触发命令
    DEPENDS ${IN_FILES} ${IMAGE_DIR}
    COMMENT "Generating image header..."
)

add_custom_target(generate_image_data ALL DEPENDS ${OUT_FILE})
add_dependencies(project generate_image_data)

修改生成脚本(command-to-generate-build-artifact.sh)

在脚本开头加入判断逻辑,只有当文件列表变化或者输出文件不存在时,才重新生成:

#!/bin/bash
IMAGE_DIR=$1
OUT_FILE=$2
shift 2
# 获取当前传入的图片列表
CURRENT_FILES="$@"

# 用MD5哈希记录当前文件列表的状态
HASH_FILE="${OUT_FILE}.hash"
CURRENT_HASH=$(echo "$CURRENT_FILES" | md5sum | cut -d' ' -f1)

# 判断是否需要更新
if [ ! -f "$OUT_FILE" ] || [ ! -f "$HASH_FILE" ] || [ "$CURRENT_HASH" != "$(cat "$HASH_FILE" 2>/dev/null)" ]; then
    # 这里放你原来的生成逻辑,比如生成包含文件名的宏
    echo "#pragma once" > "$OUT_FILE"
    echo "#define IMAGE_COUNT $#" >> "$OUT_FILE"
    echo "const char* IMAGE_FILES[] = {" >> "$OUT_FILE"
    for file in $CURRENT_FILES; do
        echo "    \"$(basename "$file")\"," >> "$OUT_FILE"
    done
    echo "};" >> "$OUT_FILE"
    
    # 更新哈希文件
    echo "$CURRENT_HASH" > "$HASH_FILE"
else
    # 没有变化,触摸输出文件保持时间戳最新,避免后续不必要的构建
    touch "$OUT_FILE"
fi

方式二:让构建系统自动触发CMake重新配置

如果不想修改脚本,可以让Makefile在检测到目录变化时自动重新运行CMake配置,更新依赖列表。

修改CMake配置

set(IMAGE_DIR ${CMAKE_SOURCE_DIR}/images)
set(OUT_FILE ${CMAKE_BINARY_DIR}/generated.h)
# 用一个标记文件追踪目录变化
set(DIR_MARKER ${CMAKE_BINARY_DIR}/.images_dir_marker)

# 生成标记文件,依赖目录本身
add_custom_command(
    OUTPUT ${DIR_MARKER}
    COMMAND ${CMAKE_COMMAND} -E touch ${DIR_MARKER}
    DEPENDS ${IMAGE_DIR}
    COMMENT "Checking image directory changes..."
)

# 扫描图片文件
file(GLOB IN_FILES CONFIGURE_DEPENDS ${IMAGE_DIR}/*.png)

# 自定义命令同时依赖标记文件,目录变化时触发重新运行CMake
add_custom_command(
    OUTPUT ${OUT_FILE}
    COMMAND ${CMAKE_SOURCE_DIR}/command-to-generate-build-artifact.sh ${OUT_FILE} ${IN_FILES}
    DEPENDS ${IN_FILES} ${DIR_MARKER}
    COMMENT "Generating image header..."
)

add_custom_target(generate_image_data ALL DEPENDS ${OUT_FILE})
add_dependencies(project generate_image_data)

# 添加一个目标,检测目录变化后自动重新配置CMake
configure_file(
    ${CMAKE_SOURCE_DIR}/cmake/CheckDirChange.cmake.in 
    ${CMAKE_BINARY_DIR}/CheckDirChange.cmake 
    @ONLY
)
add_custom_target(check_dir_change 
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/CheckDirChange.cmake
    DEPENDS ${DIR_MARKER}
)
add_dependencies(generate_image_data check_dir_change)

创建CheckDirChange.cmake.in文件

在项目根目录下新建cmake文件夹,创建该文件:

set(IMAGE_DIR @IMAGE_DIR@)
set(DIR_MARKER @DIR_MARKER@)

# 获取目录和标记文件的修改时间
file(TIMESTAMP ${IMAGE_DIR} DIR_TIMESTAMP)
if(EXISTS ${DIR_MARKER})
    file(TIMESTAMP ${DIR_MARKER} MARKER_TIMESTAMP)
else()
    set(MARKER_TIMESTAMP "")
endif()

# 目录变化时重新运行CMake配置
if(NOT DIR_TIMESTAMP STREQUAL MARKER_TIMESTAMP)
    execute_process(
        COMMAND ${CMAKE_COMMAND} -E touch ${DIR_MARKER}
        COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR} -B ${CMAKE_BINARY_DIR}
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    )
endif()

验证效果

  • 新增/删除/重命名images下的png文件,直接运行make(或VS Code里的构建),脚本会自动重新生成generated.h
  • 修改图片内容,脚本也会因为文件时间戳变化触发更新

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:57:19