☰
CMake指令:list实用功能详解
2026/11/4 1:21:49 网站建设 项目流程

目录

1.简介

2.常用命令

2.1.APPEND:向列表末尾添加元素

2.2.PREPEND:向列表开头添加元素

2.3.INSERT:在指定索引处插入元素

2.4.REMOVE_ITEM:删除列表中指定值的元素

2.5.REMOVE_AT:删除指定索引处的元素

2.6.REMOVE_DUPLICATES:移除列表中的重复元素

2.7.LENGTH:获取列表长度(元素个数)

2.8.GET:获取列表中指定索引的元素

2.9.JOIN:将列表元素用指定分隔符连接成字符串

2.10.REVERSE:反转列表顺序

2.11.SORT:对列表进行排序(按字母顺序)

2.12.CLEAR:清空列表中的所有元素

2.13.CONCAT:合并多个列表为一个列表(等价于多次 APPEND)

2.14.TRANSFORM: 列表元素变换

2.15.FILTER(CMake 3.6+): 过滤元素

3.注意事项

4.set 命令和 list 命令异同

5.总结

相关链接


1.简介

在 CMake 中,list命令用于操作列表(Lists),这是 CMake 中一种重要的数据结构(用于存储多个值,如源文件路径、编译选项、宏定义等)。list命令支持多种子命令,用于实现列表的创建、修改、查询和处理等操作。

list(COMMAND [arguments...])

其中,COMMAND是子命令(如APPEND、REMOVE_ITEM等),arguments是对应子命令的参数。

2.常用命令

2.1.APPEND:向列表末尾添加元素

list(APPEND my_list "item1" "item2") # 添加多个元素 # 结果:my_list = ["item1", "item2"]

2.2.PREPEND:向列表开头添加元素

list(PREPEND my_list "item0") # 结果:my_list = ["item0", "item1", "item2"]

2.3.INSERT:在指定索引处插入元素

list(INSERT my_list 1 "item0.5") # 在索引 1 处插入元素 # 结果:my_list = ["item0", "item0.5", "item1", "item2"]

2.4.REMOVE_ITEM:删除列表中指定值的元素

list(REMOVE_ITEM my_list "item0.5") # 删除值为 "item0.5" 的元素 # 结果:my_list = ["item0", "item1", "item2"]

2.5.REMOVE_AT:删除指定索引处的元素

list(REMOVE_AT my_list 0) # 删除索引 0 处的元素 # 结果:my_list = ["item1", "item2"]

2.6.REMOVE_DUPLICATES:移除列表中的重复元素

list(APPEND my_list "item1") # 添加重复元素 # 此时 my_list = ["item1", "item2", "item1"] list(REMOVE_DUPLICATES my_list) # 结果:my_list = ["item1", "item2"]

2.7.LENGTH:获取列表长度(元素个数)

list(LENGTH my_list list_length) message(STATUS "列表长度:${list_length}") # 输出:列表长度:2

2.8.GET:获取列表中指定索引的元素

list(GET my_list 0 first_item) # 获取索引 0 处的元素 message(STATUS "第一个元素:${first_item}") # 输出:第一个元素:item1

2.9.JOIN:将列表元素用指定分隔符连接成字符串

list(JOIN my_list ";" joined_string) message(STATUS "连接后的字符串:${joined_string}") # 输出:item1;item2

2.10.REVERSE:反转列表顺序

list(REVERSE my_list) # 结果:my_list = ["item2", "item1"]

2.11.SORT:对列表进行排序(按字母顺序)

list(APPEND my_list "item3" "item0") # 此时 my_list = ["item2", "item1", "item3", "item0"] list(SORT my_list) # 结果:my_list = ["item0", "item1", "item2", "item3"]

2.12.CLEAR:清空列表中的所有元素

list(CLEAR temp_files) # 清空临时文件列表

2.13.CONCAT:合并多个列表为一个列表(等价于多次APPEND)

list(CONCAT all_files src_files test_files) # 合并源文件和测试文件列表

2.14.TRANSFORM: 列表元素变换

在 CMake 3.12 及以上版本中,list(TRANSFORM ...)用于对列表中的每个元素执行转换操作(如添加前缀、替换字符串、调用函数等),并将结果存储到原列表或新变量中。这是处理列表元素的强大工具,尤其适合批量处理文件路径、编译选项等场景。

list(TRANSFORM <list> <ACTION> ... [OUTPUT_VARIABLE <output>])
  • <list>:要操作的列表变量名。
  • <ACTION>:转换动作,支持以下几种:
    • PREPEND <prefix>:为每个元素添加前缀。
    • APPEND <suffix>:为每个元素添加后缀。
    • REPLACE <match> <replace>:替换元素中的匹配字符串。
    • STRIP:去除元素首尾的空格。
    • TOUPPER/TOLOWER:转换为大写 / 小写。
    • GENEX_STRIP:移除生成器表达式(如$<CONFIG:Debug>)。
  • OUTPUT_VARIABLE <output>(可选):将结果存储到新变量,而非覆盖原列表。

常用场景示例

1.添加前缀 / 后缀(最常用)

set(SOURCES "main.cpp" "utils.cpp") # 为每个源文件添加 "src/" 前缀(等效于 "src/main.cpp" "src/utils.cpp") list(TRANSFORM SOURCES PREPEND "src/") # 为每个源文件添加 "_test" 后缀(等效于 "main_test.cpp" "utils_test.cpp") list(TRANSFORM SOURCES APPEND "_test.cpp")

2.替换字符串

set(PATHS "/old/path/file1" "/old/path/file2") # 将 "/old/path/" 替换为 "/new/path/" list(TRANSFORM PATHS REPLACE "/old/path/" "/new/path/")

3.大小写转换

set(FLAGS "Debug" "Release") # 转换为大写(等效于 "DEBUG" "RELEASE") list(TRANSFORM FLAGS TOUPPER) # 转换为小写(等效于 "debug" "release") list(TRANSFORM FLAGS TOLOWER)

4.输出到新变量(保留原列表)

set(INPUT "file1.txt" "file2.txt") # 将结果存入 NEW_INPUT,原 INPUT 不变 list(TRANSFORM INPUT PREPEND "data/" OUTPUT_VARIABLE NEW_INPUT) # NEW_INPUT 为 "data/file1.txt" "data/file2.txt"

5.结合生成器表达式

生成器表达式可在构建时动态计算值,例如:

set(SOURCES "main.cpp" "utils.cpp") # 为每个源文件添加基于配置的编译定义(如 Debug 模式下定义 DEBUG=1) list(TRANSFORM SOURCES APPEND "$<$<CONFIG:Debug>:-DDEBUG=1>")

2.15.FILTER(CMake 3.6+): 过滤元素

list(FILTER <list> <MODE> REGEX <regex>)

对列表进行过滤,原地修改原列表变量,只保留或者剔除符合正则的元素。

参数说明

  1. <list>:变量名(不是直接写列表值!),是要被修改的列表变量
  2. <MODE>二选一:
    • INCLUDE:保留匹配正则的元素,删掉不匹配的
    • EXCLUDE:剔除匹配正则的元素,删掉匹配的(你要的删除包含指定字符串就是这个)
  3. REGEX <regex>:CMake 正则表达式

⚠️ 重点:是正则匹配,不是简单子串匹配!

基础示例:

set(LST "foo.txt;bar.cpp;foo.h;test.log") # 保留带 foo 的(INCLUDE) list(FILTER LST INCLUDE REGEX "foo") # LST = foo.txt;foo.h set(LST "foo.txt;bar.cpp;foo.h;test.log") # 删除带 foo 的(EXCLUDE) list(FILTER LST EXCLUDE REGEX "foo") # LST = bar.cpp;test.log

匹配规则(CMake 正则语法,很容易踩坑)

CMake 使用的是POSIX ERE(扩展正则)

  • "abc":只要元素里面任意位置包含 abc就匹配(等价于 .abc.)✅ 也就是你想要的 “包含字符串”
  • "^abc":以 abc 开头
  • "abc$":以 abc 结尾
  • "^abc$":整项严格等于 abc

不需要手动前后加.*,REGEX "abc"自动是包含匹配,这是很多人不知道的。

元字符需要转义

. + * ? [ ] ( ) \ { }都是正则元字符,如果你想字面匹配这些字符,必须转义:

表格

要匹配字面正则写法
.so\\.so
+\\+
*\\*
[\\[

示例:删除包含.so的条目

set(LST "liba.so;main.cpp;libb.a;test.so") list(FILTER LST EXCLUDE REGEX "\\.so") # 结果:main.cpp;libb.a

CMake 字符串里\本身也要转义,所以写两个反斜杠\\.

大小写

CMake 的 REGEX默认区分大小写

set(LST "Abc;abc;ABC") list(FILTER LST EXCLUDE REGEX "abc") # 只会删掉小写 abc,Abc、ABC 保留

CMake 原生list(FILTER)没有不区分大小写开关!如果需要忽略大小写,list(FILTER)做不到,只能用foreach + string(TOLOWER) + string(FIND)方案。

边界坑点(高频踩坑)

1.不会新建变量,原地修改!

# ❌ 错误写法:不能直接写列表字面量 list(FILTER "a;b;c" EXCLUDE REGEX "a") # ✅ 正确:必须先 set 到变量 set(lst a;b;c) list(FILTER lst EXCLUDE REGEX "a")

2.空列表、空匹配结果

如果所有元素都被 EXCLUDE 过滤掉,最后变量变成空列表,不会报错:

set(lst "1;2;3") list(FILTER lst EXCLUDE REGEX ".") # 全部匹配,全部删掉 message(STATUS ">>${lst}<<") # >> <<

3.列表元素带分号;

CMake 列表分隔符就是;,如果你的元素内部含有;,list本身就已经拆分错乱,不适合用 list (FILTER)。

4.和 string (FIND 的区别)

  • list(FILTER REGEX):正则,适合简单包含、开头结尾、多模式;要注意转义
  • string(FIND):纯字面子串查找,没有正则,遇到. * +不用转义,适合不确定内容、带大量特殊符号的场景(兼容所有 CMake 版本)

纯字面删除模板(无正则,无转义烦恼,CMake 3.0 就能用):

macro(list_remove_contains LIST_VAR SUB_STR) set(_new "") foreach(_item IN LISTS ${LIST_VAR}) string(FIND "${_item}" "${SUB_STR}" _pos) if(_pos EQUAL -1) list(APPEND _new "${_item}") endif() endforeach() set(${LIST_VAR} "${_new}") endmacro()

多条件过滤示例

删除包含foo或者包含log的项,正则|代表或:

set(LST "foo.txt;bar.log;test.cpp;hello.h") list(FILTER LST EXCLUDE REGEX "foo|log") # 结果 test.cpp;hello.h

只保留以.cpp或者.h结尾的:

list(FILTER LST INCLUDE REGEX "\\.(cpp|h)$")

版本替代方案小结

  • CMake ≥3.6:优先list(FILTER),简洁一行搞定
  • CMake <3.6 / 需要忽略大小写 / 子串有大量特殊符号:foreach + string (FIND)
set(my_list "abc123;def456;abc789;xyz000") set(new_list "") foreach(item IN LISTS my_list) string(FIND "${item}" "abc" pos) if(NOT pos EQUAL -1) # 包含abc,跳过(即删除) continue() endif() list(APPEND new_list "${item}") endforeach() set(my_list "${new_list}") message("${my_list}")

快速速查表

# 保留包含 xxx list(FILTER var INCLUDE REGEX "xxx") # 删除包含 xxx list(FILTER var EXCLUDE REGEX "xxx") # 保留以 xxx 开头 list(FILTER var INCLUDE REGEX "^xxx") # 保留以 xxx 结尾 list(FILTER var INCLUDE REGEX "xxx$") # 删除 .so 文件 list(FILTER var EXCLUDE REGEX "\\.so$")

3.注意事项

  • CMake中的list是通过空格分隔的字符串表示的,因此要注意元素中是否包含空格或特殊字符。
  • 列表索引从0开始(类似 C/C++ 数组)。
  • list命令修改的是当前作用域内的列表变量,若需在父作用域或全局作用域生效,需配合PARENT_SCOPE或CACHE使用。
  • 在使用list命令时,要确保指定的list变量已经存在,否则CMake会报错。
  • CMake的list命令是大小写敏感的,因此在指定元素或索引时要保持一致。
  • 列表常用于add_executable、add_library等命令中传递源文件列表,例如:
list(APPEND SOURCES "file1.cpp" "file2.cpp") add_executable(my_app ${SOURCES})

4.set命令和list命令异同

在 CMake 中,set命令和list命令的核心区别主要体现在功能定位和操作对象上,具体可以从以下几个方面区分:

1.功能用途:通用赋值 vs 列表专项操作

set命令的核心是设置变量,可以为变量赋予任意类型的值(字符串、数字、列表、布尔值等),甚至能操作缓存变量(CACHE选项)或环境变量(PARENT_SCOPE等作用域)。

简单来说,只要是 “给某个变量赋值” 的场景,无论是普通数据还是复杂结构,都可以用set,例如:

set(APP_NAME "MyProject") # 赋值字符串 set(SOURCE_FILES main.cpp util.cpp) # 赋值列表(本质是用空格分隔的字符串) set(DEBUG ON CACHE BOOL "Debug mode") # 设置缓存变量

list命令的核心是对列表进行专项操作,只能作用于 “列表类型” 的数据(CMake 中列表本质是用空格分隔的字符串,但list命令会将其按列表逻辑处理),支持对列表进行元素添加、删除、查找、排序、拆分、合并等操作,必须通过子命令指定具体操作(如APPEND、REMOVE_ITEM、FIND等)。
例如,对已有的列表变量进行修改:

list(APPEND SOURCE_FILES module.cpp) # 向列表追加元素 list(REMOVE_ITEM SOURCE_FILES util.cpp) # 从列表删除指定元素 list(SORT SOURCE_FILES) # 对列表元素排序

2.操作对象:变量赋值 vs 列表修改

set可以创建新变量或覆盖已有变量,赋值时直接给定值,无需关注值的类型是否为列表(即使是列表,也是作为一个整体赋值给变量)。
比如,用set定义列表时,本质是将多个元素用空格拼接成字符串,存储到变量中:

set(MY_LIST item1 item2 item3) # 变量 MY_LIST 的值是 "item1 item2 item3"(列表形式的字符串)

list必须基于已有的变量(且通常假设该变量存储的是列表),通过子命令对列表的结构进行修改(增、删、改、查元素),不会直接创建变量,而是操作已有变量中的列表数据。
例如,必须先通过set定义一个列表变量,再用list对其元素进行操作:

set(MY_LIST item1 item2) # 先用 set 定义列表变量 list(INSERT MY_LIST 1 item0) # 用 list 在索引 1 处插入元素,结果 MY_LIST 变为 "item1 item0 item2"

3.常用场景:基础变量管理 vs 复杂列表处理

  • set的使用场景更通用,包括:

    • 定义项目基本信息(如项目名称、版本);
    • 收集源文件、头文件路径(以列表形式赋值,但本质是变量赋值);
    • 设置编译选项(如CMAKE_CXX_FLAGS)、缓存变量(用于用户配置)等。
  • list的使用场景更聚焦于列表的动态操作,例如:

    • 向已有源文件列表中追加特定平台的文件(list(APPEND ...));
    • 从列表中删除不需要的元素(如排除测试文件);
    • 对列表进行排序、去重、查找特定元素(list(SORT/REMOVE_DUPLICATES/FIND ...));
    • 拆分或合并列表(如list(SPLIT ...)按分隔符拆字符串为列表,list(JOIN ...)用分隔符合并列表为字符串)。

总之,set命令和list命令可以简单理解为:

  • set是 “万能赋值器”,负责给变量 “存值”,值可以是任何形式(单个值或列表),甚至能创建或修改变量的作用域(如缓存、父作用域);
  • list是 “列表处理器”,负责对 “已经存了列表值的变量” 进行 “元素级别的操作”,必须依赖已有变量,且需要通过子命令指定具体的列表操作逻辑。

5.总结

子命令功能描述示例(列表名为my_list)
APPEND向末尾添加元素list(APPEND my_list "a" "b")
PREPEND向开头添加元素list(PREPEND my_list "x")
INSERT在指定索引插入元素list(INSERT my_list 1 "mid")
REMOVE_ITEM删除指定值的元素list(REMOVE_ITEM my_list "b")
REMOVE_AT删除指定索引的元素list(REMOVE_AT my_list 0)
REMOVE_DUPLICATES去重list(REMOVE_DUPLICATES my_list)
LENGTH获取列表长度list(LENGTH my_list len)
GET获取指定索引的元素list(GET my_list 2 val)
JOIN连接元素为字符串list(JOIN my_list ";" str)
REVERSE反转列表顺序list(REVERSE my_list)
SORT按字母序排序list(SORT my_list)
CLEAR清除列表list(CLEAR temp_files)
CONCAT合并多个列表为一个列表list(CONCAT all_files src_files test_files)
TRANSFORM列表元素转换list(TRANSFORM SOURCES PREPEND "src/")

通过这些子命令,你可以灵活地操作 CMake 列表,实现源文件管理、编译选项配置、跨平台条件处理等复杂逻辑。

相关链接

  • CMake 官网 CMake - Upgrade Your Software Build System
  • CMake 官方文档:CMake Tutorial — CMake 4.0.2 Documentation
  • CMake 源码:GitHub - Kitware/CMake: Mirror of CMake upstream repository
  • CMake 源码: CMake · GitLab
  • 中文版基础介绍:CMake 入门实战 | HaHack
  • wiki:Home · Wiki · CMake / Community · GitLab

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询