完整的CMake指南。 第一部分:语法


引言


CMake是一组开放且跨平台的实用程序,旨在自动执行C / C ++中的测试,编译和创建项目包。 通过编写每个人都可以理解的小脚本,您将确保在有CMake的任何平台上,您的项目都具有相同的构建。


CMake语言被翻译成本地程序集文件(例如,Makefile或Ninja),定义了所有项目管理的过程。 在职能方面,只有您可以将团队组成相当复杂的结构。 我们将从他们开始。


CMake发布


以下是使用应练习的CMake语言的示例。 通过修改现有命令并添加新命令来试验源代码。 要运行这些示例,请从官方网站安装CMake。


队伍


CMake中的命令类似于许多编程语言中的功能。 要调用命令,必须写出它的名称,然后将其传递给括号中的参数,并用空格分隔。 在上面的示例中,六个参数被传递到message命令以输出到控制台:


 #    "CMake is the most powerful buildsystem!" message("CMake " "is " "the " "most " "powerful " "buildsystem!") 

争论


用双引号括起来的参数允许您转义并替换内部变量。 无框架的参数不允许产生此类内容,并且不能包含字符()#"\和空格,但使用起来更方便。


 #  "Hello, my lovely CMake",    "!": message("Hello, my lovely CMake\t!") #  "Hello,_my_lovely_CMake!"  : message(Hello,_my_lovely_CMake!) 

值得注意的是,参数Walk;around;the;forest会扩展到列表中,因为所有无框架的参数都会自动扩展为值列表(前提是原始参数的值由分号分隔),但是要加倍引号作为参数不会发生这种转换(分号字符会消失)。 评论中提到了此功能。


留言


注释以井号开头,并在打印行的结尾处结束。 注释包含的文本将被构建系统忽略,并且对其操作没有影响。 上面的示例还演示了注释的使用。


变数


可以通过调用set命令来定义变量,而可以通过调用unset删除unset 。 您可以通过构造${VARIABLE}来获取变量的值。 如果尚未定义变量,并且需要在某个位置获取其值,则此变量将变为空字符串。 一个例子:


 #   VARIABLE   "Mr. Thomas": set(VARIABLE "Mr. Thomas") #  "His name is: Mr. Thomas": message("His name is: " ${VARIABLE}) #  "'BINGO' is equal to: []",   "BINGO"  : message("'BINGO' is equal to: [${BINGO}]") #   VARIABLE: unset(VARIABLE) 

选件


CMake支持根据用户修改的设置选项。 选项类似于变量,由option命令设置,该命令仅包含三个参数:变量名称,变量的字符串描述以及变量的默认值( ONOFF ):


 #   `USE_ANOTHER_LIBRARY`   # "Do you want to use an another library?"   "OFF": option(USE_ANOTHER_LIBRARY "Do you want to use an another library?" OFF) 

逻辑表达式


在继续研究条件运算符和循环构造之前,有必要了解逻辑表达式的作用。 检查条件时使用逻辑表达式,并且可以采用两个值之一:true或false。 例如,表达式52 LESS 58将为true,因为52 <58。表达式88 EQUAL 88将为true, 63 GREATER 104将为false。 您不仅可以比较数字,还可以比较字符串,版本,文件,列表成员资格和正则表达式。 可以在此处找到逻辑表达式的完整列表。


条件语句


CMake中的条件运算符的工作方式与其他编程语言完全相同。 在此示例中,只有第一个条件运算符将起作用,该条件运算符将检查5>1。第二和第三个条件为假,因为5不能小于或等于1。 elseifelse命令块是可选的,而endif必需的,并指示先前检查的完成。


 #  "Of course, 5 > 1!": if(5 GREATER 1) message("Of course, 5 > 1!") elseif(5 LESS 1) message("Oh no, 5 < 1!") else() message("Oh my god, 5 == 1!") endif() 

周期数


CMake中的循环类似于其他编程语言中的循环。 在上面的示例中,将VARIABLE变量的值设置为Airport ,然后依次执行四个嵌套命令,直到VARIABLE变量的值等于Airport 。 最后的第四个set(VARIABLE "Police station")命令set(VARIABLE "Police station")设置set(VARIABLE "Police station")中已检查变量的值,因此循环将在到达第二次迭代之前立即停止。 endwhile命令表示嵌套在循环中的命令列表的完成。


 #      "VARIABLE is still 'Airport'": set(VARIABLE Airport) while(${VARIABLE} STREQUAL Airport) message("VARIABLE is still '${VARIABLE}'") message("VARIABLE is still '${VARIABLE}'") message("VARIABLE is still '${VARIABLE}'") set(VARIABLE "Police station") endwhile() 

此示例foreach工作方式如下:在该循环的每次迭代中,将从列表中为VARIABLE变量分配以下值, Give me the sugar please! 然后执行message(${VARIABLE})命令,该命令显示VARIABLE变量的当前值。 如果列表中没有值,则循环结束其执行。 endforeach命令指示嵌套在循环中的命令列表的完成。


 #  "Give me the sugar please!"   : foreach(VARIABLE Give me the sugar please!) message(${VARIABLE}) endforeach() 

编写foreach还有3种形式。 在此示例中,第一个循环生成从0到10的整数代替列表,第二个循环在3到15的范围内生成,第三个循环在从50到90的段中工作,但步长为10。


 #  "0 1 2 3 4 5 6 7 8 9 10"   : foreach(VARIABLE RANGE 10) message(${VARIABLE}) endforeach() #  "3 4 5 6 7 8 9 10 11 12 13 14 15"   : foreach(VARIABLE RANGE 3 15) message(${VARIABLE}) endforeach() #  "50 60 70 80 90"   : foreach(VARIABLE RANGE 50 90 10) message(${VARIABLE}) endforeach() 

函数和宏


CMake语法允许您定义自己的命令,这些命令可以完全调用内置命令。 下面的示例演示了函数和宏的用法:首先,使用它们自己的命令定义函数和宏,并在调用它们时按顺序执行它们的命令。


 #   "print_numbers": function(print_numbers NUM1 NUM2 NUM3) message(${NUM1} " " ${NUM2} " " ${NUM3}) endfunction() #   "print_words": macro(print_words WORD1 WORD2 WORD3) message(${WORD1} " " ${WORD2} " " ${WORD3}) endmacro() #   "print_numbers",   "12 89 225": print_numbers(12 89 225) #   "print_words",   "Hey Hello Goodbye": print_words(Hey Hello Goodbye) 

function命令将future函数的名称用作第一个参数,其余参数是可用作普通变量的参数的名称。 参数仅对所定义的函数可见,这意味着我们无法在函数外部访问其参数。 此外,在函数中定义和重新定义的所有其他变量仅对自身可见。


宏与函数相似,不同之处在于它们没有自己的作用域:宏内的所有变量都被视为全局变量。 您可以在此处阅读有关宏和函数之间差异的更多信息。


注释中所述,CMake中的宏类似于C预处理器中的宏:如果将return命令放在宏主体中,则将退出调用函数(或整个脚本),如本示例所示:


 #  ,   : macro(demonstrate_macro) return() endmacro() #  ,   : function(demonstrate_func) demonstrate_macro() message("The function was invoked!") endfunction() #  "Something happened with the function!" demonstrate_func() message("Something happened with the function!") 

在上面的示例中, demonstrate_func函数将没有时间打印消息。 The function was invoked! 与之前一样,将替换调用宏demonstrate_macro的位置,并执行退出命令。


解析参数


注释中所述,强大的cmake_parse_arguments机制允许解析传递给函数或宏的参数。


此命令接受变量定义中使用的前缀(请参见下一段),不带后续值的选项列表,关键字后跟单个值的列表,关键字后跟值集的列表以及传递给函数的所有值的列表或宏。


参数解析机制的工作是将接收到的参数转换为变量值。 因此,为每个选项和关键字考虑的命令定义了自己的形式,形式为<Prefix>_<OptionOrKeyword> ,该变量封装了某个值。 对于选项,这些是布尔值(true-表示该选项;否则为false),对于关键字,所有传递的值都位于它们之后。


custom_function函数包含对cmake_parse_arguments的调用,然后输出某些变量的值。 接下来,使用参数LOW NUMBER 30 COLORS red green blue调用该函数,然后将其打印在屏幕上:


 function(custom_function) #       : cmake_parse_arguments(CUSTOM_FUNCTION "LOW;HIGH" "NUMBER" "COLORS" ${ARGV}) #  "'LOW' = [TRUE]": message("'LOW' = [${CUSTOM_FUNCTION_LOW}]") # "'HIGH' = [FALSE]": message("'HIGH' = [${CUSTOM_FUNCTION_HIGH}]") #  "'NUMBER' = [30]": message("'NUMBER' = [${CUSTOM_FUNCTION_NUMBER}]") #  "'COLORS' = [red;green;blue]": message("'COLORS' = [${CUSTOM_FUNCTION_COLORS}]") endfunction() #   "custom_function"   : custom_function(LOW NUMBER 30 COLORS red green blue) 

范围


在上一节中,您了解了CMake中的某些构造可以定义自己的范围。 实际上,默认情况下,所有变量均被视为全局变量(可在任何地方访问它们),但已在函数中定义和重新定义的变量除外。 也有具有自己范围的高速缓存变量 ,但使用频率不高。


如注释中所述,可以使用set(VARIABLE ... PARENT_SCOPE)命令set(VARIABLE ... PARENT_SCOPE)在“父”范围中定义set(VARIABLE ... PARENT_SCOPE) 。 此示例演示了此功能:


 # ,   "VARIABLE"   # "In the parent scope..."    : function(demonstrate_variable) set(VARIABLE "In the parent scope..." PARENT_SCOPE) endfunction() #   "VARIABLE"    : demonstrate_variable() #      "VARIABLE" : message("'VARIABLE' is equal to: ${VARIABLE}") 

如果从VARIABLE变量的定义中删除了PARENT_SCOPE ,则该变量将只能由PARENT_SCOPE函数访问,并且在全局范围内它将为空值。


结论


到此结束CMake语法。 下一篇文章将在大约两天后发布,并将介绍CMake构建系统的用法。 待会见!

Source: https://habr.com/ru/post/zh-CN431428/


All Articles