【CMake】message函数
目录
一.message函数
1.1.不带任何mode(默认NOTICE)
1.2.STATUS
1.3.WARNING
1.4.SEND_ERROR
1.5.FATAL_ERROR
一.message函数
大家可以去官网看看:message — CMake 4.1.1 Documentation
事实上,message函数最常见的就是下面这种形式
message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "要打印的内容" ...)
1.1.不带任何mode(默认NOTICE)
不带任何模式的 message 命令是 CMake 中最基础的消息输出形式。
该命令将指定的文本内容直接记录到日志中,其基本语法为
message("message text" ...)
当提供多个消息字符串时,它们会被自动连接成一个单独的字符串,中间不添加任何分隔符。
这些消息没有任何自动添加的前缀,如 STATUS 模式的 "-- " 或 WARNING 模式的 "CMake Warning:",完全按照用户提供的文本内容原样输出。
话不多说,我们直接来看例子
CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(PrintVarDemo LANGUAGES CXX)message("你好,")
message("CMake.")set(MY_NAME "流云")
message("我的名字是:${MY_NAME}")
我们来构建一下
mkdir build && cd build && cmake ..
事实上呢!!在 CMake 中,命令 message 在不显式指定模式参数时,其行为等同于使用 NOTICE 模式。
也就是说
message("text")
等价于
message(NOTICE "text")
我们可以去修改一下我们上面那个CMakeLists.txt即可
cmake_minimum_required(VERSION 3.15)
project(PrintVarDemo LANGUAGES CXX)message(NOTICE "你好,")
message(NOTICE "CMake.")set(MY_NAME "流云")
message(NOTICE "我的名字是:${MY_NAME}")
是不是一模一样的啊!!!
1.2.STATUS
示例一
我们直接来看我们自己写的例子,首先我们的整个项目的结构是下面这样子的
cmake_minimum_required(VERSION 3.10)
project(MessageStatus)message(STATUS "这是一个状态提示:正在配置项目...")
接下来我们来构建项目
mkdir build && cd build && cmake ..
大家看到了吗,这个message打印的东西前面有两条杠(也就是"--“),这个是STATUS的特点哦!
大家可能疑惑,这玩意和NOTICE模式有什么区别呢?
其实还是有一点区别的
- 所有通过无模式 message 命令输出的信息都会被发送到标准错误流(stderr)
- 所有通过 STATUS 模式 message 命令输出的信息都会被发送到标准输出流(stdout)
我们可以看个例子
📂 项目结构
MsgDemo/
└── CMakeLists.txt
📄 CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(MsgDemo)# 无 mode(等同于 NOTICE,输出到 stderr)
message("这是无模式 message(NOTICE),输出到 stderr")# 显式 STATUS,输出到 stdout
message(STATUS "这是 STATUS message,输出到 stdout")
🛠️ 运行方法
mkdir build && cd build# 把 stdout 和 stderr 分别重定向到不同文件
cmake .. >log.txt 2>err.txt
我们看看这两个文件里面的内容
cat log.txt
输出示例:
我们看看另外一个
cat err.txt
输出示例:
这样就能很直观地看到:
-
STATUS → stdout
-
无 mode(NOTICE) → stderr
1.3.WARNING
用于向用户输出一个警告(Warning)信息。其核心目的是:提醒用户某个潜在的问题、非理想的情况或已弃用的用法,但允许配置和生成过程继续执行。
它就像一个“黄灯”,告诉用户“请注意,但你可以继续前进”。
1. 输出目的地和格式
-
目的地: 输出到 标准错误 (stderr)。这与
STATUS
(输出到 stdout)有根本区别。 -
前缀和格式: 消息会以显眼的
CMake Warning:
为前缀。此外,CMake 会自动附上文件名和行号,极大地方便了用户定位问题代码。 -
颜色高亮: 在许多终端中,警告信息会以黄色或红色等醒目的颜色显示,以吸引用户注意。
-
示例:
# 在 CMakeLists.txt 的第 10 行 message(WARNING "This is a custom warning message.")
输出:
CMake Warning at CMakeLists.txt:10 (message):This is a custom warning message.
2. 设计初衷和用途
WARNING
消息的设计目标是:在不停止流程的前提下,最大限度地引起用户对某个问题的关注。
典型用途包括:
-
功能弃用警告:告知用户某个变量、函数或目标即将被移除,应使用新的替代方案。
-
兼容性警告:提醒用户当前配置可能导致与其他软件或旧版本的兼容性问题。
-
非致命的条件检查:当某个条件不满足时,使用回退方案,但警告用户这不是最优配置(例如,找不到首选库,转而使用捆绑的版本)。
-
可疑的用户输入:检查用户设置的变量值是否在合理范围内,如果不在,则发出警告。
-
平台或编译器限制:告知用户在特定平台或编译器上,某些功能被禁用或可能无法正常工作。
3. 行为:不会中断过程
这是 WARNING
与 SEND_ERROR
和 FATAL_ERROR
最关键的区别。
-
WARNING
: 打印消息,继续正常执行所有后续的配置和生成步骤。 -
SEND_ERROR
: 打印消息,继续配置,但跳过生成(不会生成 Makefile 或项目文件)。 -
FATAL_ERROR
: 打印消息,立即停止所有处理。
4.示例
我们来看看这个目录结构
📂 目录结构
WarningExample/
├── CMakeLists.txt
└── main.cpp
📄 main.cpp
#include <iostream>
int main() {std::cout << "Hello, CMake!" << std::endl;return 0;
}
📄 CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(WarningExample)# 输出一个警告,但不会中断配置
message(WARNING "⚠️ 这是一个警告:你没有开启优化选项!")add_executable(hello main.cpp)
其实我们可以一键复制下面这个命令来一键搭建出这个目录结构和文件
mkdir -p WarningExample && \
cat > WarningExample/main.cpp <<'EOF'
#include <iostream>
int main() {std::cout << "Hello, CMake!" << std::endl;return 0;
}
EOFcat > WarningExample/CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.10)
project(WarningExample)# 输出一个警告,但不会中断配置
message(WARNING "⚠️ 这是一个警告:你没有开启优化选项!")add_executable(hello main.cpp)
EOF
接下来我们就来构建我们的项目
cd WarningExample && \
mkdir build && cd build && \
cmake ..
我们看到这里出现了黄色字体,这就是message的WARNING模式。
接下来我们进行构建
cmake --build .
我们看看当前的build目录
然后项目还是能继续正常生成。
1.4.SEND_ERROR
简要介绍
message(SEND_ERROR)
是 CMake 的 message()
函数的一种特殊模式。它的核心作用是:生成一个错误消息,允许当前配置阶段继续完成,但会阻止生成阶段的进行。
为了理解这句话,我们首先要区分 CMake 的两个主要阶段:
-
配置阶段 (Configure Stage):
-
CMake 读取并处理你的
CMakeLists.txt
文件。 -
它评估变量、解析命令、检查编译器、寻找依赖包等。
-
最终,它会在你的构建目录(通常是
build/
)中生成一个本地构建系统(如 Makefile文件等)。
-
-
生成阶段 (Generate Stage):
-
紧随配置阶段之后。
-
CMake 使用配置阶段收集的所有信息,实际编写出最终的构建系统文件(如
Makefile
,.sln
等)。
-
message(SEND_ERROR)
的行为正是围绕这两个阶段设计的。
详细行为解析
当你调用 message(SEND_ERROR “Your error message”)
时,会发生以下事情:
-
输出错误信息:
-
消息会以错误的格式打印到终端(通常在 Unix-like 系统上表现为红色文字)。
-
消息内容会明确包含 “CMake Error” 字样,使其很容易被识别和定位。
-
-
配置阶段继续执行:
-
这是
SEND_ERROR
与FATAL_ERROR
最关键的区别。 -
CMake 不会在遇到
SEND_ERROR
时立即停止。它会继续处理CMakeLists.txt
文件中该命令之后的所有内容。 -
这意味着,在一次配置运行中,你可能会看到多个
SEND_ERROR
消息。
-
-
设置内部错误标志:
-
虽然配置继续了,但 CMake 会记录下“至少发生了一个错误”的状态。
-
-
阻止生成阶段:
-
当配置阶段完全结束后,CMake 会检查错误状态。
-
如果存在任何
SEND_ERROR
(或FATAL_ERROR
),CMake 将跳过生成阶段。 -
它不会创建或更新任何构建系统文件(如
Makefile
)。如果你之前已经成功生成过,旧的构建文件依然存在,但它们很可能是基于过时的配置,不应该被使用。
-
-
返回非零退出码:
-
整个过程结束时,CMake 会返回一个非零的退出代码,这对于 CI/CD 流水线或其他脚本化流程来说非常重要,因为它们可以据此判断构建失败。
-
一个简单的例子
假设我们有如下 CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.10)
project(MyProject)message(STATUS "This is a status message. Configuration is proceeding...")# 假设我们检查某个必备的依赖项
if (NOT EXISTS "/usr/include/somelib.h")message(SEND_ERROR "Critical library 'somelib' was not found!")
endif()# 即使上面出错了,下面的代码依然会被执行
message(STATUS "This message will still be printed.")
set(SOURCES main.cpp)# 尝试添加一个目标,这也会被执行,但最终不会生成构建系统
add_executable(my_app ${SOURCES})
运行 cmake -B build
后,输出将会是:
-- This is a status message. Configuration is proceeding...
CMake Error at CMakeLists.txt:7 (message):Critical library 'somelib' was not found!
-- This message will still be printed.
-- Configuring incomplete, errors occurred!
你会注意到:
-
两个
STATUS
消息都打印了。 -
add_executable
命令也被处理了(虽然你看不到直接输出,但 CMake 内部已经知道了my_app
目标)。 -
最后,CMake 报告 “Configuring incomplete, errors occurred!”。
-
查看
build/
目录,你会发现没有生成Makefile
(或者它没有被更新)。
主要用途
message(SEND_ERROR)
的典型使用场景是:在配置阶段进行条件检查,如果条件不满足就报错,但同时希望收集所有可能的错误,而不是在第一个错误处就停止。
-
检查必需的编译器标志:检查编译器是否支持某个必需的标志,如果不支持则报错。
-
验证用户提供的选项:检查用户通过
-D
传递的参数是否有效、是否相互兼容。 -
寻找强制性依赖:如上例所示,如果项目绝对需要一个第三方库,但没找到,就使用
SEND_ERROR
。这比立即FATAL_ERROR
更好,因为你可以一次性地告诉用户所有缺失的依赖,而不是让他们修复一个,重新运行,再发现下一个,如此反复。
与其他 message()
类型的对比
类型 | 目的 | 对流程的影响 |
---|---|---|
| 打印信息性消息,通常用于向用户报告进度。 | 无。配置和生成照常进行。 |
| 打印警告消息。警告通常表示有问题,但构建仍可继续。 | 无。配置和生成照常进行,但会高亮显示警告。 |
| 打印错误消息。表示遇到了问题。 | 配置阶段继续,但生成阶段被跳过。构建无法进行。 |
| 打印错误消息。表示遇到了严重问题。 | 立即终止整个 CMake 进程(配置和生成都立即停止)。 |
| 警告用户某个功能已被弃用。 | 如果 |
最佳实践和注意事项
-
不要滥用:
SEND_ERROR
应该用于真正的错误条件,即会使后续构建失败的条件。对于可以绕过的可选功能或仅仅是警告,使用WARNING
。 -
提供清晰的错误信息:错误信息应该明确地指出是什么错了以及用户应该如何修复它。例如,不要只说 “Library not found”,最好说 “LibXYZ not found. Please install the libxyz-dev package or set -DXYZ_ROOT to its installation directory.”
-
与
option()
或set(CACHE)
结合使用:通常,你会先提供一个选项让用户设置路径,如果路径无效,再使用SEND_ERROR
报错。 -
与
find_package()
结合使用:很多FindXXX.cmake
模块在找不到包时会使用SEND_ERROR
或FATAL_ERROR
。
总结
message(SEND_ERROR)
是 CMake 中一个非常有用的流程控制命令。它就像一个“温和的杀手”:
-
温和在于:它允许配置阶段完成其工作,让你能一次性看到所有问题,极大提高了调试效率。
-
杀手在于:它最终会阻止构建系统的生成,确保在有问题的情况下不会进行徒劳的构建。
示例
我们来看看这个目录结构
📂 目录结构
test/
├── CMakeLists.txt
└── main.cpp
📄 main.cpp
#include <iostream>
int main() {std::cout << "Hello, CMake!" << std::endl;return 0;
}
📄 CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(SendErrorExample)# 输出一个错误,但配置继续进行
message(SEND_ERROR "❌ 这是一个错误:缺少依赖库 foo")add_executable(hello main.cpp)
message("我是最后一句")
其实我们可以一键复制下面这个命令来一键搭建出这个目录结构和文件
mkdir -p test && \
cat > test/main.cpp <<'EOF'
#include <iostream>
int main() {std::cout << "Hello, CMake!" << std::endl;return 0;
}
EOFcat > test/CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.10)
project(SendErrorExample)# 输出一个错误,但配置继续进行
message(SEND_ERROR "❌ 这是一个错误:缺少依赖库 foo")add_executable(hello main.cpp)
message("我是最后一句")
EOF
接下来我们就来构建我们的项目
cd test && \
mkdir build && cd build && \
cmake ..
我们看到这里出现了红色字体,并且执行完了整个CMakeLists.txt。
接下来我们进行构建
cmake --build .
我们发现构建不了项目了!!这就是message的SEND_ERROR模式的特别之处。
WARNING和SEND_ERROR模式的区别是:
-
WARNING
→ 只提示警告,构建继续 -
SEND_ERROR
→ 报错,但不会立刻中止 CMake 配置,会继续执行完剩余的 CMake 脚本。但是最后生成的 Makefile 是不完整的,无法编译成功。
1.5.FATAL_ERROR
1️⃣ FATAL_ERROR
的关键特点
-
一旦遇到
message(FATAL_ERROR ...)
,CMake 立即中断,不会再执行后续命令。 -
配置阶段结束时,只会生成很少的临时文件,不会产生 Makefile。
2️⃣ SEND_ERROR
的对比
如果是 SEND_ERROR
:
-
会报错,但 CMakeLists.txt 后面的语句会继续执行。
-
但是配置最后依然失败 → 没有可用的 Makefile。
示例1
我们来看看这个目录结构
📂 目录结构
test/
├── CMakeLists.txt
└── main.cpp
📄 main.cpp
#include <iostream>
int main() {std::cout << "Hello, CMake!" << std::endl;return 0;
}
📄 CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(FatalErrorExample)# 输出一个致命错误,直接中止配置
message(FATAL_ERROR "💥 致命错误:缺少关键依赖,无法继续!")add_executable(hello main.cpp)
message("我是最后一句")
其实我们可以一键复制下面这个命令来一键搭建出这个目录结构和文件
mkdir -p test && \
cat > test/main.cpp <<'EOF'
#include <iostream>
int main() {std::cout << "Hello, CMake!" << std::endl;return 0;
}
EOFcat > test/CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.10)
project(FatalErrorExample)# 输出一个致命错误,直接中止配置
message(FATAL_ERROR "💥 致命错误:缺少关键依赖,无法继续!")add_executable(hello main.cpp)
message("我是最后一句")
EOF
接下来我们就来构建我们的项目
cd test && \
mkdir build && cd build && \
cmake ..
我们看到这里出现了红色字体,但是我们发现这里没有打印出我们在CMakeLists.txt里面最后写的message("我是最后一句")。
这就是message的FATAL_ERROR模式的特点——CMake 直接中断,不会继续执行message(FATAL_ERROR……)后面的的语句。
接下来我们进行构建
cmake --build .
我们发现构建不了项目了!!这里和SEND_ERROR其实是一样的。
⚠️ 和
SEND_ERROR
的不同:
-
FATAL_ERROR
:CMake 直接中断,不会继续执行后面的add_executable
。 -
SEND_ERROR
:报错,但会继续执行剩下的命令,最后仍然失败。