跳到主要内容

编写 CMakeLists

Ref: Writing CMakeLists Files, 语法文档

变量(Variables)

内置变量一览:cmake-variables

命名规则

  • 大小写敏感,只能包含字母,数字和下划线
  • 保留变量以CMAKE__CMAKE_或下划线_加任意CMake Command开头

设置变量

使用set命令,第一个参数是变量名,第二个参数是值,变量按set调用顺序定义

当传入多个参数时,它们会被以顿号;分隔并打包成的字符串(string)

set(Foo "")      # 1 quoted arg -> value is ""
set(Foo a) # 1 unquoted arg -> value is "a"
set(Foo "a b c") # 1 quoted arg -> value is "a b c"
set(Foo a b c) # 3 unquoted args -> value is "a;b;c"

对无引号参数,先替换再展开

即先替换为带;的字符串,然后如果没被"包裹,再展开为多个参数

set(Foo a b c)      # 3 unquoted args -> value is "a;b;c"
command(${Foo}) # unquoted arg replaced by a;b;c
# and expands to three arguments
command("${Foo}") # quoted arg value is "a;b;c"
set(Foo "") # 1 quoted arg -> value is empty string
command(${Foo}) # unquoted arg replaced by empty string
# and expands to zero arguments
command("${Foo}") # quoted arg value is empty string

环境变量

通过$ENV{VAR}访问环境变量,在 Windows 中可通过[HKEY_CURRENT_USER\\Software\\path1\\path2;key]访问注册表

作用范围

作用范围是 scope,定义的变量可以作用于当前及所有下游的 scope。下游 scope 在处理新 subdirectory 或调用 function 时产生,其会用当前的全部变量初始化一个新的 scope。所有对 scope 的更改,不会影响上游的 scope.

function(foo)
# child scope
message(${test}) # test is 1 here
set(test 2) # not affect top level scope
message(${test}) # test is 2 here, but only in this scope
endfunction()

# top level scope
set(test 1)
# enter function scope with test = 1
foo()
# still top level scope
message(${test}) # test will still be 1 here

若想修改上游 scope 变量,可使用PARENT_SCOPE,但它不会修改当前 scope 的变量。

function(foo)
message(${test}) # test is 1 here
set(test 2 PARENT_SCOPE)
message(${test}) # test still 1 in this scope
endfunction()

set(test 1)
foo()
message(${test}) # test will now be 2 here

命令(Commands)

内置命令可参考:cmake-commands

命令依次由命令名,左括号,空格分隔的参数及右括号构成。

  • 命令名不区分大小写,但推荐使用小写
  • 命令的编写中会忽略所有的除分隔变量的空格,换行,tab 等空白符号。只要命令名与左括号在同一行就行。
  • 参数大小写敏感,由双引号"包裹的视为单个参数,若参数中含有",需使用反斜杠\转译,或使用方括号参数(CMake 3.0+),以[一个以上的=,和[开头,以]同样数量的=,和]结尾。其中的反斜杠与变量都不会被解释

更多语法可参考 Syntax

command("")          # 1 quoted argument
command("a b c") # 1 quoted argument
command("a;b;c") # 1 quoted argument
command("a" "b" "c") # 3 quoted arguments
command(a b c) # 3 unquoted arguments
command(a;b;c) # 1 unquoted argument expands to 3
# 1 bracket argument, multi-line
command([=[
"No \-escape sequences" and ${no_evaluated_var}
]=])

流控制

if

condition常量时,1, ON, YES, Y或任意不为零的数(包括浮点数)时为真,0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, 空字符串,或以-NOTFOUND结尾的字符串时为假。如果常量不满足以上条件,则按变量或字符串规则处理。

condition变量时,有定义,且不为以上假常量时为真,反之为假

可用条件语法可参考:Condition Syntax

if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()

更详细语法可参考:if

foreach/while

foreach 的第一个参数是在循环中使用的循环变量的变量名,之后的参数是循环变量的值的列表

foreach(<iter variable name>
<loop value 1>
<loop value 2>
...
)
command(${<iter variable name>})
endforeach()

while 可通过条件使用循环

while(<condition>)
command()
endwhile()

foreach循环中,循环变量比其他变量都更早替换,因此可以实现可变变量名

foreach(<iter var>)
command(${changing_${<iter var>}_var})
endforeach()

foreach 和 while 中都可以用 break()continue()

更详细语法可参考:foreach, while

流定义

函数(function)

使用function命令创建函数,其第一个参数为函数名,之后所有的参数为函数参数(formal arguments)。

在调用函数时,可传入大于已定义参数的参数,此时,可通过ARGV0, ARGV1...调用。formal arguments 既可通过参数名调用,也可用通过ARGV的方式调用。特别地,ARGC表示所有传入参数的数量,包括 formal argumentsARGV表示所有传入参数的列表,ARGN表示除 formal arguments 外传入参数的列表,ARGVARGN可通过foreach遍历。

function(<function name>
<param name 1>
<param name 2>
...
)
command(<param name 1> <param name 2>)
endfunction()

当调用函数时,会继承父 scope,并生成新 scope,返回后,这个 scope 会被丢弃,也就是说,所有在函数中对变量中做的修改都不会影响父 scope

可使用PARENT_SCOPE修改父 scope 的变量,作为函数返回。在下面的例子中,函数通过_time拿到变量current_timeset通过PARENT_SCOPE参数设置调用者的 scope 中的current_time

function(DetermineTime _time)
# pass the result up to whatever invoked this
set(${_time} "1:23:45" PARENT_SCOPE)
endfunction()

# now use the function we just defined
DetermineTime(current_time)

if(DEFINED current_time)
message(STATUS "The time is now: ${current_time}")
endif()

可使用return返回

更详细语法可参考:function

宏(macro)

macro命令与函数命令使用方法一样,但是宏在当前 scope 运行,不会生成新的 scope,在调用时,会直接将变量解析为字符串并替换,并且无法使用return

# define a simple macro
macro(assert TEST COMMENT)
if(NOT ${TEST})
message("Assertion failed: ${COMMENT}")
endif()
endmacro()

# use the macro
find_library(FOO_LIB foo /usr/local/lib)
assert(${FOO_LIB} "Unable to find library foo")

更详细语法可参考:macro

正则表达式

部分命令,如 if, string 可使用正则表达式,实现如匹配,截取,替换字符串的功能。

详细语法可参考:string