Color highlighting of Makefile warnings and errors Color highlighting of Makefile warnings and errors bash bash

Color highlighting of Makefile warnings and errors


In make context the following lines do not behave the way they would in the shell:

ccred=$(echo -e "\033[0;31m")ccyellow=$(echo -e "\033[0;33m")ccend=$(echo -e "\033[0m")

In the shell those would put the echoed output into those variables. In make that tries to run the echo command, which doesn't exist, and ends up creating empty variables.

Those lines should either be

  • ccred=$(shell echo -e "\033[0;31m") to run the commands through the shell and store the output and then used as $(ccred) in the body
  • ccred=\033[0;31m to store the string in the variable and then used as $$(echo -e '$(ccred)') in the body
  • ccred=echo -e "\033[0;31m" to store the command in the variable and then used as $$($(ccred) in the body

Either of the first or second options is likely fine. (Use := instead of = in the first option to have make only run the echo command once, at make parse time, instead of every time ccred is used.)

make and shell variables share a prefix sigil $. As such to use shell variables in make contexts requires escaping the $ in shell contexts by doubling it to $$. As such s%$pathpat%$ccred&$ccend%g needs to be s%$$pathpat%$$ccred&$$ccend%g, etc.

Each line of a make rule body is executed as a distinct shell command, as such the commands cannot interact with each other. In order to use constructs like echo "${PIPESTATUS[0]}" meaningfully therefore requires that they be on the same command line in make. As such the compile line in that pattern rule would need to be $(COMPILE_cpp) 2>&1 | sed ...; echo "${PIPESTATUS[0]}".

However, even that isn't going to do what you want since you don't need to echo the exit status from the compilation you need to exit with it, so you probably want ; exit "${PIPESTATUS[0]}" there instead.


Got it working.

First of all thanks @EtanReisner and @rici. Here's the code:

BUILD_PRINT = \e[1;34mBuilding $<\e[0mCOMPILE_cpp = $(CXX) $(CFLAGS) -o $@ -c $< $(MAKEDEP) $(INCLUDES)COMPILE_cpp_OUT=$$($(COMPILE_cpp) 2>&1 | sed -e 's/error/\\\e[1;31merror\\\e[0m/g' -e s/warning/\\\e[1;33mwarning\\\e[0m/g')%.o : %.cpp    @echo -e "$(BUILD_PRINT)\n$(COMPILE_cpp)\n$(COMPILE_cpp_OUT)".SUFFIXES: .o .cpp

All the commands are invoked by only one echo because I want all the outputs (command string and warnings/errors) coherently grouped for each file built when I launch a parallel build with make -j.

$(BUILD_PRINT) just prints out the path of the file currently being built.

$(COMPILE_cpp) prints out the string of the compiler, so that I can see the command with all the flags/dependencies/etc...

$(COMPILE_cpp_OUT) stores the output of the compiler and change some relevant word colour via sed command.