CMake语法结构说明

文章目录

  • 一. 组织
    • 1. 目录
    • 2. 脚本
    • 3. 模块
  • 二. 语法
    • 1. 编码
    • 2. 源文件
    • 3. 命令调用
    • 4. 命令参数
      • (1)括号参数
      • (2)带引号的参数
      • (3)未引用的参数
    • 5. 转义序列
    • 6. 变量引用
    • 7. 注释
      • (1)括号注释
      • (2)行注释
  • 三. 控制结构
    • 1. 条件块
    • 2. 循环
    • 3. 命令定义
  • 四. 变量
  • 五. 环境变量
  • 六. 列表

一. 组织

CMake输入文件以CMake语言编写在名为CMakeLists.txt的源文件中,或以.CMake文件扩展名结尾。
项目中的CMake语言源文件被组织为:

  • 目录Directories (CMakeLists.txt),
  • 脚本Scripts (<script>.cmake)
  • 模块Modules (<module>.cmake).

1. 目录

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

2. 脚本

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

3. 模块

目录或脚本中的CMake语言代码可以使用include()命令在include上下文的范围内加载<module>.CMake源文件。项目源树也可以提供它们自己的模块,并CMAKE_MODULE_PATH变量中指定它们的位置。

二. 语法

1. 编码

CMake语言源文件可以用7位ASCII文本编写,以便在所有支持的平台上实现最大的可移植性。换行符可以编码为\n\r\n,但在读取输入文件时会转换为\n
请注意,该实现是8位干净的,因此在系统API支持这种编码的平台上,源文件可以编码为UTF-8。此外,CMake 3.2及以上版本支持在Windows上以UTF-8编码的源文件(使用UTF-16调用系统API)。此外,CMake 3.0及更高版本允许在源文件中使用领先的UTF-8字节顺序标记。

2. 源文件

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'>

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

3. 命令调用

命令调用是一个名称,后面跟着用空格分隔的带括号的参数:

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

4. 命令参数

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

argument ::=  bracket_argument | quoted_argument | unquoted_argument

(1)括号参数

受Lua长括号语法启发,括号自变量将内容包含在相同长度的开头和结尾括号之间:

bracket_argument ::=  bracket_open bracket_content bracket_close
bracket_open     ::=  '[' '='* '['
bracket_content  ::=  <any text not containing a bracket_close withthe same number of '=' as the bracket_open>
bracket_close    ::=  ']' '='* ']'

左括号写为[后接零或更多=后接[。相应的右括号写为]后接相同数量的=后接]。支架不嵌套。可以始终为打开和关闭括号选择唯一的长度,以包含其他长度的关闭括号。
括号参数内容由位于左括号和右括号之间的所有文本组成,除了左括号后面的一行换行符(如果有的话)将被忽略。不执行对所附内容(如转义序列或变量引用)的评估。括号参数总是作为一个参数提供给命令调用。例如:

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.
]=])

(2)带引号的参数

带引号的参数包含位于开头和结尾双引号字符之间的内容:

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)未引用的参数

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

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

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

foreach(argNoSpaceEscaped\ SpaceThis;Divides;Into;Five;ArgumentsEscaped\;Semicolon)message("${arg}")
endforeach()

5. 转义序列

转义序列是一个\后面跟一个字符:

escape_sequence  ::=  escape_identity | escape_encoded | escape_semicolon
escape_identity  ::=  '\' <match '[^A-Za-z0-9;]'>
escape_encoded   ::=  '\t' | '\r' | '\n'
escape_semicolon ::=  '\;'

后面跟着一个非字母数字字符的\只是对文字字符进行编码,而不将其解释为语法。\t、\r或分别对制表符、回车符或换行符进行编码。A \:在任何变量引用之外对其自身进行编码,但可以在未引用的参数中用于对;而不除以其上的参数值。A\:内部变量引用对文本进行编码;

6. 变量引用

变量引用的形式为${<variable>},在带引号的参数或未带引号的自变量中进行求值。变量引用由指定变量或缓存项的值替换,或者如果两者都未设置,则由空字符串替换。变量引用可以嵌套并由内而外进行评估,例如${outer_${inner_variable}_variable}

文字变量引用可以由字母数字字符、字符/_.±、,和转义序列。嵌套引用可用于评估任何名称的变量。

  • Variables部分记录了变量名称的范围以及如何设置它们的值。
  • 环境变量引用的形式为$ENV{<variable>}
  • 缓存变量引用的形式为$cache{<variable>},并由指定ca的值替换
  • if()命令有一个特殊的条件语法,允许使用缩写形式<variable>而不是${<variable>}的变量引用。但是,环境变量总是需要被引用为$ENV{<variable>}

7. 注释

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

  • 括号注释
  • 行注释

(1)括号注释

#后面紧跟着一个括号,形成一个括号注释,由整个括号外壳组成:

bracket_comment ::=  '#' bracket_argument

例如:

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

(2)行注释

#后面没有紧跟括号,形成一个行注释,该注释一直持续到行的末尾:

line_comment ::=  '#' <any text not starting in a bracket_openand not containing a newline>

例如:

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

三. 控制结构

1. 条件块

if(),eleif(),else(),endif(),命令定义要有条件执行的代码块。

2. 循环

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

3. 命令定义

macro(),endmark(),function(),endfunction(),命令定义了要记录的代码块,以便以后作为命令调用。

四. 变量

变量是CMake语言中的基本存储单元。它们的值总是字符串类型的,尽管有些命令可能会将字符串解释为其他类型的值。set()unset()命令显式地设置或取消设置变量,但其他命令也具有修改变量的语义。变量名称区分大小写,几乎可以由任何文本组成,但我们建议使用仅由字母数字字符加上_-组成的名称。
变量具有动态范围。每个变量setunset在当前作用域中创建一个绑定:

  • 块范围:block()命令可以为变量绑定创建一个新的作用域。
  • 功能范围:function()命令创建的命令定义创建的命令在被调用时处理新变量绑定范围中记录的命令。变量setunset在此范围内绑定,并且对于当前函数及其内的任何嵌套调用都可见,但在函数返回后不可见。
  • 目录作用域:源树中的每个目录都有自己的变量绑定。在处理目录的CMakeLists.txt文件之前,CMake复制当前在父目录中定义的所有变量绑定(如果有的话),以初始化新的目录作用域。当使用CMake -P处理时,CMake脚本将变量绑定到一个“目录”范围中。
    不在函数调用内的变量setunset绑定到当前目录作用域。
  • 永久缓存:CMake存储一组单独的“缓存”变量或“缓存条目”,其值在项目构建树中的多个运行中保持不变。缓存条目有一个单独的绑定作用域,该绑定作用域仅通过显式请求进行修改,例如通过set()unset()命令的Cache选项进行修改。

在评估变量引用时,CMake首先在函数调用堆栈(如果有)中搜索绑定,然后返回到当前目录作用域中的绑定(如果有的话)。如果找到set绑定,则使用其值。如果找到“未设置”的绑定,或者没有找到绑定,CMake将搜索缓存条目。如果找到缓存条目,则使用其值。否则,变量引用的计算结果为空字符串。$CACHE{}VAR}语法可用于直接查找缓存条目。

五. 环境变量

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

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

六. 列表

尽管CMake中的所有值都存储为字符串,但在某些上下文中,例如在评估未引用的参数时,字符串可能会被视为列表。在这样的上下文中,字符串通过在上进行拆分而被划分为列表元素;不在[]字符数不相等且前面不紧跟\的字符。序列\:不划分值,但替换为:在得到的元素中。
元素列表通过连接由:分隔的元素来表示为字符串;例如,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"

通常,列表不支持包含以下内容的元素:字符。为避免出现问题,请考虑以下建议:

  • 许多CMake命令、变量和属性的接口都接受分号分隔的列表。避免将包含分号元素的列表传递给这些接口,除非它们记录了直接支持或某种转义或编码分号的方式。

  • 构造列表时,用未使用的占位符替换:在元素中。然后替换:用于处理列表元素时的占位符。例如,以下代码使用|代替:字符:

    set(mylist a "b|c")
    foreach(entry IN LISTS mylist)string(REPLACE "|" ";" entry "${entry}")# use "${entry}" normally
    endforeach()
    
  • 在生成器表达式列表中,使用$<SEMICON>生成器表达式。

  • 在命令调用中,尽可能使用带引号的参数语法。被调用的命令将接收保留分号的参数内容。未引用的参数将以分号分隔。

  • function()实现中,避免使用ARGVARGN,因为它们不区分值中的分号和分隔值的分号。相反,更喜欢使用命名的位置参数以及ARGCARGV#变量。使用cmake_parse_arguments()解析参数时,首选其parse_ARGV签名,该签名使用ARGV#变量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/113762.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线性代数-Python-02:矩阵的基本运算 - 手写Matrix及numpy中的用法

文章目录 一、代码仓库二、矩阵的基本运算2.1 矩阵的加法2.2 矩阵的数量乘法2.3 矩阵和向量的乘法2.4 矩阵和矩阵的乘法2.5 矩阵的转置 三、手写Matrix代码Matrix.pymain_matrix.pymain_numpy_matrix.py 一、代码仓库 https://github.com/Chufeng-Jiang/Python-Linear-Algebra-…

Golang笔记

01 = 和 := 的区别? 前者是赋值变量,后者是定义变量 02 指针的作用 指针指向变量的地址,在64位机器上占8个字节 【1 字节(Byte)= 8 位(bit) 1 千字节(KB,Kilobyte)= 1,024 字节(2^10 字节)】 作用 取址然后取值swap函数 交换变量的值指针接收器来改变结构体里面…

Python机器学习入门指南

前言 机器学习 作为人工智能领域的核心组成&#xff0c;是计算机程序学习数据经验以优化自身算法&#xff0c;并产生相应的“智能化的”建议与决策的过程。 一个经典的机器学习的定义是&#xff1a; A computer program is said to learn from experience E with respect to …

【Edabit 算法 ★☆☆☆☆☆】 Return Something to Me!

【Edabit 算法 ★☆☆☆☆☆】 Return Something to Me! strings language_fundamentals Instructions Write a function that returns the string "something" joined with a space " " and the given argument a. Examples giveMeSomething(“is bett…

打造属于自己的vue图标库

hfex-icon图标库 Install npm i -D hfex-icon主要提供2种使用方式 方式一 通过svg图标资源&#xff0c;借助unplugin-icons库将svg图标文件生成vue组件&#xff0c;然后通过vue组件的引入方式在vue中使用 unplugin-icons 兼容vue2和vue3 在vue.config.js的plugins中配置…

【C语言】进阶——程序编译

目录 一&#xff1a;&#x1f512;程序环境 程序的翻译环境和执行环境 &#x1f4a1;1.1翻译环境 预编译阶段&#xff1a; 编译阶段&#xff1a; 汇编阶段&#xff1a; 链接阶段&#xff1a; &#x1f4a1;1.2运行环境 二&#xff1a;&#x1f512;预处理详解 &…

文件夹图片相似图片检测并删除相似图片

项目开源地址 pip install imagededupgit clone https://github.com/idealo/imagededup.git cd imagededup pip install "cython>0.29" python setup.py installQuick Start from imagededup.methods import PHash phasher PHash()# Generate encodings for all…

[Spring]为什么Spring动态代理默认使用CGlib,而不是JDK代理?

文章目录 原因一&#xff1a;CGlib不需要接口原因二&#xff1a;CGlib效率高原因三&#xff1a;JDK代理会导致注解失效如果希望使用JDK代理扩展AOP in Spring Boot, is it a JDK dynamic proxy or a Cglib dynamic proxy?SpringSpringBoot 原因一&#xff1a;CGlib不需要接口 …

[AUTOSAR][网络管理] 实战网络管理

文章目录 一、简介(1) 睡眠模式(2) 预睡眠模式(3) 网络模式① 重复报文状态② 常规操作状态③ 准备睡眠状态二、目录介绍三、实现方法(1)can_nm 网络管理硬件层网络管理参数代码实现思路(2)app_nm 网络网络业务层四、测试方法(1) 网络报文唤醒(2) 诊断报文唤醒五、示例…

分类预测 | Matlab实现WOA-BiLSTM鲸鱼算法优化双向长短期记忆神经网络的数据多输入分类预测

分类预测 | Matlab实现WOA-BiLSTM鲸鱼算法优化双向长短期记忆神经网络的数据多输入分类预测 目录 分类预测 | Matlab实现WOA-BiLSTM鲸鱼算法优化双向长短期记忆神经网络的数据多输入分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现WOA-BiLSTM鲸鱼算法…

力扣每日一题53:最大子数组和

题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;请你找出一个具有最大和的连续子数组&#xff08;子数组最少包含一个元素&#xff09;&#xff0c;返回其最大和。 子数组 是数组中的一个连续部分。 示例 1&#xff1a; 输入&#xff1a;nums [-2,1,-3,4,-1,2,1,…

oracle-AWR报告生成方法

AWR报告生成方法 1. 以oracle用户登陆服务器 2. 进入到要保存awr报告的目录 3. 以sysdba身份连接数据库 sqlplus / as sysdba4. 执行生成AWR报告命令 ?/rdbms/admin/awrrpt.sql5. 选择AWR报告的文件格式 6. 选择生成多少天的AWR报告 7. 选择报告的快照起始和结束ID 8. 输入生…

MongoDB深度学习

MongoDB的简介 什么是MongoDB? MongoDB是一个基于分布式文件存储的数据库&#xff0c;由C语言编写。MongoDB是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的&#xff0c;它支持的数据结构非常松散&…

面试算法31:最近最少使用缓存

题目 请设计实现一个最近最少使用&#xff08;Least Recently Used&#xff0c;LRU&#xff09;缓存&#xff0c;要求如下两个操作的时间复杂度都是O&#xff08;1&#xff09;。 get&#xff08;key&#xff09;&#xff1a;如果缓存中存在键key&#xff0c;则返回它对应的值…

【二维差分】ICPC南京 A

https://codeforces.com/gym/104128/problem/A 题意 思路 二维差分经典模型 考虑如果没有洞那么经历操作之后会剩下什么样子的袋鼠。发现上下左右移动可以看成是边界在移动&#xff0c;边界一直保持一个原初的矩形形状&#xff0c;而且上下移动和左右移动没有任何关系。一旦…

【LeetCode刷题(数据结构与算法)】:将二叉搜索树转化为排序的双向链表

将一个 二叉搜索树 就地转化为一个 已排序的双向循环链表 对于双向循环列表&#xff0c;你可以将左右孩子指针作为双向循环链表的前驱和后继指针&#xff0c;第一个节点的前驱是最后一个节点&#xff0c;最后一个节点的后继是第一个节点 特别地&#xff0c;我们希望可以 就地 完…

LAXCUS分布式操作系统是怎么实现的?

一直有网友要求讲讲LAXCUS分布式操作系统是怎么实现的&#xff0c;其实LAXCUS分布式操作系统的设计研发&#xff0c;涉及各种基础技术和底层架构&#xff0c;研发过程很漫长&#xff0c;一直在坚持&#xff0c;实现过程也非常复杂&#xff0c;尤其重要的是要保证运行过程&#…

前端 TS 快速入门之二:接口

1. 接口有什么用 通过 interface 定义接口。 检测对象的属性&#xff0c;不会去检查属性的顺序&#xff0c;只要相应的属性存在并且类型也是对的就可以。 interface IPerson {name: string;age: number; } function say(person: IPerson): void {console.log(my name is ${pers…

Elasticsearch 8.9 Master节点处理请求源码

大家看可以看ElasticSearch源码&#xff1a;Rest请求与Master节点处理流程&#xff08;1&#xff09; 这个图非常好&#xff0c;下午的讲解代码在各个类和方法之间流转&#xff0c;都体现这个图上 一、Master节点处理请求的逻辑1、节点(数据节点)要和主节点进行通讯&#xff0…

C语言常量

常量的概念 常量&#xff1a; 在程序运行期间不可以该改变的量 作用&#xff1a; 用于记录程序中不可更改的数据 常量的五种表现形式 语法&#xff1a; 1、数值常量&#xff08;整数型常量&#xff08;整数&#xff09;、实数型常量&#xff08;小数&#xff09;&#xff09…