cmake:cmake-language

1059 篇文章 285 订阅

组织

CMake输入文件以CMake语言写在名为CMakeLists.txt的源文件中,或者以.CMake扩展名结尾的文件中

项目中的CMake语言源文件被组织为:

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

Directories

  • 当CMake处理一个项目源树时,入口点是顶级源目录中的一个名为CMakeLists.txt的源文件。
  • 这个文件可能包含整个构建规范,或者使用add_subdirectory()命令向构建添加子目录。
  • 该命令添加的每个子目录还必须包含一个CMakeLists.txt文件作为该目录的入口点。
  • 对于处理CMakeLists.txt文件的每个源目录,CMake在构建树中生成一个响应的目录,作为默认的工作和输出目录。

Scripts

  • 单个< script>.cmake源文件可以通过使用带有-P选项的cmake(1)命令行工具在脚本模式下进行处理。
  • 脚本模式只是在给定的CMake语言源文件中运行命令,并不生成生成系统。它不允许使用CMake命令来定义构建目标或操作。

Modules

  • 【Directories 】或【Scripts】中的CMake语言代码可以使用include()命令在include上下文的范围内加载< module>.CMake源文件。请参阅cmake模块(7)手册页,了解cmake发行版中包含的模块文档。
  • 项目源树还可以提供自己的模块,并在 CMAKE_MODULE_PATH 变量中指定它们的位置。

语法

编码

  • CMake Language源文件可以用7位ASCII文本编写,以便在所有支持的平台上实现最大的可移植性。换行可以被编码为\n或\r\n,但当读取输入文件时将被转换为\n。
  • 注意,这个实现是8位的,所以在支持这种编码的系统api平台上,源文件可以被编码为UTF-8。

源文件

CMake语言源文件由零个或多个由换行符分隔的【命令调用】以及可选的空格和【注释】组成:

 file         ::=  file_element*
file_element ::=  command_invocation line_ending |
                  (bracket_comment|space)* line_ending
line_ending  ::=  line_comment? newline
space        ::=  <match '[ \t]+'>
newline      ::=  <match '\n'>

请注意,任何不在【命令参数】或括号注释内的源文件行都可以以行注释结束。

命令调用

命令调用是一个名称,后跟由空格分隔的paren封闭参数:

command_invocation  ::=  space* identifier space* '(' arguments ')'
identifier          ::=  <match '[A-Za-z_][A-Za-z0-9_]*'>
arguments           ::=  argument? separated_arguments*
separated_arguments ::=  separation+ argument? |
                         separation* '(' arguments ')'
separation          ::=  space | line_ending

例如:

add_executable(hello world.c)
  • 命令名称不区分大小写。
  • 参数中嵌套的不带引号的圆括号必须保持平衡。
  • 每个(或)都作为一个【无引号的实参】赋给命令调用。

这可以用于调用if()命令来封装条件。例如:

if(FALSE AND (FALSE OR TRUE)) # evaluates to FALSE

命令参数

在【命令调用】中有三种类型的参数:

argument ::=  bracket_argument | quoted_argument | unquoted_argument

bracket_argument(括号参数)

一个括号参数,受Lua长括号语法的启发,将内容括在相同长度的开始和结束“括号”之间:

bracket_argument ::=  bracket_open bracket_content bracket_close
bracket_open     ::=  '[' '='* '['
bracket_content  ::=  <any text not containing a bracket_close with
                       the same number of '=' as the bracket_open>
bracket_close    ::=  ']' '='* ']'
  • 左括号被写成[后跟0或多个=后跟[。相应的右括号写为],后面跟着相同数目的=,后面跟着]
  • 括号参数内容包括在开始和结束括号之间的所有文本,除非紧跟在开始括号之后的换行符(如果有的话)被忽略。不会对包含的内容(如转义序列或变量引用)执行计算。方括号参数总是作为一个参数给命令调用。

例子:

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(引号参数)

用双引号括起来的参数将内容括在双引号的开始和结束字符之间:

quoted_argument     ::=  '"' quoted_element* '"'
quoted_element      ::=  <any character except '\' or '"'> |
                         escape_sequence |
                         quoted_continuation
quoted_continuation ::=  '\' newline

引用的参数内容包括在开始和结束引号之间的所有文本。转义序列和变量引用都会被计算。带引号的参数总是作为一个参数提供给命令调用。

例如:

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.\
")

注意:3.0之前的CMake版本不支持使用\继续。如果引用的参数包含以奇数个\字符结尾的行,则报告错误。

无引号的参数

非引号参数不包含在任何引号语法中。它不能包含任何空格,(,),#,"或\,除非用反斜杠转义:

unquoted_argument ::=  unquoted_element+ | unquoted_legacy
unquoted_element  ::=  <any character except whitespace or one of '()#"\'> |
                       escape_sequence
unquoted_legacy   ::=  <see note in text>

不带引号的参数内容由允许或转义字符的连续块中的所有文本组成。转义序列和变量引用都会被计算。结果值的划分方式与list划分元素的方式相同。每个非空元素都作为参数提供给命令调用。因此,一个未带引号的参数可以作为零个或多个参数提供给命令调用。

例如:

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  ::=  '\' <match '[^A-Za-z0-9;]'>
escape_encoded   ::=  '\t' | '\r' | '\n'
escape_semicolon ::=  '\;'

后跟非字母数字字符的\只对文字字符进行编码,而不将其解释为语法。一个\t、\r或\n分别编码制表符、回车符或换行符。一个;外部的任何变量引用本身编码,但可以在无引号参数中使用;而不需要在上面划分参数值。一个;inside变量引用编码文字;的性格

变量引用

变量引用的形式为${<variable>},并且在带引号参数或不带引号参数中计算。变量引用被替换为该变量的值,如果没有设置该变量,则替换为空字符串。变量引用可以嵌套并由内到外计算,例如${outer_${inner_variable}_variable}

字面值变量引用可以包含字母数字字符,字符·/_.+-和转义序列。嵌套引用可用于计算任何名称的变量。也请参阅政策CMP0053文档,了解历史考虑和为什么$在技术上也是允许的,但不鼓励的原因。

【Variables】部分记录变量名的范围以及如何设置它们的值。

环境变量引用的格式为$ENV{<variable>}。有关详细信息,请参见环境变量部分。

缓存变量引用的格式为$cache{<variable>}。有关详细信息,请参见缓存。

if()命令有一个特殊的条件语法,允许使用缩写形式<variable>而不是${<variable>}的变量引用。但是,环境和缓存变量总是需要被引用为$ENV{<variable>}$cache{<variable>}

注释

注释以#字符开头,该字符不在方括号参数、带引号的参数中,也不作为不带引号的参数的一部分用\转义。有两种类型的注释:括号注释和行注释。

括号注释

紧跟在bracket_open后面的#构成了一个由整个括号括起来的括号注释:

bracket_comment ::=  '#' bracket_argument

例子:

#[[这是一个括号注释。
它一直运行到右括号。]]
message("First Argument\n" #[[Bracket Comment]] "Second Argument")

注意3.0之前的CMake版本不支持括号注释。它们将开头#解释为行注释的开始。

行注释

没有紧跟bracket_open的#会形成行注释,一直运行到行尾:

line_comment ::=  '#' <任何不以括号开头的文本
						不包含换行符>

例子:

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

流程控制

条件块

if()/elseif()/else()/endif()命令将有条件执行的代码块分隔开。

循环

foreach()/endforeach()和while()/endwhile()命令分隔要在循环中执行的代码块。在这样的块中,break()命令可以用来提前终止循环,而continue()命令可以用来立即开始下一个迭代。

命令定义

macro()/endmacro()和function()/endfunction()命令将代码块分隔,以便稍后作为命令调用。

变量

变量是CMake语言中最基本的存储单元。它们的值总是字符串类型,尽管有些命令可能将字符串解释为其他类型的值。set()和unset()命令显式地设置或取消设置变量,但其他命令也有修改变量的语义。变量名区分大小写,可以包含几乎任何文本,但我们建议只包含字母数字字符加上_和-的名称。

变量具有动态作用域。每个变量“set”或“unset”在当前作用域内创建一个绑定:

  • 函数作用域:
    • 由function()命令创建的【命令定义】创建命令,在调用时,这些命令将在新的变量绑定作用域内处理记录的命令
    • 变量“set”或“unset”绑定在此作用域内,对当前函数和其中的任何嵌套调用可见,但在函数返回后不可见。
  • 目录作用域
    • 源树中的每个目录都有自己的变量绑定。
    • 在处理目录的CMakeLists.txt文件之前,CMake复制当前在父目录中定义的所有变量绑定(如果有),以初始化新的目录作用域
    • 使用CMake-P处理CMake脚本时,将变量绑定到一个“目录”作用域中。
    • 不在函数调用内的变量“set”或“unset”绑定到当前目录作用域。
  • 持久缓存
    • CMake存储一组单独的“cache”变量或“cache entries”,它们的值在项目生成树中的多个运行中保持不变。
    • 缓存项有一个仅由显式请求修改的独立绑定范围,如set()和unset()命令的Cache选项。

当计算变量引用时,CMake首先在函数调用堆栈(如果有的话)中搜索绑定,然后返回到当前目录作用域(如果有的话)中的绑定。

  • 如果找到一个“set”绑定,则使用它的值。
  • 如果找到一个“unset”绑定,或者没有找到绑定,CMake就会搜索一个缓存条目。
  • 如果找到一个缓存条目,就使用它的值。
  • 否则,变量引用将计算为空字符串。

$CACHE{VAR}语法可以用来进行直接的缓存条目查找。

CMake -variables(7)手册文档记录了cmake提供的许多变量,或者在项目代码设置时对cmake有意义的变量。

环境变量

环境变量和普通变量一样,有以下区别:

  • 作用域:环境变量在CMake过程中具有全局作用域。它们从不被缓存。
  • 引用:变量引用的形式为$ENV{< Variable >}
  • 初始化
    • CMake环境变量的初始值是调用进程的初始值。
    • 可以使用set()和unset()命令更改值。
    • 这些命令只影响正在运行的CMake进程,对整个系统环境没有影响。
    • 更改后的值不会写回调用流程,后续的构建或测试流程也不会看到它们。

CMake -env-variables(7)手册记录了对cmake有特殊意义的环境变量。

列表

尽管CMake中的所有值都存储为字符串,但在某些上下文中,例如在计算一个未带引用的参数时,字符串可以被视为一个列表。在这样的上下文中,一个字符串被拆分为列表元素;不跟在数量不相等的[and]字符后面且前面不直接跟一个\的字符。

元素列表通过连接以;分隔的元素来表示为字符串。例如,set()命令将多个值以列表的形式存储到目标变量中:

set(srcs a.c b.c c.c) # sets "srcs" to "a.c;b.c;c.c"

列表用于简单的用例,例如源文件列表,不应用于复杂的数据处理任务。大多数构造列表的命令不会转义;列表元素中的字符,从而展平嵌套列表:

set(x a "b;c") # sets "x" to "a;b;c", not "a;b\;c"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值