0
点赞
收藏
分享

微信扫一扫

cmake语言

木樨点点 2022-08-29 阅读 147

组织结构

目录

目录结构:

.
├── CMakeLists.txt
├── sub_1
│ ├── CMakeLists.txt
│ ├── sub_1_sub_1
│ │ └── CMakeLists.txt
│ └── sub_1_sub_2
│ └── CMakeLists.txt
└── sub_2
└── CMakeLists.txt

上层目录通过​​add_subdirectory()​​添加子目录,如:

# CMakeLists.txt
add_subdirectory(sub_1)
add_subdirectory(sub_2)

# sub_1/CMakeLists.txt
add_subdirectory(sub_1_sub_1)
add_subdirectory(sub_1_sub_2)

脚本

用cmake语言编写并以.cmake结尾的文件。它可以用 ​​cmake -P script.cmake​​执行,它不会产生编译系统,不能定义任何目标。

不知道脚本是用来干什么的?

模块

<module>.cmake, 我很不理解,这不就是脚本文件吗?

在CMakeLists.txt中或是有cmake脚本中,都可以用include命令把module.cmake加载到当前环境中,类型c++的include语句。

通过设置​​CMAKE_MODULE_PATH​​ 变量指模块的搜索路径。

语法

编码

3.2以上版本支持UTF8编码,这就够了!

还有一些其它元素的定义,直接看源文吧:​​https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#syntax​​

源文件

可以把它理解为c++中的.cpp文件

命令调用

可以把它理解为c++中的函数

command_name(arg1 arg2
arg3 ...)

参数之间不是用​​,​​分隔而是‘space或\n’, 注意 space 可以是‘空格’或'\t'

其它的和c的函数没什么差别。

参数
括号参数

message(
[=[

[的第一个换行会被忽略(本应该有两个换行,但是只输出了一个)
这是多行叁数
多行参数中不可以引用变量 ${PROJECT_BINARY_DIR}
也没有转义\t(制表符不起作用),最后的换行不会被忽略
]=]
)

  • [=[ 中的‘=’可以没有,也可以有多个
  • 结尾的]=]必须与开头的[=[成对匹配

括号参数里的内容只能是字符串...

有引号的参数

message(
"
这是双引号 \"可以使用转换字符\"
也可以引和变量:${PROJECT_BINARY_DIR}
这个是续行符\
,接上一行
"
)

没有引号的参数

message(${PROJECT_BINARY_DIR}) # 引用变量
message(hello\tword) # 符串,这符串中不能包含'()#\',可以有转义序列

转义序列

escape_sequence  ::=  escape_identity | escape_encoded | escape_semicolon
escape_identity ::= '\' <match '[^A-Za-z0-9;]'># 编码转换比如要表示一个utf8的字符
escape_encoded ::= '\t' | '\r' | '\n'
escape_semicolon ::= '\;' # 不知道有什么作用

变量引用

${<variable>}

注释

单行注释

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

多行注释

#[=[
第一行
第二行
...
]=]

[=[xxxx]=]和括号参数的语法一样

控制结构

参考c/c++相信你很快就知道它们的含义有用法了

条件表达式语法

基本表达式

if(<常量>)

# [1 ON YES TRUE Y 非0的数字(包括浮点数)] -- true
# [ 0 OFF NO FALSE N IGNORE NOTFOUND 空串 xx-NOTFOUND] -- false

if(y) # 不区分大小写
message("show me")
endif()

if(<变量>)

set(MY_VAL OFF)
# MY_VAL = [ 0 OFF NO FALSE N IGNORE NOTFOUND 空串 xx-NOTFOUND] is false
# 其它为true (如果 MY_VAL没有定义也为false)
# 不支持 if(ENV{some_var}) 一直为false
if(MY_VAL)
message("show me")
endif()

if(<字符串>)

if("string") # 为false
endif()
# ON YES TRUE Y 为true
if("y")
message("show me")
endif()

逻辑表达式

if(NOT<condition>)

set(MY_VAL MY-NOTFOUND)
if(NOT MY_VAL)
message("show me")
endif()

if(<cond1> AND<cond2>)

set(MY_VAL MY-NOTFOUND)
if(NOT MY_VAL AND ON)
message("show me")
endif()

if(<cond1> OR<cond2>)

set(MY_VAL MY-NOTFOUND)
if(NOT MY_VAL OR OFF)
message("show me")
endif()

组合与嵌套

set(MY_VAL MY-NOTFOUND)
if(NOT (NOT (MY_VAL OR OFF) AND FALSE))
message("show me")
endif()

存在检测

​if(COMMAND command-name)

如果命令名存在,返回true

if(COMMAND message)
message("show me")
endif()

​if(TARGET target-name)

target-name是否存在

if(TARGET Tutorial)
message("show me")
endif()

​if(DEFINED <name>|CACHE{<name>}|ENV{<name>})

变量是否有定义|缓存中是否有变量name|环境变量是否存在

if(DEFINED ENV{PATH})
message("show me")
endif()

需要注意:

  • PATH 不能用小写,环境变量都要用大写??
  • 宏参数不是变量
  • if(DEFINED someName)不能直接判断是不有缓存变量someName,someName是缓存或非缓存变量它都返回true.
  • if(DEFINED CACHE{someName})只能判断缓存中是否存在该变量
  • 如果要两个(缓存和非缓存)都判断 : if(DEFINED someName AND NOT DEFINED CACHE{someName})
​if(<variable|string> IN_LIST <variable>)

set(MY_LIST A B C D E)
set(V E)
if(V IN_LIST MY_LIST)
message("show me")
endif()
if("A" IN_LIST MY_LIST)
message("show me2")
endif()

文件操作

​if(EXISTS path-to-file-or-directory)

文件或目录是否存在

set(p /home/luan/cmake_tutorial/cmake-3.24.1-tutorial-source/Step2/build)
if(EXISTS ${p})
message("show me")
endif()

# 可以使用相对路径
set(p Makefile)
if(EXISTS ${p})
message("show me")
endif()

​if(file1 IS_NEWER_THAN file2)

file1 比file2 更新,如果两个文件的时间戳相同也返回true

if(myfile2 IS_NEWER_THAN myfile)
message("show me")
endif()

​if(IS_DIRECTORY path-to-directory)

判断目录

​if(IS_SYMLINK file-name)

给定的路径是否为软链接(或者快捷方式)

​if(IS_ABSOLUTE path)

是否为绝对路径

比较

​if(<variable|string> MATCHES regex)

字符串或变量的值是与给定的正则匹配

if(" my book name" MATCHES "^ my")
message("show me")
endif()

if(<variable|string> <OP><variable|string>)

OP可以取以下值:

  • LESS 
  • GREATER 
  • EQUAL 
  • LESS_EQUAL 
  • GREATER_EQUAL 
  • STRLESS 
  • STRGREATER 
  • STREQUAL 
  • STRLESS_EQUAL 
  • STRGREATER_EQUAL 

两大类,数值和字符串比较

# 指定 16进制也是可以的
if("100" EQUAL "0x64")
message("show me")
endif()
# 字符串比较,不会相同...
if("100" STREQUAL "0x64")
message("show me")
endif()

版本比较

​if(<variable|string> <OP><variable|string>)

OP的取值:

  • VERSION_LESS 
  • VERSION_GREATER 
  • VERSION_EQUAL 
  • VERSION_LESS_EQUAL 
  • VERSION_GREATER_EQUAL 

if("1.0" VERSION_LESS "1.1")
message("show me")
endif()

路径的比较

if(<variable|string> PATH_EQUAL <variable|string>)

这个要求的版本比较高:New in version 3.24.

与字符 STREQUAL相比,它把多个路径分割符处理成1个

# tue
if ("/a/b//c" PATH_EQUAL "/a/b/c")
message("show me")
endif()

变量拓展

set(var1 OFF)
set(var2 "var1")
# if(${var2}) --> 先执行取值操作 --> if(var1)
if(${var2}) # 相当于 if(var1) 所以它是假的
message("true")
else()
message("false")
endif()

if(var2) # var2 = "var1" 不是false常数,所以它是返回真
message("true")
else()
message("false")
endif()

 <variable|string>语法解析:
  • 先测试参数是否是一个定义的变量,如果是先求值,否则直接应用原始值
  • NOT OR AND 先测试参数是否布尔常量,如果不是则假定它是一个变量

条件块

if()/elseif()/else()/endif()

if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()

循环

foreach()/endforeach()

foreach(<loop_var> <items>)

set(VAR a b c d e fg)

foreach(item ${VAR})
message(${item})
endforeach()

message("\n")

foreach(item 1 2 3 4 5 6)
message(${item})
endforeach()

foreach(<loop_var> RANGE <stop>)

foreach(item RANGE 5) # 从 0 开始
message(${item})
endforeach()

foreach(<loop_var> RANGE <start> <stop> [<step>])

foreach(item RANGE 0 10 2) # start 0 stop 10 step 2
message(${item})
endforeach()

foreach(<loop_var> IN [LISTS [<lists>]] [ITEMS [<items>]])

foreach(item IN ITEMS 1 2 3 4 5 6 7 8)
message(${item})
endforeach()

set(A 0;1)
set(B 2 3)
set(C "4 5")
set(D 6;7 8)
set(E "")
foreach(X IN LISTS A B C D E)
message(STATUS "X=${X}")
endforeach()

foreach(<loop_var>... IN ZIP_LISTS <lists>)


New in version 3.17(我的机子中,cmake版本是3.16,比较尴尬...)

list(APPEND English one two three four)
list(APPEND Bahasa satu dua tiga)

foreach(num IN ZIP_LISTS English Bahasa)
message(STATUS "num_0=${num_0}, num_1=${num_1}")
endforeach()

foreach(en ba IN ZIP_LISTS English Bahasa)
message(STATUS "en=${en}, ba=${ba}")
endforeach()

-- num_0=two, num_1=dua
-- num_0=three, num_1=tiga
-- num_0=four, num_1=
-- en=one, ba=satu
-- en=two, ba=dua
-- en=three, ba=tiga
-- en=four, ba=

和python的zip函数差不多一个功能...

while()/endwhile()

set(COUNT 0)
while(COUNT LESS 10)
math(EXPR COUNT "${COUNT} + 1" OUTPUT_FORMAT DECIMAL)
message(${COUNT})
endwhile()

突然间发现,cmake没有数学算的功能(它是通过​​math​​来实现的)...

break()/continue()

很遗憾,它们只能嵌套到while或foreach中

cmake语言_cmake

注定不能像c/c++的break或continue那样灵活...

数学运算

math(EXPR <variable> "<expression>" [OUTPUT_FORMAT <format>])

  • variable 是要输出的变量(保存结果的变量)
  • expression 数学运算表达式 如 5 + 2 ..., 引号表达式内可以引用变量的值 "${var} + 1" 也是可以的

set(COUNT 0)
while(COUNT LESS 10)
math(EXPR COUNT "${COUNT} + 1" OUTPUT_FORMAT DECIMAL)
message(${COUNT})
endwhile()

  • format 可取值: DECIMAL , HEXADECIMAL

自定义指令

还没有用过,先把链接贴出来,如果有需要再来看...

​ ​macro()​​/​​endmacro()

​​https://cmake.org/cmake/help/latest/command/macro.html#command:macro​​

function()​/​​endfunction()

​​https://cmake.org/cmake/help/latest/command/function.html#command:function​​

先把一些操作的声明贴上来,例过段时间再回来补上...

变量

set(<variable> <value>... [PARENT_SCOPE])

所有的变量类型都是字符串,但是有一些命令可以把字符解释为数值。

  • set(varName value) -- 定义变量
  • unset(varName) -- 取消变量的定义
  • cmake中一些被保留的变量名(大小字不敏感)
    1. CMAKE_
    2. _CMAKE_
    3. _开始的或者是cmake命令

变量的作用域

目录作用域

# CMakeLists.txt
set(MY_NAME hello)
...
# 报错了
# message(${YOU_NAME})

# MathFunctions/CMakeLists.txt
message(${MY_NAME}) # 可以输出

set(YOU_NAME word)

结论: 子目录可以引用父目录的变量,而父目录不能使用子目录中定义的变量

环境变量

引用语法:

$ENV{<variable>}

也可以用set/unset对它进行操作,对于环境变量应该是引用居多...

列表

通过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"

通过list操作

​​https://cmake.org/cmake/help/latest/command/list.html​​

读操作

list(LENGTH <list> <output variable>)

list(LENGTH <list> <output variable>)

list(GET <list> <element index> 
[<element index> ...]
<output variable>)

list(JOIN <list> <glue> <output variable>)

list(SUBLIST <list> <begin> <length> <output variable>)

查找搜索

list(FIND <list> <value> <output variable>)

修改

list(APPEND <list> [<element> ...])

list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)

list(INSERT <list> <element_index> <element> [<element> ...])

list(POP_BACK <list> [<out-var>...])

list(POP_FRONT <list> [<out-var>...])

list(PREPEND <list> [<element> ...])

list(REMOVE_ITEM <list> <value> [<value> ...])

list(REMOVE_AT <list> <index> [<index> ...])

list(REMOVE_DUPLICATES <list>)

list(TRANSFORM <list> <ACTION> [<SELECTOR>]
[OUTPUT_VARIABLE <output variable>])

list(TRANSFORM <list> <APPEND|PREPEND> <value> ...)

list(TRANSFORM <list> STRIP ...)

list(TRANSFORM <list> GENEX_STRIP ...)

list(TRANSFORM <list> REPLACE <regular_expression>
<replace_expression> ...)

list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...)

list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...)

list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...)

排序

list(REVERSE <list>)

list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])


举报

相关推荐

0 条评论