[原创] Cmake语法速览

0 源文件


  • Cmake的源码文件,可以包含命令+注释+空格+换行。
  • 以cmake编写的源文件以CMakeLists.txt命名或者以.cmake为扩展名。
  • 一般在项目源码的最顶层目录会放置CMakeLists.txt编写的整个项目的构建规则,或者通过add_subdirectory()命令把下一层源码目录的构建规则也添加进来。
  • Cmake源文件中所有有效的语句都是命令(内置的命令或者自定义的函数/宏命令)

1 注释


1.1 单行注释

语法格式如下:

#注释内容

备注:注释从#开始到行尾结束

例子:

# 这是单行注释
message("First Argument\n" # 这是单行注释 :)
        "Second Argument") # 这是单行注释.

1.2 多行注释

Cmake使用括号参数 (Bracket Argument )来实现多行注释

语法格式如下:

#[=*[注释内容]=*]

备注:其中*号表示0个或者多个=,当然左边=号的数量要等于右边=的数量

最简单格式是:

#[[注释内容]]

例子:

#[[这是多行注释!
这是多行注释! 
这是多行注释!]]
message("First Argument\n" #[[这是多行注释]] "Second Argument")

2 变量


在cmake语言中,所有的变量都是string 类型。可以使用cmake内置的set()和unset() 命令来明确的设置或者移除一个变量。

2.1 定义变量

语法格式如下:

set(变量名 变量值)

备注:变量名是大小写敏感的,变量名可以包含任何文本,官方建议只使用字母数字-和_
例子:

set(var 123)

2.2 变量的引用

语法格式如下:

${变量名}
$ENV{VAR}

备注: $ENV{VAR}是对环境变量VAR的引用,cmake支持变量嵌套引用,解引用的顺序从内到外
例子:

set(var 123)
message(" var = ${var}")
message("PATH = $ENV{PATH}")

set(inner_var foo)
set(outer_foo_var 999)
message("nest variable value is :${outer_${inner_var}_var}")

3 列表(lists)


列表也是字符串,可以把列表看做特殊的变量,这个变量有多个值,每个值用分号”;”进行分隔。

3.1 定义列表

语法格式如下:

set(列表名 值1 值2 ... 值N)
或者
set(列表名 “值1;值2; ...;值N”)

例子:

set(list_var 1 2 3 4) # list_var = 1;2;3;4
set(list_foo "5;6;7;8") # list_foo = 5;6;7;8

3.2 列表的引用

语法格式如下:

${列表名}

例子:

set(list_var 1 2 3 4) # list_var = 1;2;3;4
set(list_foo "5;6;7;8") # list_foo = 5;6;7;8
message(${list_var})#输出: 1234
message(${list_foo})#输出:5678
message("${list_var}")#输出:1;2;3;4
message("${list_foo}")#输出:5;6;7;8

备注:不加引号的引用cmake将自动在分号处进行切分成多个列表元素,并把它们作为多个独立的参数传给命令。加了引号的引用cmake不会进行切分并保持分号不动,把整个引号内的内容当作一个参数传给命令。

4 流控命令


在cmake语言中,不管是条件语句,循环语句,函数或者宏,都是命令。

4.1 操作符

用于条件/循环的表达式的操作符,这些操作符是大小写敏感的。操作符的处理优先级:

带()的表达式 > 一元 > 二元 > 逻辑

操作符类型 操作符名称
一元 EXISTS, COMMAND, DEFINED.
二元 EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL, STREQUAL,STRLESS, STRLESS_EQUAL, STRGREATER, STRGREATER_EQUAL,VERSION_EQUAL, VERSION_LESS, VERSION_LESS_EQUAL, VERSION_GREATER, VERSION_GREATER_EQUAL,MATCHES
逻辑 NOT, AND, OR

4.2 布尔常量值

Cmake中的布尔常量值也是大小写敏感的。

类型
true 1, ON, YES, TRUE, Y, 非0的值
false 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, 空字符串””, 以-NOTFOUND 结尾的字符串

4.3 条件命令

语法格式如下:

if(表达式)
  # 要执行的命令块
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
elseif(表达式2)
  # 要执行的命令块
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
else(表达式)
  # 要执行的命令块
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
endif(表达式)

备注:elseif 和else部分是可选的,也可以有多条elseif ,这些是根据你的实际的业务需求来选择的。缩进和空格对语句解析没有影响。
例子:

set(if_tap OFF)
set(elseif_tap ON)

if(${if_tap})
    message("这是 if 表达式")
elseif(${elseif_tap})
    message("这是 elseif 表达式")
else(${if_tap})
    message("这是 else 表达式")
endif(${if_tap})

4.4 循环命令

语法格式如下:

while(表达式)
  # 要执行的命令块
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
endwhile(表达式)

备注:循环可以用break()命令退出,continue()命令可以跳过下面的语句块,立即进入下一次的循环迭代。
例子:

set(a "")

while(NOT a STREQUAL "xxxxx")
  set(a "${a}x")
  message("  a = ${a}")
endwhile()

4.5 循环遍历

语法格式一如下:

foreach(循环变量 参数1 参数2 ...)
  # 要执行的命令块
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
endforeach(循环变量)

备注:每次迭代设置${循环变量} = 参数N
例子:

foreach(item "A" "B" "C")
  message("  ${item}")
endforeach(item)

语法格式二如下:

foreach(循环变量 RANGE total)
  # 要执行的命令块
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
endforeach(循环变量)

备注:循环的范围从0~total

foreach(循环变量 RANGE  start stop [step])
  # 要执行的命令块
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
endforeach(循环变量)

备注:循环的范围从start ~stop ,循环增量为step
例子:

foreach(x RANGE 10)
  message("  ${x}")
endforeach(x)

foreach(x RANGE 10 14 2)
  message("  ${x}")
endforeach(x)

语法格式三如下:

foreach(loop_var IN [LISTS [list1 [...]]]
                    [ITEMS [item1 [...]]])

备注:foreach支持对列表的遍历
例子:

set(list_var "1;2;3;4")
foreach(x IN LISTS list_var)
  message("  ${x}")
endforeach(x)

备注:同样foreach也支持break(),continue()命令操作

5 命令


Cmake支持很多内置的命令,像我们之前使用的set,message,if,while,foreach等待都是内置的命令。也可以自定义命令。命令可以带字符串参数,但是没有还回值。命令名是大小写不敏感的,所以SET和set表示同一个命令,但是命令带的参数名是大小写敏感的ARG和arg是两个不同的参数。

5.1 自定义命令

自定义函数命令格式如下:

function(<name> [arg1 [arg2 [arg3 ...]]])
# 自定义命令块
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
endfunction(<name>)

备注:定义了一个函数名为name,参数为arg1, arg2, arg3, ...的函数命令。参数之间用空格进行分隔,如果某一参数里面包含空格最好用双引号把该参数包起来(引号内的所有字符串只当作一个参数),比如”arg1”。如果不指定参数列表,则函数可以接受任意的参数,ARGC内置变量表明传人参数的个数,ARGV0, ARGV1, ARGV2, ...内置变量可以获得对应传入的参数,ARGV内置变量可以获得整个参数列表

命令的调用格式如下:

name(实参列表)

例子:

function(foo x y z)
  message("Calling function 'foo':")
  message("  x = ${x}")
  message("  y = ${y}")
  message("  z = ${z}")
  message("ARGC = ${ARGC} arg1 = ${ARGV0} arg2 = ${ARGV1} arg3 = ${ARGV2} all args = ${ARGV}")
endfunction(foo)

foo("1" "2" "3")

自定义宏命令格式如下:

macro(<name> [arg1 [arg2 [arg3 ...]]])
  COMMAND1(ARGS ...)
  COMMAND2(ARGS ...)
endmacro(<name>)

备注:宏和函数的基本上是一样的,只是说函数命令有自己的作用域,宏命令的作用域和调用者的作用域一样。

6 变量的作用域


Cmake里面有三种作用域,全局层的,目录层的,函数层的。

  • 全局层:cache变量,在整个项目范围之内可见,一般在用set定义变量的时候指定CACHE参数就能定义为cache的变量。
  • 目录层:在当前目录CMakeLists.txt中定义,及在该文件中包含进来的(通过include或者macro引进的)其他的cmake源文件中定义的变量属于目录层这一级的作用域。
  • 函数层:在命令函数中定义的变量,属于函数作用域内的变量。

其中全局层的 < 目录层的 < 函数层的

  • <之后的层定义的变量将覆盖掉<之前层定义的变量。
  • 引用一个变量会先在当前层的作用域查找该变量的值,只有当前层找不到该变量的值,才会去上一层的作用域查找。比如在function命令中要引用一个变量,它会先查看该函数是否有“set”该变量如果有的话就用,如果没有的话就要往上一层比如当前的目录层(也有可能是调用它的另一个函数),查看是否有“set”该变量如果有的话就用,如果在当前目录层及父目录层都没找到的话,就去找是否有对应的同名cache变量如果有的话就用,都没找到就是空值。
  • 在当前作用域修改了上一层作用域的变量,并不会传递到上一层的作用域(当前作用域只是复制上一作用域的全部变量到自己的作用域在进行修改),比如在函数命令中对目录层作用域定义的一个变量进行修改,并不会影响目录层中该变量的值。

备注:如果修改时通过set命令明确指定PARENT_SCOPE参数,修改的变量作用域就是在上一层作用域,而不是当前作用域。

参考文献


[1] https://cmake.org/cmake/help/v3.10/manual/cmake-language.7.html#id9
[2] http://preshing.com/20170522/learn-cmakes-scripting-language-in-15-minutes/
[3] https://cgold.readthedocs.io/en/latest/overview.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容

  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,159评论 2 33
  • CMake学习 本篇分享一下有关CMake的一些学习心得以及相关使用。 本文目录如下: [1、CMake介绍] [...
    AlphaGL阅读 12,246评论 11 79
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy阅读 9,516评论 1 51
  • 绝文,4000汉字无一重复!!厉害 “只学一篇韵文便识天下汉字”,这句话说的似乎大了,但事实的确如此。 郑州大学郭...
    一帆闲阅读 256评论 0 0
  • 木棉花(kapok)是南方的特产,是广州市、高雄市以及攀枝花市的市花。花掉落后,树下落英纷陈,花不褪色、不萎靡,很...
    五月成长笔记阅读 479评论 0 1