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

CMake遍历子目录指定模式文件时变量仅保留最后一个文件的问题

问题分析与解决方案

问题现象

调用ListFilesInSubmodule两次分别收集.c和.h文件后,PLUGIN_STRUCTURES仅保留每次调用的最后一个文件,最终仅留存第二次调用的最后一个.h文件。

问题根源

  1. 原代码中,循环内调用set(PLUGIN_STRUCTURES ${PLUGIN_STRUCTURES} "${_file}" PARENT_SCOPE)时,函数作用域内未定义PLUGIN_STRUCTURES,导致每次都将父作用域变量覆盖为单个文件。
  2. 修改后的代码里,每次函数调用都会初始化空的_Temp变量,收集当前模式的文件后直接覆盖父作用域的PLUGIN_STRUCTURES,第一次调用的结果被第二次完全覆盖。

解决方案

方案1:修复原函数的作用域问题

让函数接收输出变量名作为参数,先读取父作用域的已有值,追加新文件后再写回父作用域:

function(ListFilesInSubmodule directory_path pattern output_var)
    # 读取父作用域中输出变量的当前值
    set(_current_files "")
    if(DEFINED ${output_var})
        set(_current_files "${${output_var}}")
    endif()

    if(WIN32)
        execute_process(COMMAND powershell -c "Get-ChildItem -Path '${directory_path}' -Recurse -Filter '${pattern}' -File | ForEach-Object { Write-Host $_.FullName }"
            WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
            OUTPUT_VARIABLE _Files
            OUTPUT_STRIP_TRAILING_WHITESPACE
        )
    else()
        execute_process(COMMAND bash -c "find '${directory_path}' -type f -name '${pattern}'"
            WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
            OUTPUT_VARIABLE _Files
            OUTPUT_STRIP_TRAILING_WHITESPACE
        )
    endif()

    if(NOT _Files)
        message(STATUS "No files found matching pattern '${pattern}' in '${directory_path}'.")
    else()
        string(REPLACE "\n" ";" _FilesList "${_Files}")
        foreach(_file IN LISTS _FilesList)
            if(EXISTS "${CMAKE_SOURCE_DIR}/${_file}")
                list(APPEND _current_files "${_file}")
                message(STATUS "File is found '${_file}'.")
            else()
                message(WARNING "File is possibly not found '${_file}'.")
            endif()
        endforeach()
    endif()

    # 将更新后的列表写回父作用域
    set(${output_var} "${_current_files}" PARENT_SCOPE)
endfunction()

调用方式:

ListFilesInSubmodule("libs/subhook" "*.c" PLUGIN_STRUCTURES)
ListFilesInSubmodule("libs/subhook" "*.h" PLUGIN_STRUCTURES)

message(STATUS "PLUGIN_STRUCTURES : ${PLUGIN_STRUCTURES}")

方案2:改用CMake内置file(GLOB_RECURSE)(推荐)

CMake自带跨平台的递归文件查找命令,无需手动处理shell逻辑,更可靠:

file(GLOB_RECURSE PLUGIN_STRUCTURES
    "${CMAKE_SOURCE_DIR}/libs/subhook/*.c"
    "${CMAKE_SOURCE_DIR}/libs/subhook/*.h"
)

# 可选:过滤不存在的文件(GLOB_RECURSE理论不会返回无效路径,仅作容错)
foreach(_file IN LISTS PLUGIN_STRUCTURES)
    if(NOT EXISTS "${_file}")
        message(WARNING "File not found: ${_file}")
        list(REMOVE_ITEM PLUGIN_STRUCTURES "${_file}")
    endif()
endforeach()

message(STATUS "PLUGIN_STRUCTURES : ${PLUGIN_STRUCTURES}")

关键说明

  • 方案1通过参数化输出变量,实现灵活的变量操作,同时避免作用域导致的覆盖问题。
  • 方案2符合CMake最佳实践,若需自动感知文件新增(无需手动重新配置),可使用file(GLOB_RECURSE ... CONFIGURE_DEPENDS)(CMake 3.12+支持)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 02:35:16