编译原理与语法(五)——CMake语法详解
- 在Android Studio 2.2及以上,构建原生库的默认工具是CMake
- CMake是一个跨平台的支持产出各种不同的构建脚本的一个工具
- CMake并不直接构建出最终的软件,而是产生其他工具的脚本(如makefile)
注释
单行注释:
# 注释内容
多行注释:
# [[注释内容
注释内容
注释内容]]
变量
声明变量:set(变量名 变量值)
移除变量:unset(变量名)
引用变量: ${变量名}
set(var 123)
message(WARNING "var = ${var}")
结果:var = 123
message
message([<mode>] "message to display" ...)
- (none) = 重要消息
- STATUS = 附带消息
- WARNING = CMake警告,继续处理
- AUTHOR_WARNING = CMake警告(dev),继续处理
- SEND_ERROR = CMake错误,继续处理,但跳过生成
- FATAL_ERROR = CMake错误,停止处理和生成
- DEPRECATION = 如果分别启用了变量CMAKE_ERROR_DEPRECATED或CMAKE_WARN_DEPRECATED,则CMake弃用错误或警告,否则无消息
在高版本的CMake中,(none) 和 STATUS 两种级别的 message 不会直接打印出来,要使用其他级别
指定abi
abiFilters "armeabi", "armeabi-v7a" , "arm64-v8a", "x86", "x86_64", "mips", "mips64"
defaultConfig {
applicationId "com.example.myapplication"
minSdkVersion 25
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "armeabi-v7a"
}
}
}
列表
声明列表:set(列表名 值1 值2 ...值N)
声明列表:set(列表名 "值1;值2;...值N")
引用列表:${列表名}
set(list1 111 222 333)
message(WARNING "list1 = ${list1}")
set(list2 "aaa;bbb;ccc")
message(WARNING "list2 = ${list2}")
结果:
list1 = 111;222;333
list2 = aaa;bbb;ccc
流程控制
操作符
类型 | 名称 |
---|---|
一元 | EXIST,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 |
布尔常量值
类型 | 值 |
---|---|
true | 1,ON,YES,TRUE,Y,非0值 |
false | 0,OFF,NO,FALSE,N,IGNORE,NOTFOUND,空字符串,以-NOTFOUND结尾的字符串 |
条件命令
- 语法格式:
if(表达式)
COMMAND(ARGS...)
endif(表达式)
COMMAND(ARGS...)
endif(表达式)
COMMAND(ARGS...)
end(表达式)
COMMAND(ARGS...)
endif(表达式)
缩进和空格对语句没有影响
set(controloff OFF)
set(controlon ON)
if(${controloff})
message(WARNING "if")
elseif(${controloff})
message(WARNING "elseif1")
elseif(${controloff})
message(WARNING "elseif2")
else(${controloff})
message(WARNING "else")
endif(${controloff})
结果:else
循环命令
- 语法格式:
while(表达式)
COMMAND(ARGS...)
endwhile(表达式)- break()命令可以跳出整个循环,continue()可以跳出当前循环
set(a "")
while(NOT a STREQUAL "xxx")
set(a "${a}x")
message("a = ${a}")
endwhile()
结果:
a = x
a = xx
a = xxx
b = y
b = yyy
b = yyyy
循环遍历一
语法格式
foreach(循环变量 参数1 参数2 ... 参数N)
COMMAND(ARGS...)
endforeach(循环变量)
foreach(item 1 2 3)
message(WARNING "item = ${item}")
endforeach(item)
结果:
item = 1
item = 2
item = 3
循环遍历二
- 语法格式
foreach(循环变量 RANGE total)
COMMAND(ARGS...)
endforeach(循环变量)- 循环范围从0到total
foreach(item RANGE 3)
message(WARNING "item = ${item}")
endforeach(item)
结果:
item = 0
item = 1
item = 2
item = 3
循环遍历三
- 语法格式
foreach(循环变量 RANGE start stop step)
COMMAND(ARGS...)
endforeach(循环变量)- 循环范围从start到stop,循环增量为step
foreach(item RANGE 1 8 2)
message(WARNING "item = ${item}")
endforeach(item)
结果:
item = 1
item = 3
item = 5
item = 7
循环遍历四
语法格式
foreach(循环变量 IN LISTS 列表)
COMMAND(ARGS...)
endforeach(循环变量)
set(list_foreach 1 3 ass qw3dd)
foreach(item IN LISTS list_foreach)
message(WARNING "item = ${item}")
endforeach(item)
结果:
item = 1
item = 3
item = ass
item = qw3dd
自定义函数
命令格式:
function(name arg1 arg2 arg3 ...)
COMMAND()
endfunction(name)
function(func a b c)
message(WARNING "a= ${a}")
message(WARNING "b= ${b}")
message(WARNING "c= ${c}")
message(WARNING "ARGC= ${ARGC}")
message(WARNING "ARGV0= ${ARGV0}")
message(WARNING "ARGV1= ${ARGV1}")
message(WARNING "ARGV2= ${ARGV2}")
message(WARNING "ARGV3= ${ARGV3}")
message(WARNING "ARGV= ${ARGV}")
endfunction(func)
func(1 www 222)
结果:
a= 1
b= www
c= 222
ARGC= 3
ARGV0= 1
ARGV1= www
ARGV2= 222
ARGV3=
ARGV= 1;www;222
变量 | 含义 |
---|---|
ARGC | 函数有多少个参数 |
ARGV+N | N代表第几个参数 ARGV0第一个参数,ARGV2第二个参数,依次类推 |
ARGV | 打印所有的参数 |
自定义宏命令
命令格式:
macro(name arg1 arg2 arg3 ...)
COMMAND()
endmacro(name)
macro(ma x y z)
message(WARNING "x= ${x}")
message(WARNING "y= ${y}")
message(WARNING "z= ${z}")
message(WARNING "ARGC= ${ARGC}")
message(WARNING "ARGV0= ${ARGV0}")
message(WARNING "ARGV1= ${ARGV1}")
message(WARNING "ARGV2= ${ARGV2}")
message(WARNING "ARGV3= ${ARGV3}")
message(WARNING "ARGV= ${ARGV}")
endmacro(ma)
ma(1 2 3)
结果:
x= 1
y= 2
z= 3
ARGC= 3
ARGV0= 1
ARGV1= 2
ARGV2= 3
ARGV3=
ARGV= 1;2;3
与函数的区别
函数有自己的作用域,宏的作用域与调用者是一样的
set(funcdifmacro 100)
function(funcdif)
set(funcdifmacro 200)
message(WARNING "in funcdif value = ${funcdifmacro}")
endfunction(funcdif)
funcdif()
message(WARNING "out funcdif value = ${funcdifmacro}")
macro(madif)
set(funcdifmacro 200)
message(WARNING "in madif value = ${funcdifmacro}")
endmacro(madif)
madif()
message(WARNING "out madif value = ${funcdifmacro}")
结果:
in funcdif value = 200
out funcdif value = 100
in madif value = 200
out madif value = 200
可以看到,function里面改变的funcdifmacro 值在外部并没有生效,function使用外部变量时,会拷贝一份外部变量来操作,所以并不会改变外部变量
变量的作用域
- 全局层:cache变量,在整个项目范围可见,一般在set定义变量时,指定CACHE参数就能定义为cache变量
- 目录层:在当前目录CMakeLists.txt中定义,以及在该文件包含的其他cmake源文件中定义的变量
- 函数层:在命令函数中定义的变量,属于函数作用域内的变量