CMake基础:foreach详解

目录

1.简介

2.使用场景

2.1.批量添加源文件到目标

2.2.遍历目录下的所有指定文件

2.3.批量链接第三方库

[3.循环控制(CMake 3.20+ 支持)](#3.循环控制(CMake 3.20+ 支持))

4.同时循环多个列表

5.注意事项


1.简介

CMake 的 foreach 是遍历列表 / 集合的核心指令,支持传统遍历现代关键字遍历两种语法,常用于批量处理源文件、库依赖、编译选项等场景。

语法:

cpp 复制代码
foreach(<循环变量> IN [LISTS <列表名>] [ITEMS <元素>] [RANGE <起始> <结束>])
    # 循环体
endforeach()
  • LISTS:遍历已定义的 CMake 列表变量
  • ITEMS:遍历直接给出的元素
  • RANGE:遍历数值范围(如 RANGE 1 5 对应 1-5)

2.使用场景

2.1.批量添加源文件到目标

适用于项目源文件较多的情况,避免重复写 add_executable 的参数。

cpp 复制代码
cmake_minimum_required(VERSION 3.15)
project(ForeachDemo LANGUAGES CXX)

# 定义源文件列表
set(SOURCE_FILES
    main.cpp
    utils.cpp
    network.cpp
)

# 遍历源文件列表,打印并收集(这里直接用列表也能加,遍历主要用于额外操作)
foreach(src IN LISTS SOURCE_FILES)
    message(STATUS "添加源文件: ${src}")
endforeach()

# 添加可执行文件
add_executable(${PROJECT_NAME} ${SOURCE_FILES})

# Windows + VS2019 环境配置
if(MSVC)
    target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX)
endif()

2.2.遍历目录下的所有指定文件

结合 file(GLOB) 收集目录中的 .cpp 文件,适合动态管理源文件。

cpp 复制代码
cmake_minimum_required(VERSION 3.15)
project(ForeachFileDemo LANGUAGES CXX)

# 收集 src 目录下的所有 .cpp 文件(GLOB 会自动生成列表)
file(GLOB_RECURSE SRC_FILES ${CMAKE_SOURCE_DIR}/src/*.cpp)

# 遍历文件列表,过滤掉不需要的文件(比如 test_xxx.cpp)
foreach(file IN LISTS SRC_FILES)
    # 检查文件名是否包含 test_
    if(file MATCHES "test_.*\\.cpp$")
        message(STATUS "过滤测试文件: ${file}")
        list(REMOVE_ITEM SRC_FILES ${file}) # 从列表中移除
    endif()
endforeach()

add_executable(${PROJECT_NAME} ${SRC_FILES})

注意:file(GLOB) 不推荐用于频繁增减文件的场景,若文件变动需手动执行 cmake --build . --clean-first 重新生成。

2.3.批量链接第三方库

适用于项目依赖多个库的情况,简化 target_link_libraries 的写法。

cpp 复制代码
cmake_minimum_required(VERSION 3.15)
project(ForeachLibDemo LANGUAGES CXX)

add_executable(${PROJECT_NAME} main.cpp)

# 定义依赖库列表(假设已通过 find_package 找到这些库)
set(DEPEND_LIBS
    Qt5::Core
    Qt5::Sql
    Boost::asio
)

# 遍历库列表,批量链接
foreach(lib IN LISTS DEPEND_LIBS)
    target_link_libraries(${PROJECT_NAME} PRIVATE ${lib})
    message(STATUS "链接库: ${lib}")
endforeach()

3.循环控制(CMake 3.20+ 支持)

CMake 3.20 及以上版本支持 continue()(跳过当前循环)和 break()(终止循环),示例如下:

cpp 复制代码
foreach(num RANGE 1 10)
    if(num LESS 3)
        continue() # 跳过 1、2
    endif()
    if(num GREATER 7)
        break() # 终止于 8
    endif()
    message(STATUS "当前数值: ${num}")
endforeach()

4.同时循环多个列表

CMake 的 foreach 本身不支持直接并行遍历多个列表,需借助索引循环 + 列表取值 实现,核心思路是通过列表长度确定循环次数,再用 list(GET) 获取对应索引的元素。

示例:同时遍历源文件列表对应的编译选项列表,为不同源文件设置专属编译参数

cpp 复制代码
cmake_minimum_required(VERSION 3.15)
project(MultiListForeach LANGUAGES CXX)

# 定义两个长度相同的列表
set(SOURCE_FILES main.cpp utils.cpp network.cpp)
set(COMPILE_FLAGS "-O2" "-g -Wall" "-O3 -march=native")

# 获取列表长度(需确保所有列表长度一致)
list(LENGTH SOURCE_FILES FILE_COUNT)
if(NOT FILE_COUNT EQUAL ${CMAKE_ARGV2})
    message(FATAL_ERROR "列表长度不一致,无法并行遍历!")
endif()

# 索引循环,遍历多个列表
math(EXPR MAX_INDEX "${FILE_COUNT} - 1")
foreach(IDX RANGE 0 ${MAX_INDEX})
    # 获取对应索引的元素
    list(GET SOURCE_FILES ${IDX} CURRENT_FILE)
    list(GET COMPILE_FLAGS ${IDX} CURRENT_FLAG)

    # 打印信息 + 应用编译选项
    message(STATUS "为 ${CURRENT_FILE} 设置编译选项: ${CURRENT_FLAG}")
    set_source_files_properties(${CURRENT_FILE} PROPERTIES COMPILE_FLAGS ${CURRENT_FLAG})
endforeach()

add_executable(${PROJECT_NAME} ${SOURCE_FILES})

# Windows VS2019 环境适配
if(MSVC)
    target_compile_options(${PROJECT_NAME} PRIVATE /W4)
endif()

5.注意事项

1.循环变量的作用域:foreach 内定义的变量默认是全局的,若需局部作用域,可在循环内用 set(<var> <value> PARENT_SCOPE) 控制。

2.跨平台路径处理:遍历文件路径时,建议用 CMAKE_SOURCE_DIR/CMAKE_CURRENT_SOURCE_DIR 等变量,避免硬编码 Windows 路径分隔符。

相关推荐
天骄t2 小时前
UART通信全解析:从原理到实战
linux·单片机
sjg200104142 小时前
GoFrame学习随便记2
windows·学习
感觉不怎么会2 小时前
ubuntu - 搭建TR069平台问题(Open ACS)
linux·运维·ubuntu
2301_765715142 小时前
深入操作系统核心:全面解析存储管理机制
windows
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ2 小时前
List、Set的相似性
windows·tomcat·list
小黄鸭code2 小时前
C++ 算法笔试题(常见算法版)
c++·算法·排序算法
Xの哲學2 小时前
Linux Worklet 深入剖析: 轻量级延迟执行机制
linux·服务器·网络·数据结构·算法
lihao lihao2 小时前
C++ set和map
开发语言·c++·算法
宴之敖者、2 小时前
Linux——初始Linux系统
linux·运维·服务器