CMake_流程控制,函数和宏

语法

条件语句

在 CMake 中,你可以使用 ifelseifelseendif 来进行条件控制:

1
2
3
4
if(  )   # 执行当条件为真时的命令
elseif( ) # 执行当第一个条件为假而这个条件为真时的命令
else() # 执行当所有条件都为假时的命令
endif()

条件可以基于变量的值、是否定义了变量、文件是否存在等条件。

循环

CMake 支持 foreach 循环和 while 循环。

其中 CMake 3.0以及更高版本中,你可以使用 IN LISTSIN ITEMS 语法来明确指示 foreach 循环应该遍历的是列表变量或者是后面直接指定的项,使得 CMake 脚本更易读、写和维护。

使用 foreach 循环遍历列表中的每个项:
如果有需要遍历自己定义的变量那么

1
2
foreach(loop_var IN [LISTS <list...>] [ITEMS <items...>]...)   # 对列表中的每个项执行命令 注意ITEMS项要在LISTS后面 
endforeach()

例如:
[Pasted image 20240107175849.png]
[Pasted image 20240107180148.png]
混用的时候作用是挨个解析读取,注意一定要在 IN 后面指定是什么类型(LISTS or ITEMS)
如果想进行更细的操作可以使用定义的局部变量来进行操作,例如
上面图片中是 file,我们可以通过 file_0,或者 file_1 来分别操作 sources 和 headers
[Pasted image 20240107182731.png]
[Pasted image 20240107182805.png]
注:如果是低版本没有 IN 那么需要以${A}的形式去指定自定义变量
如果只是想在循环中指定项目元素

疑问:ITEMS 和 LISTS 的区别是什么?
答:区别是 ITEMS 是输出名字而 LISTS 是会去解析变量名

1
2
foreach(loop_var item1 item2 ... itemN)   # 对列表中的每个项执行命令
endforeach()

例如:
[Pasted image 20240107173220.png]
[Pasted image 20240107173156.png]

或者是遍历数字

1
2
3
foreach(loop_var RANGE total)    # 命令
...
ndforeach()

使用 while 循环,直到条件为假:

1
2
while(  )   # 执行命令直到条件变为假 
endwhile()

函数和宏

函数和宏允许你定义代码块,并在需要的地方调用。

定义和调用函数:

1
2
3
function(my_func_name param1 param2)   # 函数体 
endfunction()
my_func_name(arg1 arg2)

定义和调用宏:

1
2
3
macro(my_macro param1 param2)   # 宏体 
endmacro()
my_macro(arg1 arg2)

函数和宏之间的主要区别在于它们如何处理变量的作用域。宏不会产生新的作用域,而函数会。

用途

If:
对于不同的操作系统进行适配需要用到判断语句:

1
2
3
4
5
if(WIN32)
add_definitions(-DWINDOWS)
elseif(UNIX)
add_definitions(-DLINUX)
endif()

While:
可以构想一个场景,比如说,你需要在一列文件中搜索某个特定的文件,并将它的路径设置为变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
set(files "file1.txt" "file2.txt" "file3.txt")
set(found FALSE)
set(i 0)

while(NOT found AND i LESS list(LENGTH files))
list(GET files ${i} current_file)
if(current_file STREQUAL "file2.txt")
set(found TRUE)
set(special_file_path ${current_file})
endif()
math(EXPR i "${i} + 1")
endwhile()

message(STATUS "Special file found at: ${special_file_path}")

foreach:
用来存储源文件名,便于后期的管理

1
2
3
4
5
set(src_files "main.cpp" "utils.cpp" "widget.cpp")

foreach(src_file IN LISTS src_files)
message(STATUS "Source file: ${src_file}")
endforeach()

Function:
用来封装命令
如上面的命令就可以封装

1
2
3
4
5
6
7
function(print_source_files)
foreach(src_file IN LISTS ARGN)#使用`ARGN`关键字来接收传递给函数的所有未命名参数。`ARGN`在函数中代表所有未处理的参数列表。
message(STATUS "Source file: ${src_file}")
endforeach()
endfunction()

set(src_files "main.cpp" "utils.cpp" "widget.cpp") print_source_files(${src_files})

或者

1
2
3
4
5
6
macro(print_source_files)
foreach(src_file IN LISTS ARGN)
message(STATUS "Source file: ${src_file}")
endforeach()
endmacro()
set(src_files "main.cpp" "utils.cpp" "widget.cpp") print_source_files(${src_files})