函数
- 基本用法
function(\<name> [arg1 [arg2 [arg3 ...]]])
command1(args ...)
command2(args ...)
...
endfunction(\<name>)
-
使用return()命令退出函数,注意:return并不可以用于返回参数
-
可变参函数:cmake中,调用函数时实际传入的参数个数不需要等于函数定义的参数个数,但是必须要大于等于函数定义的参数个数
-
函数的内部变量:在函数内部使用的内置变量
内部变量 | 说明 |
---|---|
ARGVX | X是一个数字,如ARGV0、ARGV1等,分为表示第一个参数、第二个参数…… |
ARGV | 实际调用时传入的参数会存放在ARGV变量中,如果是多个参数,就是一个参数列表 |
ARGN | 定义函数时参数为2个,实际调用时传入了4个,则剩下2个存放在这里,如果是多个参数,就是一个参数列表 |
ARGC | 调用函数时,实际传入的参数个数 |
- function()定义的函数使用范围是全局的,并不局限于当前源码,在其子源码或父源码中也可以被使用
宏
-
基本用法
macro(\<name> [arg1 [arg2 [arg3 ...]]])
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endmacro(\<name>)
-
宏与函数的差异:宏的参数,诸如ARGC、ARGV、ARGN等这些值并不是变量,而是字符串替换。当cmake执行宏定义时,会先将宏的参数和ARGC、ARGV、ARGN等这些值进行字符串替换。类似于C语言对宏的处理。
文件操作
写文件:写、追加内容
file(WRITE \<filename> \<content> ...)
fire(APPEND \<filename> \<content> ...)
- 如果文件不存在,将被创建;如果存在,WRITE直接覆盖,APPEND在末尾追加。
写文件:由内容生成文件
file(GENERATE OUTPUT output-file \<INPUT input-file|CONTENT content> [CONDITION expression])
读文件:字节读取
file(READ \<filename> \<variable> [OFFSET \<offset>] [LIMIT \<max-in>] [HEX])
- 从名为filename的文件中读取内容并存储在variable中,可选择从给定的offset开始,最多读取max-in个字节,HEX选项使数据转换为十六进制表示。
读文件:字符串形式读取
file(STRINGS \<filename> \<variable> [\<options> ...])
- 从文件中解析ASCII字符串列表并存储在variable中。文件中的二进制数据将被忽略,回车符将被忽略。
- options
参数 | 说明 |
---|---|
LENGTH_MAXIMUM \<max-len> | 读取的字符串的最大长度 |
LENGTH_MINIMUM \<min-len> | 读取的字符串的最小长度 |
LIMIT_COUNT \<max-num> | 读取的行数 |
LIMIT_INPUT \<max-in> | 读取的字节数 |
LIMIT_OUTPUT \<max-out> | 存储到变量的限制字节数 |
NEWLINE_CONSUME | 把换行符也考虑进去 |
NO_HEX_CONVERSION | 除非提供此选项,否则Intel Hex和Motorola S-record文件在读取时会自动转换为二进制文件 |
REGEX \<regex> | 只读取符合正则表达式的行 |
ENCODING \<encoding-type> | 指定输入文件的编码格式 |
计算文件hash值
file(\<MD5|SHA1|SHA224|SHA256|SHA384|SHA512> \<filename> \<variable>)
文件重命名
file(RENAME \<oldname> \<newname>)
删除文件
file(REMOVE [\<files> ...])
file(REMOVE_RECURSE [\<files> ...])
- REMOVE选项将删除给定的文件,但不可以删除目录
- REMOVE_RECURSE选项将删除给定的文件或目录以及非空目录。
交叉编译
直接做法
- 如果不设置交叉编译,默认情况下,cmake会使用主机系统的编译器来编译工程。
# 设置arm交叉编译
set(CMAKE_SYSTEM_NAME Linux) #设置目标系统名字
set(CMAKE_SYSTEM_PROCESSOR arm) #设置目标处理器架构
# 设置编译器的sysroot路径
set(TOOLCHAIN_DIR /opt/fsl-imx-x11/4.1.14-2.1.0/sysroots) # 根据自己编译器路径更改
set(CMAKE_SYSROOT ${TOOLCHAIN_DIR}/cortexa7hf-neon-poky-linux-gnueabi) # 根据自己编译器路径更改
# 设置arm-gcc和arm-g++交叉编译器
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-g++)
# 为编译器添加编译选项
set(CMAKE_C_FLAGS "-march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7")
set(CMAKE_CXX_FLAGS "-march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
- CMAKE_FIND_ROOT_PATH_MODE_INCLUDE 变量控制 CMAKE_SYSROOT 中的路径是否被 find_file()和 find_path()使用。
- 如果设置为 ONLY,则只会搜索 CMAKE_SYSROOT 中的路径;
- 如果设置为 NEVER,则 CMAKE_SYSROOT 中的路径将被忽略并且仅使用主机系统路径;
- 如果设置为 BOTH,则将搜索主机系统路径和 CMAKE_SYSROOT 中的路径。其它两个同理。
- 配置ARM交叉编译器的代码要放在project()命令之前 ,否则不会生效。
更加规范的作法
-
通常的做法是:将配置项写在一个单独的配置文件中,而不直接写入到CMakeLists.txt中,在执行cmake命令时,指定配置文件给cmake,让其去配置交叉编译环境。
cmake -DCMAKE_TOOLCHAIN_FILE=cfg_file ..
-
通过-D选项可以创建一个缓存变量,在整个工程中生效,会覆盖CMakeLists.txt源码中定义的同名变量
变量的作用域
函数作用域
-
当在函数内通过set将变量var与当前函数作用域绑定时,变量var仅在函数作用域内有效,出了这个作用域,如果这个作用域外也有同名的变量var,那么使用的将是域外同名变量var。
-
如何在函数内部去修改外部同名变量呢?
在调用set命令时,在参数列表末尾加上PARENT_SCOPE关键字。
如果添加了 PARENT_SCOPE 选项,则变量将设置在当前作用域范围之上的作用域范围内。
目录作用域
- 子目录会将父目录的所有变量拷贝到当前 CMakeLists.txt 源码中,当前 CMakeLists.txt 中的变量的作用域仅在当前目录有效。
- 目录作用域有两个特点:
- 向下有效:上层作用域中定义的变量在下层作用域中是有效的
- 值拷贝:子源码从父源码中拷贝了一份变量副本,在子源码中修改不会影响父源码中变量的值
全局作用域
- 缓存变量在整个 cmake 工程的编译生命周期内都有效,所以这些变量的作用域是全局范围的
- 定义缓存变量
- 通过 set 命令定义,使用 set 命令时添加 CACHE 选项
- 使用-D选项定义
属性
- 属性详细内容链接:https://cmake.org/cmake/help/v3.5/manual/cmake-properties.7.html
- 主要涉及全局属性、目录属性、目标属性等。
本文地址: cmake入门与进阶——进阶篇