0%

cmake语法简介

CMake意为cross-platform make,可用于管理c/c++工程。
CMake解析配置文件CMakeLists.txt生成Makefile,相比直接用Makefile管理工程,CMake更灵活和简单。

结构

Cmake的输入是源码目录下的 ‘CMakeLists.txt’ 文件,或者后缀为’.cmake’。
这个文件可以用 ‘include’ 或者 ‘add_subdirectory’ 命令增加入其它的输入文件。组织结构有以下几部分组成:

  • Directories (CMakeLists.txt)
  • Scripts (<script>.cmake)
  • Modules (<module>.cmake)

Directories

顶层目录下的 ‘CMakeLists.txt’ 文件可以使用命令 ‘add_subdirectory’ 来添加子目录,
此子目录下必须存在 ‘CMakeLists.txt’ 文件

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

Scripts

脚本模式可以使用以下命令运行给定的CMake源文件中的命令,但是不会构建系统。

cmake [<options>] (<path-to-source> | <path-to-existing-build>)
cmake [(-D<var>=<value>)...] -P <cmake-script-file>
cmake --build <dir> [<options>] [-- <build-tool-options>...]
cmake -E <command> [<options>]
cmake --find-package <options>...

Modeles

使用命令 ‘include’ 来导入 ‘.cmake’ 源文件

include(<file|module> [OPTIONAL] [RESULT_VARIABLE <VAR>] [NO_POLICY_SCOPE])

语法

编码

使用7-bit ASCII进行编码,新行可使用 ‘\n’ 或 ‘\r\n’,将被转换为 ‘\n’ 做为输入文件读取

源文件

CMakeList.txt文件是由注释、命令和空白字符组成。

命令调用

命令是由:命令名、(、空格分隔的参数、)组成。
‘CMakeLists.txt’ 文件中命令调用大小写不敏感的。 例如:

command (args….)

上面的command可以是一个命令名;或者是一个宏;也可以是一个函数名。

命令参数

args是以空格分隔的参数例表(如果参数中包含空格,则要加双引号)

除了用于分隔参数的空白字符(空格、换行号、tabs)都是被忽略不计的。任何包含在双引号中的字符都做为一个参数。

三种参数类型:括号、引号和普通

Bracket Argument:

message([=[
This is the first line in a bracket argument with bracket length 1.
No \-escape sequences or ${variable} references are evaluated.
This is always one argument even though it contains a ; character.
The text does not end on a closing bracket of length 0 like ]].
It does end in a closing bracket of length 1.
]=])

Quoted Argument:

message("This is a quoted argument containing multiple lines.
This is always one argument even though it contains a ; character.
Both \\-escape sequences and ${variable} references are evaluated.
The text does not end on an escaped double-quote like \".
It does end in an unescaped double quote.
")

可以在行尾添加 ‘' 进行行连接,例如:

message("\
This is the first line of a quoted argument. \
In fact it is the only line but since it is long \
the source code uses line continuation.\
")

Unquoted Argument:

foreach(arg
        NoSpace
        Escaped\ Space
        This;Divides;Into;Five;Arguments
        Escaped\;Semicolon
    )
    message("${arg}")
endforeach()

前两种都是提供一个参数,而且不会进行转义,最后一个需要注意转义!

转义

‘'后跟的部分字符进行转义:

escape_sequence  ::=  escape_identity | escape_encoded | escape_semicolon
escape_identity  ::=  '\(' | '\)' | '\#' | '\"' | '\ ' |
                    '\\' | '\$' | '\@' | '\^'
escape_encoded   ::=  '\t' | '\r' | '\n'
escape_semicolon ::=  '\;'

‘(‘,’)’,’#’,’”‘,’ ‘,’',’$’,‘@’,’^’ 进行简单转义;’\t’ : tab ‘\r’ : return ‘\n’ : newline;’;‘ 用于参数中不表示隔离参数

变量引用

变量引用的形式为 ‘${variable_name}’,替换为变量的值,或空字符串(变量未赋值)。

变量引用可以嵌套,从内到外展开,例如 ‘${outer_${inner_variable}_variable}’

环境变量引用形式为 ‘$ENV{VAR}’

注释

注释由一个不是 (括号中的参数、引用参数或’'转义)一部分的’#’字符开始,有行注释和括号注释:

括号注释:

#[[This is a bracket comment.
It runs until the close bracket.]]
message("First Argument\n" #[[Bracket Comment]] "Second Argument")

行注释:

# This is a line comment.
message("First Argument\n" # This is a line comment :)
        "Second Argument") # This is a line comment.

控制结构

Conditional Blocks

# some_command will be called if the variable's value is not:
# empty, 0, N, NO, OFF, FALSE, NOTFOUND, or -NOTFOUND. 
if(var)
    some_command(...)
elseif()
    some_command(...)
else()
    some_command(...)
endif() 

Loops

set(VAR a b c) 

# loop over a, b,c with the variable f 
foreach(f ${VAR}) 
    message(${f}) 
endforeach(f)

while(condition)
    command(args ...)
    command(args ...)
endwhile(condition)

Command Definitions

macro()/endmacro() 和 function()/endfunction() 进行宏和函数的定义:

# define a macro hello 
macro(hello MESSAGE)
    message(${MESSAGE})
endmacro(hello) 

# call the macro with the string "hello world" 
hello("hello world") 

# define a function hello 
function(hello MESSAGE)
    message(${MESSAGE}) 
endfunction(hello)

Variables

变量命名大小写敏感,set()/unset()对变量进行赋值操作:

set (VAR " hello world ")   #赋值
unset (VAR)                 #取消赋值

CMake支持简单的变量:字符串或字符串列表。用${VAR} 语法得到变量的引用。

可以用一个set命令把一个字符串列表设置为一个变量,然后把这个变量传递给需要传递多参数的函数。例如:

set(Foo a b c)
command(${Foo})

上面两行等效

command(a b c)

如果你想传把一个字符串列表做为一个单独的参数传递给函数,用双引号包含它。例如:

Command(“${Foo}”)
#等效于
command(“a b c”)

环境变量:

用$ENV{VAR}得到环境变量的引用

设置环境变量:

Set(ENV{VAR} /home)

Lists

字符串(string)和字符串列表(lists)

CMake的基本数据类型是字符串(string)。
CMake也支持由字符串组成的字符串列表。字符串列表可以由;或空格分隔的组成。例如:下面设置变量var是等效的。

set(var a;b;c)
set(var a b c)

字符串列表可以用 foreach命令叠代(iterated)或list命令操作。

正则表达式

一些CMake命令(如if和 string),能使用正则表达式或使用正则表达式作为参数。
一个简单的形式,一个正则表达式用于在一个序列的字符串中精确查找一个字符。
然而在大多时候,一个精确查找是不知道的或者只是匹配最前或者最后字符。
所以这里用正则表达式进行不同的转换。
Cmake标准是可被描述的。这个描述是基于开源的正则表达式类(Texas Instruments)。

  • ^ 匹配一行或一字符串开头
  • $匹配一行或一字符串结尾
  • .匹配单一字符或一个新行
  • [ ]匹配括号中的任一字符
  • [^ ] 匹配不在括号内的任一字符
  • [-] 匹配指定范围内的字符
  • * 匹配0次或多次
  • + 匹配一次或多次
  • ? 匹配0次或一次
  • ()保存匹配的表达式并用随后的替换它

Ref

  1. cmake syntax
  2. cmake tutorial
  3. CMake常用变量列表
  4. CMake文档列表