跨平台工程构建:CMake 的使用 (二)基本语法
目录
组织结构
cmake 文件包括 CMakeLists.txt
和以 .cmake
为后缀的文件。
程序源文件最外层的 CMakeLists.txt 文件是 cmake 的入口文件,这个文件可以定义了整个工程的构建规范。它也可以使用 add_subdirectory()
命令来包含一个子文件夹,每个使用该命令添加的子文件夹中也需要有一个 CMakeLists.txt 文件。
变量
变量的包装与展开
在 cmake 中, 变量都是以字符串的形式存在的。使用 set( )
包装变量, 使用 ${}
展开变量。${}
可以嵌套使用。 使用未包装的变量会导致空展开:
1 2 3 4 5 6 7 8 9 10 |
set(var_name_1 var1) message("var_name is ${var_name_1}") set(var_name_2 var2) set(${var_name_2} var) #same as set(var2 var) set(${${var_name_2}}_x foo) #same as set(var_x foo) message("var2 is ${var2}") message("var_name_2 is ${var_name_2}") message("var_x is ${var_x}") message("empty var is ${empty_var}") |
执行结果如下:
1 2 3 4 5 |
var_name is var1 var2 is var var_name_2 is var2 var_x is foo empty var is |
列表
在cmake 中,列表是使用 空格 分隔的多个字符串 或 使用分号
;
分隔的字符串。如下:
1 2 3 4 5 6 |
# Creates a list with members a, b, c, and d set(my_list a b c d) set(my_list "a;b;c;d") # Creates a string "a b c d" set(my_string "a b c d") |
嵌套列表
1 2 3 4 5 6 7 8 9 10 |
set(list_of_lists a b c) set(a 1 2 3) set(b 4 5 6) set(c 7 8 9) foreach(list_name IN LISTS list_of_lists) foreach(value IN LISTS ${list_name}) message(${value}) endforeach() endforeach() |
注意到 foreach
里双重展开的。第一次将列表展开为子列表的名称,第二次展开为子列表的内容。
流控制
cmake 和其它语言一样拥有控制功能,不同的是,cmake 中的控制流使用 命令
来实现
条件语句 if, elseif, else
和其它语言不同的是, cmake 中的控制流没有作用域。条件块中设置的变量在endif()之后仍然存在。
1 2 3 4 5 6 7 |
if(<condition>) message("do stuff") elseif(<condition>) message("do other stuff") else() message("do other other stuff") endif() |
循环语句 foreach
常用的循环就是 foreach
了:
1 2 3 |
foreach(var ...) message("do stuff") endforeach() |
foreach 的变量参数可以是一个列表字面量,或者列表变量,也可以是二者的混合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
foreach(var foo bar baz) message(${var}) endforeach() # prints: # foo # bar # baz set(my_list 1 2 3) foreach(var ${my_list}) message(${var}) endforeach() # prints: # 1 # 2 # 3 foreach(var ${my_list} out_of_bounds) message(${var}) endforeach() # prints: # 1 # 2 # 3 # out_of_bounds |
当然,也有另一种写法,意义更明确:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
foreach(var IN ITEMS foo bar baz) message(${var}) endforeach() # prints: # foo # bar # baz set(my_list 1 2 3) foreach(var IN LISTS my_list) message(${var}) endforeach() # prints: # 1 # 2 # 3 foreach(var IN LISTS my_list ITEMS out_of_bounds) message(${var}) endforeach() # prints: # 1 # 2 # 3 # out_of_bounds |
列表变量使用 LISTS
标识 ,列表字面量使用 ITEMS
标识。
同条件语言一样,循环语句没有作用域。
方法与宏
定义一个方法的语法如下:
1 2 3 4 5 |
function(<name> [arg1 [arg2 [arg3 ...]]]) COMMAND1(ARGS ...) COMMAND2(ARGS ...) ... endfunction(<name>) # same as endfunction() |
如同 C 语言的 varargs
一样,cmake 中可以使用 ${ARGN}
来表示多个参数。方法体中有单独的作用域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function(printmsg arg) message(${arg}) foreach(var ${ARGN}) message(${var}) endforeach() set(var_in_fun "hello") endfunction(printmsg) printmsg(a b c d) message(${var_in_fun}) # takes an error: message called with incorrect number of arguments # prints: # a # b # c # d # message called with incorrect number of arguments |
注意一点,cmake 中的方法是没有返回值的。如果需要方法传出值,常用的方法如下:
1 2 3 4 5 6 7 8 9 10 11 |
cmake_minimum_required(VERSION 3.0) function(fun arg1) set(${arg1} abc PARENT_SCOPE) endfunction(fun) fun(val) message(${val}) # prints: # abc |
宏看起来和方法很像。但如同在 C 语言中一样,宏只是对某一特定字符串的展开。另外,宏没有作用域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
macro(print_list my_list) foreach(var IN LISTS my_list) message(${var}) endforeach() set(var_in_macro "world") endmacro() set(my_list a b c) set(my_list_of_numbers 1 2 3) print_list(${my_list_of_numbers}) print_list("X;Y") set(my_list d e f) print_list(${my_list}) message(${var_in_macro}) # prints: # a # b # c # a # b # c # d # e # f # world |
注释
注释分为两种:单行注释
和 块注释(括号注释)
单行注释 以 #
开始,直到行尾结束
块注释(括号注释) 以 #[[
,以 ]]
结束 。块注释可以包含一行或多行注释:
1 2 3 4 5 6 7 8 |
# 这是一行注释 message("FirstArgument\n" #参数一 这是一行注释 "SecondArgument" #参数二 这是一行注释 ) #[[ 块注释可以是一行 也可以是多行]] message("FirstArgument\n" #[[参数一 块注释]] "SecondArgument" #[[参数二 块注释]]) |