Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get colorized output with cmake?

Tags:

cmake

I want to have message function in CMakeLists.txt which output colorized text. Maybe an escape sequence.

For example:

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

It don't work. I got:

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
like image 667
Ivan Romanov Avatar asked Sep 23 '13 21:09

Ivan Romanov


3 Answers

To extend @grim's correct answer, you can make things a bit more convenient by setting up variables to handle the various colours:

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}") 

If you really fancy pushing the boat out, you can replace the built-in message function with your own which colourises the output depending on the message type:

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.") 

I can't say that I recommend overriding the built-in message function in this way, but having said that, I've not found any major problems with doing this either.

like image 120
Fraser Avatar answered Sep 21 '22 06:09

Fraser


A simpler solution is probably just to use CMake's built-in capability for emitting coloured output, i.e. these commands

Different colors

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 

Bold text

cmake -E cmake_echo_color --red --bold hello 

No new line

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

From CMake you can use the execute_process() command to invoke ${CMAKE_COMMAND}. You could write a convenient function for doing this.

UPDATE: Using cmake_echo_color with execute_process()

As pointed out by @sjm324 running

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

does not work. Looking at the implementation https://github.com/Kitware/CMake/blob/10371cd6dcfc1bf601fa3e715734dbe66199e2e4/Source/kwsys/Terminal.c#L160

my guess is that standard output is not attached to the terminal and thus when CMake internally calls isatty() this fails.

I have two hacks that workaround this but really if you care about this you should contact the CMake devs for a less fragile solution

HACK 1: Set CLICOLOR_FORCE=1 environment variable.

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

This isn't a great idea. If you log the output of your build to a file it will have escape sequences in it because you're forcing them to be emitted always.

HACK 2: Set OUTPUT_FILE to be the TTY

Don't do this. HACK 1 is likely more portable.

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}) 
like image 23
delcypher Avatar answered Sep 21 '22 06:09

delcypher


While tedious, you can define a variable that contains an escape character and use it in your message strings

string(ASCII 27 ESCAPE)
message("${ESCAPE}[34mblue${ESCAPE}[0m")
like image 36
grim Avatar answered Sep 19 '22 06:09

grim