函数

  • 基本用法

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选项定义

属性

说点什么
请文明发言!
支持Markdown语法
好耶,沙发还空着ヾ(≧▽≦*)o
Loading...