6. 列表操作:list()命令的增删改查、排序、反转、去重等操作
各位同学,今天我们来聊聊 CMake 里一个非常实用的命令——list()。
说实话,我刚接触 CMake 那会儿,觉得变量就是个存字符串的东西。后来项目越来越复杂,需要管理一堆源文件、一堆库路径、一堆编译选项……这时候才发现,没有列表操作,简直寸步难行。
list() 命令,说白了就是 CMake 给咱们提供的“数组工具箱”。它支持增、删、改、查、排序、反转、去重……基本上你能想到的操作,它都有。
好,咱们直接开干。
6.1 列表的创建与基本操作
在 CMake 里,列表其实就是一个用分号 ; 分隔的字符串。比如:
set(MY_LIST a b c d)
# 等价于 set(MY_LIST a;b;c;d)
但直接用 set()list() 命令。
6.1.1 获取列表长度
list(LENGTH MY_LIST len)
message("列表长度: ${len}")
这个 LENGTH 子命令会把长度存到 len 变量里。我在项目中经常用它来判断列表是否为空——如果长度为 0,就跳过某些处理逻辑。
6.1.2 获取列表中的元素
list(GET MY_LIST 0 2 first third)
message("第一个元素: ${first}")
message("第三个元素: ${third}")
注意,索引从 0 开始。GET 后面可以跟多个索引,一次性取出多个元素。
6.1.3 查找元素位置
list(FIND MY_LIST "b" index)
message("b 的位置: ${index}")
如果找不到,index 会被设为 -1。嗯,这个设计很符合直觉。
6.2 增删改操作
这部分是我用得最多的。尤其是动态拼接源文件列表的时候。
6.2.1 追加元素
list(APPEND MY_LIST "e" "f")
# MY_LIST 现在变成 a;b;c;d;e;f
APPEND 是在列表末尾添加元素。如果你想把元素插入到开头,用 PREPEND(CMake 3.15+ 支持)。
6.2.2 插入元素到指定位置
list(INSERT MY_LIST 2 "x")
# 在索引 2 的位置插入 x,MY_LIST 变成 a;b;x;c;d;e;f
我曾经在重构一个大型项目时,需要把新加的源文件插入到列表中间某个位置,INSERT 帮了大忙。
6.2.3 删除元素
list(REMOVE_ITEM MY_LIST "b")
# 删除所有值为 "b" 的元素
list(REMOVE_AT MY_LIST 0 2)
# 删除索引 0 和 2 的元素
list(REMOVE_DUPLICATES MY_LIST)
# 去重
这里有个坑:REMOVE_ITEM 是按值删除,REMOVE_AT 是按索引删除。别搞混了。我曾经在代码里写错了,结果删了一堆不该删的东西……嗯,调试了半天。
6.2.4 修改元素
list(POP_FRONT MY_LIST)
# 弹出第一个元素
list(POP_BACK MY_LIST)
# 弹出最后一个元素
这两个命令会把弹出的值存到指定变量里,比如 list(POP_FRONT MY_LIST head),head 就是被弹出的元素。
list(GET ...) 配合索引 0 或 -1。
6.3 排序、反转与去重
这三个操作,说白了就是“整理数据”。
6.3.1 排序
list(SORT MY_LIST)
# 默认按字母顺序升序排列
list(SORT MY_LIST COMPARE STRING)
# 明确指定按字符串比较
list(SORT MY_LIST COMPARE FILE_BASENAME)
# 按文件名排序(去掉路径前缀)
排序时还可以指定 CASE(大小写敏感)和 ORDER(升序/降序)。比如:
list(SORT MY_LIST ORDER DESCENDING)
# 降序排列
我个人习惯在生成源文件列表后,先排个序,这样编译输出也更有规律。
6.3.2 反转
list(REVERSE MY_LIST)
# 把列表顺序完全颠倒过来
这个命令很简单,但很实用。比如你有一个按时间顺序排列的日志文件列表,想从最新的开始处理,反转一下就行。
6.3.3 去重
list(REMOVE_DUPLICATES MY_LIST)
# 删除重复元素,保留第一次出现的那个
去重操作会改变列表顺序。如果你需要保持原有顺序,建议先去重再排序。
6.4 列表操作的知识体系
下面这张图总结了 list() 命令的核心操作分类,方便你快速查阅:
6.5 实战:一个完整的列表操作示例
咱们来看一个实际场景。假设你有一个源文件列表,需要做以下处理:
- 添加几个新文件
- 删除一个废弃的文件
- 去重(防止重复添加)
- 按字母顺序排序
- 输出最终列表
# 初始源文件列表
set(SOURCES main.cpp utils.cpp math.cpp)
# 添加新文件
list(APPEND SOURCES network.cpp database.cpp)
# 删除废弃文件
list(REMOVE_ITEM SOURCES old_utils.cpp)
# 去重
list(REMOVE_DUPLICATES SOURCES)
# 排序
list(SORT SOURCES)
# 输出结果
message("最终源文件列表: ${SOURCES}")
这段代码在实际项目中很常见。我一般会在 CMakeLists.txt 的开头定义好源文件列表,然后用 list() 命令动态调整,最后传给 add_executable() 或 add_library()。
list()是 CMake 中操作列表的唯一官方工具- 增删改查、排序、反转、去重,一应俱全
- 注意索引从 0 开始,
REMOVE_ITEM和REMOVE_AT的区别 - 排序和去重会改变列表顺序,使用时要注意副作用
好了,关于 list() 命令就讲到这里。你想想看,如果没有这个命令,咱们得用一堆 set() 和字符串拼接来模拟列表操作,那得多痛苦?
下一节咱们会聊另一个很实用的命令——foreach() 循环。到时候你会看到,list() 和 foreach() 配合起来,威力更大。