- 构建工具
- 开发工具
- CLI
【免费下载链接】CMake
Mirror of CMake upstream repository
CLICOLOR 是 CMake 3.21 起引入的终端颜色控制环境变量,用于告诉 CMake 命令行工具在连接到终端时是否输出彩色消息。本文以 Help/envvar/CLICOLOR.rst 为骨架,结合 CMake 源码中的实际实现(Source/cmStdIoTerminal.cxx 与 Source/cmStdIoStream.cxx),完整讲解 CLICOLOR 的取值语义、与其他颜色控制变量的优先级关系、底层判定逻辑,以及在实际构建和 CI 场景中的用法,帮助你彻底掌控 CMake 输出颜色的开关。
一、CLICOLOR 是什么
CLICOLOR 是一个 CMake环境变量(Environment Variable),其初始值取自调用进程的环境。按照 Help/envvar/include/ENV_VAR.rst 的通用说明,它与普通 CMake 变量不同,不需要在 CMakeLists.txt 中set(),而是直接继承自 shell 或启动 CMake 的进程。
它的语义非常简洁:
将 CLICOLOR 设置为
0,可以告诉命令行工具即使连接到了终端也不要打印彩色消息。
这一约定并非 CMake 独创,而是命令行工具圈的"通用惯例"(common convention):许多终端程序都遵守同一套规则——CLICOLOR=0表示禁用颜色,CLICOLOR_FORCE表示强制启用颜色。CMake 3.21 起遵循该惯例,将 CMake 自身的命令行工具输出(如 configure 时的诊断信息、警告、错误消息)纳入这一套统一管控。
二、三个颜色变量的职责与优先级
CLICOLOR 并不是孤立的。CMake 同时支持三个相关环境变量,文档中明确给出了优先级关系。以下是三个变量的对照总览:
| 环境变量 | 引入版本 | 生效值 | 作用 |
|---|---|---|---|
NO_COLOR | 4.1 | 非空且不等于0 | 即使连接到终端也禁用彩色消息 |
CLICOLOR_FORCE | 3.5 | 非空且不等于0 | 即使未连接到终端也强制启用彩色消息 |
CLICOLOR | 3.21 | 恰好为0 | 连接到终端时禁用彩色消息 |
优先级规则(由高到低):
- NO_COLOR一旦激活,优先于
CLICOLOR_FORCE和CLICOLOR两者; - 否则,CLICOLOR_FORCE一旦激活,优先于
CLICOLOR; - 只有前两者都未激活时,CLICOLOR的取值才生效。
也就是说,三者呈现"强制禁用 > 强制启用 > 默认禁用"的覆盖关系。更精确地说,CLICOLOR=0只有在NO_COLOR未激活且CLICOLOR_FORCE未激活时才会真正让 CMake 关闭颜色。相关文档可分别参见 Help/envvar/NO_COLOR.rst 和 Help/envvar/CLICOLOR_FORCE.rst。
三、源码实现:优先级判定究竟如何落地
上述优先级并非只写在文档里,在 CMake 源码中有完全对应的实现。CMake 在 Source/cmStdIoTerminal.cxx 中用一个立即执行的 lambda 表达式TermEnv解析这些环境变量,判定结果以cm::optional<TermKind>的形式缓存(只在进程启动时计算一次):
auto const TermEnv = []() -> cm::optional<TermKind> { /* Disable color according to https://bixense.com/clicolors/ convention. */ if (cm::optional<std::string> noColor = cmSystemTools::GetEnvVar("NO_COLOR")) { if (!noColor->empty() && *noColor != "0"_s) { return TermKind::None; } } /* Force color according to https://bixense.com/clicolors/ convention. */ if (cm::optional<std::string> cliColorForce = cmSystemTools::GetEnvVar("CLICOLOR_FORCE")) { if (!cliColorForce->empty() && *cliColorForce != "0"_s) { return TermKind::VT100; } } /* Disable color according to https://bixense.com/clicolors/ convention. */ if (cm::optional<std::string> cliColor = cmSystemTools::GetEnvVar("CLICOLOR")) { if (*cliColor == "0"_s) { return TermKind::None; } } /* GNU make 4.1+ may tell us that its output is destined for a TTY. */ if (cm::optional<std::string> makeTermOut = cmSystemTools::GetEnvVar("MAKE_TERMOUT")) { if (!makeTermOut->empty()) { return TermKind::VT100; } } return cm::nullopt; }();从源码结构可以明确推断出以下实现事实:
- 判定顺序严格固定:
NO_COLOR→CLICOLOR_FORCE→CLICOLOR→MAKE_TERMOUT,先命中者直接短路返回,这构成了文档所述优先级关系的底层保障。 - 取值判定细节:
NO_COLOR和CLICOLOR_FORCE要求"非空且不等于0"才激活;而CLICOLOR则只认恰好等于0才禁用——任何其他值(包括空值)都不会关闭颜色,这与CLICOLOR=0的语义完全吻合。 MAKE_TERMOUT的补充:如果以上三个变量都未命中,CMake 还会检查 GNU make 4.1+ 设置的MAKE_TERMOUT环境变量;非空即认为输出面向终端,强制以 VT100 模式输出颜色。这也是"CLICOLOR 未设置时彩色输出仍然可能出现"的一个重要来源。- 结果是
optional:当所有变量都未激活时返回cm::nullopt,表示"交给终端类型自动判定",此时由 Source/cmStdIoTerminal.cxx 的Print函数回退到os.Kind()获取的终端能力。
四、终端能力判定:CLICOLOR 之外的底层逻辑
当CLICOLOR等变量未介入时,CMake 输出是否彩色取决于输出流本身的TermKind,这一判定在 Source/cmStdIoStream.cxx 的流构造函数中完成:
- 类 Unix 平台:CMake 使用
isatty()判断文件描述符是否指向终端,同时检查TERM环境变量是否为已知的 VT100 兼容终端名(如xterm系列、screen、tmux等),两者都满足才将输出流标记为TermKind::VT100。 - Windows 平台:通过
GetConsoleMode探测控制台句柄,若成功启用ENABLE_VIRTUAL_TERMINAL_PROCESSING(虚拟终端处理),则视为TermKind::VT100;否则回退为通过SetConsoleTextAttribute直接设置控制台属性的TermKind::Console模式。
颜色属性的具体实现位于 Source/cmStdIoTerminal.h:TermAttr枚举定义了 19 种文本属性(Normal、前景 8 色、背景 8 色及加粗),并映射为 VT100 转义序列(如\33[31m红色、\33[32m绿色),见 Source/cmStdIoTerminal.cxx。
由此可见,CLICOLOR=0的实际效果是:在Print输出路径上,TermEnv直接返回TermKind::None,从而跳过SetVT100Attrs转义序列的写入(Source/cmStdIoTerminal.cxx),最终输出纯文本。
五、实践用法
1. 临时禁用 CMake 命令行的彩色输出
# 单条命令 CLICOLOR=0 cmake -S . -B build # 或导出到当前 shell 会话 export CLICOLOR=0 cmake --build build设置后,CMake 的 configure 诊断信息、警告、错误消息等命令行输出将不再包含 ANSI 颜色转义序列。
2. 强制启用颜色(管道/重定向场景)
当 CMake 输出被重定向到文件或通过管道传给其他工具时,默认不再着色;若希望保留颜色以便人工查看日志文件,可以使用 CLICOLOR_FORCE:
CLICOLOR_FORCE=1 cmake -S . -B build > configure.log3. 强制禁用颜色的最稳妥做法
在 CI、日志采集或文本处理场景中,若同时存在其他工具设置的CLICOLOR_FORCE,单独设置CLICOLOR=0可能无效——因为CLICOLOR_FORCE优先级更高。此时应使用最高优先级的NO_COLOR:
NO_COLOR=1 CLICOLOR=0 cmake -S . -B build4. 验证是否生效
CMake 提供的 Source/cmCTest.cxx 中的判定方式表明,CTest 同样复用cm::StdIo::Out().Kind()来判断输出流是否为 VT100 终端。你可以通过对比同一命令在设置变量前后的输出来验证:在支持彩色的终端中,CLICOLOR=0 cmake -S . -B build应输出不带转义码的纯文本,例如重定向到文件后用cat -v build.log | grep '\^\\['检查是否残留^[开头的 ANSI 序列。
六、与生成系统的颜色控制:CMAKE_COLOR_DIAGNOSTICS
需要特别区分的是:CLICOLOR 只影响 CMake 自身命令行工具的运行时输出。对于"生成出来的构建系统"(如 Makefile 或 Ninja 构建过程中的编译诊断颜色),则要使用CMAKE_COLOR_DIAGNOSTICS变量控制,详见 Help/variable/CMAKE_COLOR_DIAGNOSTICS.rst。
该变量有三种状态,控制面更广:
- 未定义:Makefile 生成器将
CMAKE_COLOR_MAKEFILE初始化为ON,GNU/Clang 编译器不带颜色诊断参数; - ON:Makefile 生成器默认产生彩色构建消息(可通过
CMAKE_COLOR_MAKEFILE=OFF显式关闭),GNU/Clang 编译器追加-fcolor-diagnostics; - OFF:Makefile 生成器默认不产生彩色构建消息(可通过
CMAKE_COLOR_MAKEFILE=ON显式开启),GNU/Clang 编译器追加-fno-color-diagnostics。
此外,如果设置了CMAKE_COLOR_DIAGNOSTICS对应的同名环境变量,其值也会被采用。因此一份完整的"关闭所有颜色"的配置,通常需要同时考虑 CLI 层(CLICOLOR=0)与构建系统层(-DCMAKE_COLOR_DIAGNOSTICS=OFF)。
七、小结
| 场景 | 推荐设置 |
|---|---|
| 仅在交互终端禁用 CMake 命令行颜色 | export CLICOLOR=0 |
| 重定向/管道时强制保留颜色 | CLICOLOR_FORCE=1 |
| 无条件禁用命令行颜色(最高优先级) | NO_COLOR=1 |
| 关闭生成系统的编译诊断颜色 | cmake -DCMAKE_COLOR_DIAGNOSTICS=OFF |
CLICOLOR是 CMake 融入命令行工具通用颜色约定的一环:它以0为唯一"禁用"信号,并置于NO_COLOR、CLICOLOR_FORCE之后作为兜底。理解其取值语义与 Source/cmStdIoTerminal.cxx 中体现的优先级实现,再配合CMAKE_COLOR_DIAGNOSTICS区分"CLI 层"与"构建系统层"的颜色控制,即可在本地开发、日志采集、CI 流水线等不同环境中精确掌控 CMake 的彩色输出行为。
- 构建工具
- 开发工具
- CLI
【免费下载链接】CMake
Mirror of CMake upstream repository
相关推荐
如何完整导出QQ空间历史说说:从零跑通 GetQzonehistory 的新手指南
如何完整导出QQ空间历史说说:从零跑通 GetQzonehistory 的新手指南 想找一条三年前写的说说?QQ空间网页版只能翻到当前可见的页面,更早的只能去消
网页爬虫数据分析ZeroTermux 终端色彩定制指南:dircolors 命令与 LS_COLORS 环境变量完全解析
ZeroTermux 终端色彩定制指南:dircolors 命令与 LS_COLORS 环境变量完全解析 导读 在 ZeroTermux 这类运行于 Andro
移动开发开发工具终极todo.txt-cli色彩配置指南:美化命令行输出的完整教程
终极todo.txt cli色彩配置指南:美化命令行输出的完整教程 todo.txt cli是一款简单且可扩展的命令行工具,用于管理你的todo.txt文件。通
开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考