Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Color highlighting of Makefile warnings and errors

Tags:

I have written a Makefile which works fine; I am just posting the part of it under investigation:

BUILD_PRINT = @echo -e "\e[1;34mBuilding $<\e[0m"
COMPILE_cpp = $(CXX) $(CFLAGS) -o $@ -c $< $(MAKEDEP) $(INCLUDES)
%.o : %.cpp
    $(BUILD_PRINT)
    $(COMPILE_cpp)
.SUFFIXES: .o .cpp

I would like to highlight the warnings and errors given by the compiler without using external tools (such as colorgcc or CMake); I thought that a good way to hack it was via "bash script tricks". Looking at the solution posted in How Can I highlight the warning and error lines in the make output? I have tried the following:

pathpat="(/[^/]*)+:[0-9]+"
ccred=$(echo -e "\033[0;31m")
ccyellow=$(echo -e "\033[0;33m")
ccend=$(echo -e "\033[0m")

BUILD_PRINT = @echo -e "\e[1;34mBuilding $<\e[0m"
COMPILE_cpp = $(CXX) $(CFLAGS) -o $@ -c $< $(MAKEDEP) $(INCLUDES)
%.o : %.cpp
    $(BUILD_PRINT)
    $(COMPILE_cpp) 2>&1 | sed -e "/[Ee]rror[: ]/ s%$pathpat%$ccred&$ccend%g" -e "/[Ww]arning[: ]/ s%$pathpat%$ccyellow&$ccend%g" echo "${PIPESTATUS[0]}"
.SUFFIXES: .o .cpp

but it is not working. I get the following output

Building main.cpp
g++ -o main.o -c main.cpp  2>&1 | sed -e "/[Ee]rror[: ]/ s%athpat%cred&cend%g" -e "/[Ww]arning[: ]/ s%athpat%cyellow&cend%g" echo ""
sed: can't read echo: No such file or directory
sed: can't read : No such file or directory

Thanks in advance!

like image 837
helmet_23 Avatar asked Jun 10 '14 15:06

helmet_23


2 Answers

Got it working.

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

BUILD_PRINT = \e[1;34mBuilding $<\e[0m

COMPILE_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.

like image 23
helmet_23 Avatar answered Sep 27 '22 16:09

helmet_23


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.

like image 121
Etan Reisner Avatar answered Sep 27 '22 18:09

Etan Reisner