cmake进阶内建变量及指令(六)

前言

cmake构建系统有一套自己的语法树

定义变量

  • 定义和取消变量的语法:
    set(variable_name variable_value) #定义变量
    set(variable_name variable_value) #改变变量的值
    unset(variable_name) #取消变量的定义
    变量名区分大小写,且值始终是string类型的。cmake中 ON、YES、TRUE、非0数字、非空字符串代表真;OFF、NO、FALSE、0、空字符串("")代表假

  • 变量引用的形式为${variable_name},在IF语句和foreach(IN LISTS)中却是IF(variable_name)和foreach(var IN LISTS variable_name)

  • 环境变量引用的形式为$ENV{variable_name}

  • 变量嵌套引用,规则为从右往左依次进行替换,例如${outer_${inner_variable}veriable}

创建sample9,创建如下setvar.cmake内容:

# CMake 最低版本号要求
cmake_minimum_required(VERSION 2.8)

# 定义变量
# 可以为一个值,也可以为多个值
set(VAR1 on)
set(VAR2 2;GREATER;1) #和set(VAR2 2 GREATER 1)等价
set(VAR3 1 GREATER 2)
set(VAR4 1)

# 引用变量
message(STATUS "this is a varibale 1 " ${VAR1})
message(STATUS "this is a varibale 2 " ${VAR2})
message(STATUS "this is a varibale 3 ${VAR2}")
message(STATUS "this is a varibale 4 ${VAR${VAR4}}")    #实际上是输出${VAR1}
IF(VAR)
message(STATUS "VAR IS tru 1 " ${VAR})
ENDIF(VAR)
IF(${VAR2}) #IF语句会先将${VAR1} 替换成 2 GREATER 1(和2;GREATER;1等价),而这是一个为true的表达式
message(STATUS "VAR IS tru 2 ${VAR2}")
ENDIF()
IF(${VAR3}) #IF语句会先将${VAR3} 替换成 1 GREATER 2 而这是一个为false的表达式
message(STATUS "VAR IS tru 3 ${VAR3}")
ENDIF()
IF(VAR3)    #VAR3 本身为1 GREATER 2 为true
message(STATUS "VAR IS tru 4 ${VAR3}")
ENDIF()
foreach(arg VAR3)   #arg在值VAR3中循环
    message(STATUS "VAR IS tru 5 ${arg}")
endforeach()
foreach(arg ${VAR3})    #foreach语句先将${VAR3}替换为1 GREATER 2,所以实际上可循环的值为1、GREATER、2
    message(STATUS "VAR IS tru 6 ${arg}")
endforeach()
foreach(arg IN LISTS VAR3)  #跟if语句一样,会把VAR3当变量处理,所以实际上可循环的值为1、GREATER、2
    message(STATUS "VAR IS tru 7 ${arg}")
endforeach()
foreach(arg IN LISTS ${VAR3}) #跟if语句一样,先将${VAR3}先进行替换,替换后的变量并没有定义,所以不进入此循环
    message(STATUS "VAR IS tru 8 ${arg}")
endforeach()
# 引用环境变量
message(STATUS "ENV IS tru " $ENV{CMAKE_INCLUDE_PATH})

依次执行如下命令

export CMAKE_INCLUDE_PATH=/usr/local
cmake -P setvar.cmake 

输出如下:

-- this is a varibale 1 on
-- this is a varibale 2 on
-- this is a varibale 3 2;GREATER;1
-- this is a varibale 4 on
-- VAR IS tru 2 2;GREATER;1
-- VAR IS tru 4 1;GREATER;2
-- VAR IS tru 5 VAR3
-- VAR IS tru 6 1
-- VAR IS tru 6 GREATER
-- VAR IS tru 6 2
-- VAR IS tru 7 1
-- VAR IS tru 7 GREATER
-- VAR IS tru 7 2
-- ENV IS tru /usr/local

cmake -P xxx.cmake 不会构建工程,只是执行cmake语法

option指令

option(var_name description defval)
定义一个变量var_name,它的默认值为defval。如果cmake参数通过-var_name=otherval方式指定了var_name的值则其值为otherval,否则为defval

# CMake 最低版本号要求
cmake_minimum_required(VERSION 2.8)

# 定义变量
option(Build_DEBUG "debug or release?" OFF)
option(Build_TEST "debug or release?" 1)
if (Build_DEBUG) 
    message(STATUS "VAR2 IS tru 1 " ${Build_DEBUG})
endif()
message(STATUS "VAR2 IS tru 2 " ${Build_TEST})

指定参数的cmake 命令 cmake -DBuild_DEBUG=OFF -P if_option.cmake;输出

-- VAR2 IS tru 2 ON

流程和循环语句

cmake语法树里面也有自己的流程控制语句。

  • IF语句,它的格式为:

if(expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
elseif([expression2])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
else([expression])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
endif([expression])

expression表达式有如下种类:

  • 变量
    1、YES,非0数字, ON,TRUE,Y,非空字符串为真
    2、NO,0,OFF,NO,FALSE,N, 空字符串(""),变量未定义为假
  • 单目逻辑表达式
    1、EXISTS
    2、COMMAND,
    3、DEFINED
    4、NOT
  • 双目逻辑表达式
    1、EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL
    2、STREQUAL, STRLESS, STRLESS_EQUAL, STRGREATER, STRGREATER_EQUAL
    3、VERSION_EQUAL, VERSION_LESS, VERSION_LESS_EQUAL, VERSION_GREATER, VERSION_GREATER_EQUAL
    4、AND
    5、OR
  • 函数表达式
    MATCHES
  • 多组合表达式
    用括号括起来
    (expr1) AND (expr2 OR (expr3))

tips:
在cmake中 ON代表真,OFF代表假
在sample9中,新建if_option.cmake内容如下:

# CMake 最低版本号要求
cmake_minimum_required(VERSION 2.8)

# 定义变量
set(VAR1 ON)
set(VAR2 OFF)
set(VAR3 1 2 4)

# IF引用变量,直接使用变量名代表对变量的引用。如果换成${变量名},则会先
# 将${变量名}替换成它的值,然后取它的值所对应的的变量的值
IF(VAR1)    #直接引用
message(STATUS "VAR IS tru  1 " ${VAR1})
ELSEIF(${VAR2}) #  ${VAR2}的值为OFF,而变量OFF未定义,所以为FALSE
message(STATUS "VAR2 IS tru 2" ${VAR2})
ELSE()
message(STATUS "VAR3 IS tru 3 " ${VAR3})
ENDIF()

if(DEFINED VAR1) #变量是否定义过了
message(STATUS "DEFINED 4 ")
endif()
if(NOT VAR2) #取变量的相反值
message(STATUS "NOT 5 ")
endif()
if(VAR3 MATCHES ";") #变量是否含有";",一般在用set()设置变量传递多个参数时,该变量都含有";"
message(STATUS "MATCHES ;")
endif()

执行命令 cmake -P if_option.cmake
输出为:

-- VAR IS tru  1 ON
-- DEFINED 4
-- NOT 5
-- MATCHES ;

foreach循环

  1. 第一种形式
    foreach(loop_var arg1 arg2 ...)
    ...
    endforeach(loop_var)
# 第一种形式 foreach 循环 i依次取后面列表中的每个值,后面列表中的值可以是纯数字或者数字与字符串的混合
foreach(I ddd ggg 2 4)
message(STATUS "CUR I is " ${I})
endforeach(I)

输出

-- CUR I is ddd
-- CUR I is ggg
-- CUR I is 2
-- CUR I is 4
  1. 第二种形式
    foreach(loop_var RANGE total)
    endforeach(loop_var)

从0开始直到total结束(包含total),这里就是对纯数字的遍历了

2、第二种形式
foreach(I RANGE 5)
message(STATUS "CUR I is " ${I})
endforeach(I)

输出:

-- CUR I is 0
-- CUR I is 1
-- CUR I is 2
-- CUR I is 3
-- CUR I is 4
-- CUR I is 5

3、第三种形式
foreach(loop_var RANGE start stop [step])
endforeach(loop_var)
从start开始直到stop结束之间的值,可以设置步进值step。也是纯数字的遍历

# 第三种形式,从1开始 5结束 步长2遍历,也是纯数字的遍历
foreach(I RANGE 1 5 2)
message(STATUS "CUR I is " ${I})
endforeach(I)

输出

-- CUR I is 1
-- CUR I is 3
-- CUR I is 5

4、第四种形式
foreach(loop_var IN [LISTS [list1 [...]]] [ITEMS [item1 [...]]])
endforeach(loop_var)

set(A 0;1)
set(B 2 3)
set(C "4 5")
set(D 6;7 8)
set(E "")
# 注意 LISTS 后面的必须是变量
foreach(X IN LISTS A B C D E)
    message(STATUS "X=${X}")
endforeach()
# 这两种方式是等价的
foreach(X IN ITEMS ${A} ${B} ${C} ${D} ${E})
    message(STATUS "X=${X}")
endforeach()

输出

-- X=0
-- X=1
-- X=2
-- X=3
-- X=4 5
-- X=6
-- X=7
-- X=8

while循环

while(condition)
....
...
endwhile(condition)

在sample9中创建while.cmake 内容为:

set(condition 1)

#while 循环
while(condition LESS 5)
message(STATUS "condition" ${condition})
set(condition 10)
endwhile(condition LESS 5)

输出

-- condition1

内建变量

  • FILE指令

文件操作相关指令,总共有如下几种情况:

1.FILE(WRITE filename "message to write"... )

在当前路径下的文件名filename名字中写入内容message to write,如果文件不存在则创建,会覆盖已存在内容

2.FILE(APPEND filename "message to write"... )

在当前路径下的文件名filename名字中写入内容message to write,如果文件不存在则创建,为追加写入

3.FILE(READ filename variable)

从当前路径的文件名filename中读取内容,并赋值给变量variable

4.FILE(GLOB variable [RELATIVE path] [globbing expressions]...)

在指定的路径[RELATIVE path]中根据指定的正则表达式[globbing expressions]搜索所有文件,将结果赋值给变量variable;...代表可以指定多个正则表达式

5.FILE(GLOB_RECURSE variable [RELATIVE path] [globbing expressions]...)

在指定的路径[RELATIVE path]中过滤掉指定的正则表达式[globbing expressions]之外的所有文件,将结果赋值给变量variable;...代表可以指定多个正则表达式

list指令

list指令和if语句一样,引用变量时也是直接使用变量名而非${变量名}

  • LENGTH返回列表的长度
    list(LENGTH <list_var><output_variable>)

  • GET返回列表中指定下标的元素;如果超出范围报错
    list(GET <list_var> <index> [<index> ...] <var1>[<var2>....])

  • APPEND添加新元素到列表中
    list(APPEND <list_var><element> [<element> ...])

  • FIND查找指定值的索引;不存在返回-1
    list(FIND <list_var><value><var>)

  • INSERT将值插入指定索引处
    list(INSERT <list_var><element_index> <element> [...])

  • REMOVE_ITEM交换两个值的位置
    list(REMOVE_ITEM <list_var> <value>[<value> ...])

  • REVERSE反转列表
    list(REVERSE <list_var>)

  • SORT排序列表
    list(SORT <list_var>)

# CMake 最低版本号要求
cmake_minimum_required(VERSION 2.8)

# 定义变量
set(VAR1 "OFF")
set(VAR2 "DD")
set(VAR3 2 GREATER 1)
# 将长度存入len2变量 为1;len3变量 为3
list(LENGTH VAR2 len2)
list(LENGTH VAR3 len3)
message(STATUS "len3 ${len3} len2 ${len2}")
# 获取指定索引(0开始)的元素;分别将索引0 1的值写入变量list_var0和list_var1处;超出范围则报错
list(GET VAR3 0 1 list_var0 list_var1)
message(STATUS "list_var0 ${list_var0} list_var1 ${list_var1}")
#将元素添加到列表中
list(APPEND VAR3 0 1)
message(STATUS "VAR3 ${VAR3}")
#查找指定值的索引,如果不存在 返回-1
list(FIND VAR3 5 var_index)
message(STATUS "var_index ${var_index}")
#插入值到指定索引处
list(INSERT VAR3 2 insert)
message(STATUS "VAR3 1 ${VAR3}")
# 交换两个值的位置
list(REMOVE_ITEM VAR3 2 insert)
message(STATUS "VAR3 2 ${VAR3}")
# 反转列表
list(REVERSE VAR3)
message(STATUS "VAR3 3 ${VAR3}")
# 排序列表
list(SORT VAR3)
message(STATUS "VAR3 4 ${VAR3}")

输出如下:

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

推荐阅读更多精彩内容