当前位置: 首页 > news >正文

4、CMake基础:日志、变量操作和宏定义

@TOC

1. 日志

在CMake中可以用用户显示一条消息,该命令的名字为message:

message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
  • (无) :重要消息
  • STATUS :非重要消息
  • WARNING:CMake 警告, 会继续执行
  • AUTHOR_WARNING:CMake 警告 (dev), 会继续执行
  • SEND_ERROR:CMake 错误, 继续执行,但是会跳过生成的步骤
  • FATAL_ERROR:CMake 错误, 终止所有处理过程

CMake的命令行工具会在stdout上显示STATUS消息,在stderr上显示其他所有消息。CMake的GUI会在它的log区域显示所有消息。
CMake警告和错误消息的文本显示使用的是一种简单的标记语言。文本没有缩进,超过长度的行会回卷,段落之间以新行做为分隔符。

# 输出一般日志信息
message(STATUS "source path: ${PROJECT_SOURCE_DIR}")
# 输出警告信息
message(WARNING "source path: ${PROJECT_SOURCE_DIR}")
# 输出错误信息
message(FATAL_ERROR "source path: ${PROJECT_SOURCE_DIR}")

2. 变量操作

2.1 追加

有时候项目中的源文件并不一定都在同一个目录中,但是这些源文件最终却需要一起进行编译来生成最终的可执行文件或者库文件。如果我们通过file命令对各个目录下的源文件进行搜索,最后还需要做一个字符串拼接的操作,关于字符串拼接可以使用set命令也可以使用list命令。

set

如果使用set进行字符串拼接,对应的命令格式如下:

set(变量名1 ${变量名1} ${变量名2} ...)

关于上面的命令其实就是将从第二个参数开始往后所有的字符串进行拼接,最后将结果存储到第一个参数中,如果第一个参数中原来有数据会对原数据就行覆盖。

cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/src1/*.cpp)
file(GLOB SRC_2 ${PROJECT_SOURCE_DIR}/src2/*.cpp)
# 追加(拼接)
set(SRC_1 ${SRC_1} ${SRC_2} ${TEMP})
message(STATUS "message: ${SRC_1}")

list

如果使用list进行字符串拼接,对应的命令格式如下:

list(APPEND <list> [<element> ...])
  • list命令的功能比set要强大,字符串拼接只是它的其中一个功能,所以需要在它第一个参数的位置指定出我们要做的操作,APPEND表示进行数据追加,后边的参数和set就一样了。
cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/src1/*.cpp)
file(GLOB SRC_2 ${PROJECT_SOURCE_DIR}/src2/*.cpp)
# 追加(拼接)
list(APPEND SRC_1 ${SRC_1} ${SRC_2} ${TEMP})
message(STATUS "message: ${SRC_1}")

在CMake中,使用set命令可以创建一个list。一个在list内部是一个由分号;分割的一组字符串。例如,set(var a b c d e)命令将会创建一个list:a;b;c;d;e,但是最终打印变量值的时候得到的是abcde。

set(tmp1 a;b;c;d;e)
set(tmp2 a b c d e)
message(${tmp1})
message(${tmp2})
# 输出结果
abcde
abcde

2.2 字符串移除

main.cpp是一个测试文件。如果我们想要把计算器相关的源文件生成一个动态库给别人使用,那么只需要add.cpp、div.cp、mult.cpp、sub.cpp这四个源文件就可以了。此时,就需要将main.cpp从搜索到的数据中剔除出去,想要实现这个功能,也可以使用list

list(REMOVE_ITEM <list> <value> [<value> ...])
cmake_minimum_required(VERSION 3.0)
project(TEST)
set(TEMP "hello,world")
file(GLOB SRC_1 ${PROJECT_SOURCE_DIR}/*.cpp)
# 移除前日志
message(STATUS "message: ${SRC_1}")
# 移除 main.cpp
list(REMOVE_ITEM SRC_1 ${PROJECT_SOURCE_DIR}/main.cpp)
# 移除后日志
message(STATUS "message: ${SRC_1}")

通过 file 命令搜索源文件的时候得到的是文件的绝对路径(在list中每个文件对应的路径都是一个item,并且都是绝对路径),那么在移除的时候也要将该文件的绝对路径指定出来才可以,否是移除操作不会成功。

2.3 其他操作

  1. 获取 list 的长度。
list(LENGTH <list> <output variable>)
* LENGTH:子命令LENGTH用于读取列表长度
* <list>:当前操作的列表
* <output variable>:新创建的变量,用于存储列表的长度。
  1. 读取列表中指定索引的的元素,可以指定多个索引
list(GET <list> <element index> [<element index> ...] <output variable>)
* <list>:当前操作的列表
* <element index>:列表元素的索引.
从0开始编号,索引0的元素为列表中的第一个元素;
索引也可以是负数,-1表示列表的最后一个元素,-2表示列表倒数第二个元素,以此类推;
当索引(不管是正还是负)超过列表的长度,运行会报错
* <output variable>:新创建的变量,存储指定索引元素的返回结果,也是一个列表。
  1. 将列表中的元素用连接符(字符串)连接起来组成一个字符串
list (JOIN <list> <glue> <output variable>)
*<list>:当前操作的列表
<glue>:指定的连接符(字符串)
<output variable>:新创建的变量,存储返回的字符串
  1. 查找列表是否存在指定的元素,若果未找到,返回-1
list(FIND <list> <value> <output variable>)
* <list>:当前操作的列表
* <value>:需要再列表中搜索的元素
* <output variable>:新创建的变量
如果列表<list>中存在<value>,那么返回<value>在列表中的索引;如果未找到则返回-1。
  1. 将元素追加到列表中
list (APPEND <list> [<element> ...])
  1. 在list中指定的位置插入若干元素
list(INSERT <list> <element_index> <element> [<element> ...])
  1. 将元素插入到列表的0索引位置
list (PREPEND <list> [<element> ...])
  1. 将列表中最后元素移除
list (POP_BACK <list> [<out-var>...])
  1. 将列表中第一个元素移除
list (POP_FRONT <list> [<out-var>...])
  1. 将指定的元素从列表中移除
list (REMOVE_ITEM <list> <value> [<value> ...])
  1. 将指定索引的元素从列表中移除
list (REMOVE_AT <list> <index> [<index> ...])
  1. 移除列表中的重复元素
list (REMOVE_DUPLICATES <list>)
  1. 列表翻转
list(REVERSE <list>)
  1. 列表排序
list (SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])
  • COMPARE:指定排序方法。有如下几种值可选:
    1. STRING:按照字母顺序进行排序,为默认的排序方法
    2. FILE_BASENAME:如果是一系列路径名,会使用basename进行排序
    3. NATURAL:使用自然数顺序排序
  • CASE:指明是否大小写敏感。有如下几种值可选:
    1. SENSITIVE: 按照大小写敏感的方式进行排序,为默认值
    2. INSENSITIVE:按照大小写不敏感方式进行排序
  • ORDER:指明排序的顺序。有如下几种值可选:
    1. ASCENDING:按照升序排列,为默认值
    2. DESCENDING:按照降序排列

3. 宏定义

在进行程序测试的时候,我们可以在代码中添加一些宏定义,通过这些宏来控制这些代码是否生效,如下所示:

#include <stdio.h>
#define NUMBER  3int main()
{int a = 10;
#ifdef DEBUGprintf("我是一个程序猿, 我不会爬树...\n");
#endiffor(int i=0; i<NUMBER; ++i){printf("hello, GCC!!!\n");}return 0;
}
  • 在程序的第七行对DEBUG宏进行了判断,如果该宏被定义了,那么第八行就会进行日志输出,如果没有定义这个宏,第八行就相当于被注释掉了,因此最终无法看到日志输入出(上述代码中并没有定义这个宏)。
  1. 运行时候定义
    可以不在代码中定义这个宏,而是在测试的时候去把它定义出来,其中一种方式就是在gcc/g++命令中去指定,如下:
$ gcc test.c -DDEBUG -o app

在gcc/g++命令中通过参数 -D指定出要定义的宏的名字,这样就相当于在代码中定义了一个宏,其名字为DEBUG。

  1. CMake定义
add_definitions(-D宏名称)
cmake_minimum_required(VERSION 3.0)
project(TEST)
# 自定义 DEBUG 宏
add_definitions(-DDEBUG)
add_executable(app ./test.c)
  1. VS中添加:预编译中加入宏

3.1 预定义宏

功能
PROJECT_SOURCE_DIR使用cmake命令后紧跟的目录,一般是工程的根目录
PROJECT_BINARY_DIR执行cmake命令的目录
CMAKE_CURRENT_SOURCE_DIR当前处理的CMakeLists.txt所在的路径
CMAKE_CURRENT_BINARY_DIRtarget 编译目录
EXECUTABLE_OUTPUT_PATH重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH重新定义目标链接库文件的存放位置
PROJECT_NAME返回通过PROJECT指令定义的项目名称
CMAKE_BINARY_DIR项目实际构建路径,假设在build目录进行的构建,那么得到的就是这个目录的路径

相关文章:

  • 跨越养生误区雷区,迈向科学养生大道
  • Python项目打包部署
  • node.js 实战——mongoDB 续一
  • 在阿里云实例上部署通义千问QwQ-32B推理模型
  • Linux基础篇、第一章_01_3安装虚拟机手动安装部署Ubuntu22.04服务器
  • Maven根据Google proto文件自动生成java对象
  • Vue基础(一) 基础用法
  • uniapp 小程序 安卓苹果 短视频解决方案
  • 云数据中心整体规划方案PPT(113页)
  • 怎样学习Electron
  • Reverse-WP记录9
  • rust 全栈应用框架dioxus
  • LeetCode58_最后一个单词的长度
  • 创龙全志T536全国产(4核A55 ARM+RISC-V+NPU 17路UART)工业开发板硬件说明书
  • 电子电器框架 --- 数据连接性和云集成在增强电气/电子架构方面的作用
  • 技术白皮书:Oracle GoldenGate 优势
  • Flip PDF Plus Corp7.7.22电子书制作软件
  • 【MCP Node.js SDK 全栈进阶指南】高级篇(5):MCP之微服务架构
  • c/c++之信号处理<signal.h>
  • MATLAB小试牛刀系列(2)
  • 上海市十六届人大常委会第二十一次会议表决通过有关人事任免事项
  • 五大国有银行明确将撤销监事会
  • 烟花、美食和购物优惠都安排上了,上海多区开启热闹模式
  • 王沪宁主持召开全国政协主席会议
  • 五月院线片单:就看五一档表现了
  • 阿里千问3系列发布并开源:称成本大幅下降,性能超越DeepSeek-R1