【问题标题】:How to get colorized output with cmake?如何使用 cmake 获得彩色输出?
【发布时间】:2013-09-28 22:10:01
【问题描述】:

我想在CMakeLists.txt 中有消息功能,它输出彩色文本。也许是一个转义序列。

例如:

message("\x1b[31m;This text must be in red")

它不起作用。我得到了:

Syntax error in cmake code at

/home/taurus/cmakecolor/CMakeLists.txt:1

when parsing string

\x1b[31m;This text must be in red

Invalid escape sequence \x

【问题讨论】:

  • 错误是因为你没有转义反斜杠。应该是message("\\x1b[31m;Red"),但还是不行……
  • cmake -E echo 也不走运。我不认为它只适用于 CMake,您可能必须调用外部命令,例如 echo
  • 如果您的编辑允许,添加文字转义对我来说效果很好。例如,在 vim 插入模式下输入 ctrl-v,然后输入 escape,你会得到一个字符 ^[。正在寻找一个 cmake 实际支持的转义序列。

标签: cmake


【解决方案1】:

为了扩展@grim 的正确答案,您可以通过设置变量来处理各种颜色来使事情变得更方便:

if(NOT WIN32)
  string(ASCII 27 Esc)
  set(ColourReset "${Esc}[m")
  set(ColourBold  "${Esc}[1m")
  set(Red         "${Esc}[31m")
  set(Green       "${Esc}[32m")
  set(Yellow      "${Esc}[33m")
  set(Blue        "${Esc}[34m")
  set(Magenta     "${Esc}[35m")
  set(Cyan        "${Esc}[36m")
  set(White       "${Esc}[37m")
  set(BoldRed     "${Esc}[1;31m")
  set(BoldGreen   "${Esc}[1;32m")
  set(BoldYellow  "${Esc}[1;33m")
  set(BoldBlue    "${Esc}[1;34m")
  set(BoldMagenta "${Esc}[1;35m")
  set(BoldCyan    "${Esc}[1;36m")
  set(BoldWhite   "${Esc}[1;37m")
endif()

message("This is normal")
message("${Red}This is Red${ColourReset}")
message("${Green}This is Green${ColourReset}")
message("${Yellow}This is Yellow${ColourReset}")
message("${Blue}This is Blue${ColourReset}")
message("${Magenta}This is Magenta${ColourReset}")
message("${Cyan}This is Cyan${ColourReset}")
message("${White}This is White${ColourReset}")
message("${BoldRed}This is BoldRed${ColourReset}")
message("${BoldGreen}This is BoldGreen${ColourReset}")
message("${BoldYellow}This is BoldYellow${ColourReset}")
message("${BoldBlue}This is BoldBlue${ColourReset}")
message("${BoldMagenta}This is BoldMagenta${ColourReset}")
message("${BoldCyan}This is BoldCyan${ColourReset}")
message("${BoldWhite}This is BoldWhite\n\n${ColourReset}")

如果你真的想把船推出来,你可以用你自己的替换内置的 message 函数,它会根据消息类型对输出进行着色:

function(message)
  list(GET ARGV 0 MessageType)
  if(MessageType STREQUAL FATAL_ERROR OR MessageType STREQUAL SEND_ERROR)
    list(REMOVE_AT ARGV 0)
    _message(${MessageType} "${BoldRed}${ARGV}${ColourReset}")
  elseif(MessageType STREQUAL WARNING)
    list(REMOVE_AT ARGV 0)
    _message(${MessageType} "${BoldYellow}${ARGV}${ColourReset}")
  elseif(MessageType STREQUAL AUTHOR_WARNING)
    list(REMOVE_AT ARGV 0)
    _message(${MessageType} "${BoldCyan}${ARGV}${ColourReset}")
  elseif(MessageType STREQUAL STATUS)
    list(REMOVE_AT ARGV 0)
    _message(${MessageType} "${Green}${ARGV}${ColourReset}")
  else()
    _message("${ARGV}")
  endif()
endfunction()

message("No colour at all.")
message(STATUS "\"Colour\" is spelled correctly.")
message(AUTHOR_WARNING "\"Color\" is misspelled.")
message(WARNING "Final warning: spell \"color\" correctly.")
message(SEND_ERROR "Game over.  It's \"colour\", not \"color\".")
message(FATAL_ERROR "And there's no \"z\" in \"colourise\" either.")

我不能说我建议以这种方式覆盖内置的message 函数,但话虽如此,我也没有发现这样做有任何重大问题。

【讨论】:

  • 这对于 cmake 模块来说听起来是个好主意 ;) 另外,win32 检查也不错。
  • 是 scape 序列有错误吗?这个例子对我有用,因为改变颜色。我的工作景观序列设置(ColourReset "${Esc}[0m") 为 0,至少在 Windows 中(在 python 子进程和 colorama 下运行,它可能使用不同的景观?)
  • @drodri 我认为我只在 Linux 上测试过这个 - 你可能是对的。
  • 不错!似乎可以与 message 函数一起使用,但是,我不确定 cmake 使用什么函数来打印输出,因为它们的输出不受影响。
  • 从 Windows 10 th2 开始原生支持 ANSI 转义序列。但是,cmd 中的 cmake 仍然存在一些问题,阻止它产生彩色输出(即使批处理文件工作正常)。
【解决方案2】:

一个更简单的解决方案可能只是使用 CMake 的内置功能来发出彩色输出,即这些命令

不同的颜色

cmake -E cmake_echo_color --normal hello
cmake -E cmake_echo_color --black hello
cmake -E cmake_echo_color --red hello
cmake -E cmake_echo_color --green hello
cmake -E cmake_echo_color --yellow hello
cmake -E cmake_echo_color --blue hello
cmake -E cmake_echo_color --magenta hello
cmake -E cmake_echo_color --cyan hello
cmake -E cmake_echo_color --white hello

粗体字

cmake -E cmake_echo_color --red --bold hello

没有换行

cmake -E cmake_echo_color --red --no-newline hello

在 CMake 中,您可以使用 execute_process() 命令调用 ${CMAKE_COMMAND}。您可以为此编写一个方便的函数。

更新:使用 cmake_echo_colorexecute_process()

正如@sjm324 所指出的那样

execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold hello)

不起作用。看实现https://github.com/Kitware/CMake/blob/10371cd6dcfc1bf601fa3e715734dbe66199e2e4/Source/kwsys/Terminal.c#L160

我的猜测是标准输出未附加到终端,因此当 CMake 内部调用 isatty() 时失败。

我有两个 hack 可以解决这个问题,但如果你真的关心这个,你应该联系 CMake 开发人员以获得一个不那么脆弱的解决方案

HACK 1:设置CLICOLOR_FORCE=1 环境变量。

execute_process(COMMAND 
  ${CMAKE_COMMAND} -E env CLICOLOR_FORCE=1
    ${CMAKE_COMMAND} -E cmake_echo_color --red --bold hello
)

这不是一个好主意。如果您将构建的输出记录到文件中 它里面会有转义序列,因为你强迫它们 总是发出。

HACK 2:将 OUTPUT_FILE 设置为 TTY

不要这样做。 HACK 1 可能更便携。

execute_process(COMMAND
  /usr/bin/tty
  OUTPUT_VARIABLE TTY_NAME
OUTPUT_STRIP_TRAILING_WHITESPACE)

execute_process(COMMAND
  ${CMAKE_COMMAND} -E cmake_echo_color --red --bold hello
  OUTPUT_FILE ${TTY_NAME})

【讨论】:

  • 这不起作用,例如execute_process(COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --red --bold hello) 将被剥夺其颜色。如果它对你有用,请用你所做的更新你的答案?
  • @sjm324 是的。 execute_process(...) 不起作用,因为标准输出未连接到终端。不过,我有一些技巧可以完成这项工作。
  • 哈! LOL 很好,这绝对是 hacky :) 没有附加 STDOUT 是关键。感谢您拼写出来!
  • 一个更好的技巧是设置OUTPUT_FILE /dev/stdout ERROR_FILE /dev/stderr。然后它从父进程继承文件描述符,并且应该正确地确定它是否是 tty。不确定这个的可移植性,但我不认为它会比 HACK 2 更糟。
【解决方案3】:

虽然繁琐,但您可以定义一个包含转义字符的变量并在消息字符串中使用它

string(ASCII 27 ESCAPE)
message("${ESCAPE}[34mblue${ESCAPE}[0m")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    相关资源
    最近更新 更多