如何在CMake中对列表内容进行随机打乱?
打乱CMake目标SOURCES列表的高效方案
这里有几个兼顾性能和易用性的实现思路,适配不同场景需求:
1. 纯CMake实现Fisher-Yates洗牌(高效跨平台)
Fisher-Yates是经典的原地洗牌算法,时间复杂度O(n),比随机移除元素的方式高效得多,完全依赖CMake内置命令,跨平台无依赖:
function(shuffle_list OUTPUT_VAR) set(LIST_TO_SHUFFLE ${ARGN}) list(LENGTH LIST_TO_SHUFFLE LIST_LENGTH) if(LIST_LENGTH LESS 2) set(${OUTPUT_VAR} ${LIST_TO_SHUFFLE} PARENT_SCOPE) return() endif() foreach(INDEX RANGE 1 ${LIST_LENGTH}) math(EXPR CURRENT_INDEX "${LIST_LENGTH} - ${INDEX}") string(RANDOM INT 0 ${CURRENT_INDEX} RANDOM_INDEX) list(GET LIST_TO_SHUFFLE ${RANDOM_INDEX} TEMP) list(GET LIST_TO_SHUFFLE ${CURRENT_INDEX} CURRENT_VALUE) list(SET LIST_TO_SHUFFLE ${RANDOM_INDEX} ${CURRENT_VALUE}) list(SET LIST_TO_SHUFFLE ${CURRENT_INDEX} ${TEMP}) endforeach() set(${OUTPUT_VAR} ${LIST_TO_SHUFFLE} PARENT_SCOPE) endfunction() # 使用示例:打乱目标的SOURCES列表 get_target_property(TARGET_SOURCES my_target SOURCES) shuffle_list(SHUFFLED_SOURCES ${TARGET_SOURCES}) set_target_properties(my_target PROPERTIES SOURCES "${SHUFFLED_SOURCES}")
对于常规规模的源文件列表(几百上千个),这个方案的性能完全够用,不会产生明显的配置阶段耗时。
2. 系统工具+管道(类Unix平台,无临时文件)
如果构建环境是Linux/macOS,可以通过管道传递列表内容给shuf,避免写入临时文件的开销:
get_target_property(TARGET_SOURCES my_target SOURCES) # 将分号分隔的列表转为换行分隔的字符串 string(REPLACE ";" "\n" SOURCES_NEWLINE "${TARGET_SOURCES}") # 通过bash管道完成打乱,再转回分号分隔格式 execute_process( COMMAND bash -c "echo '${SOURCES_NEWLINE}' | shuf" OUTPUT_VARIABLE SHUFFLED_SOURCES_NEWLINE OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REPLACE "\n" ";" SHUFFLED_SOURCES "${SHUFFLED_SOURCES_NEWLINE}") set_target_properties(my_target PROPERTIES SOURCES "${SHUFFLED_SOURCES}")
Windows平台可替换为PowerShell的Get-Random命令,不过需要注意转义规则,相对来说纯CMake方案更省心。
补充:轻量替代方案(快速触发错误)
如果核心需求是尽早暴露构建错误而非严格随机打乱,还可以用更简单的方式:
- 反转源文件列表:
list(REVERSE TARGET_SOURCES),直接把最后编译的文件移到最前面 - 只编译前N个文件:
list(SUBLIST TARGET_SOURCES 0 20 SHUFFLED_SOURCES),快速验证小范围文件 - 随机抽取部分文件:结合
string(RANDOM)取少量文件优先编译
这些方式无需复杂洗牌逻辑,能更快定位问题代码。
内容的提问来源于stack exchange,提问作者PasterOfMuppets
相关产品推荐
相关产品推荐

