Цветная подсветка предупреждений и ошибок Makefile
Я написал Makefile, который отлично работает; Я просто размещаю его часть:
BUILD_PRINT = @echo -e "\e[1;34mBuilding $<\e[0m"
COMPILE_cpp = $(CXX) $(CFLAGS) -o [email protected] -c $< $(MAKEDEP) $(INCLUDES)
%.o : %.cpp
$(BUILD_PRINT)
$(COMPILE_cpp)
.SUFFIXES: .o .cpp
Я хотел бы выделить предупреждения и ошибки, предоставленные компилятором, без использования внешних инструментов (таких как colorgcc или CMake); Я подумал, что хороший способ взломать его можно с помощью "bash script трюков". Глядя на решение, опубликованное в Как я могу выделить строки предупреждений и ошибок в выходном файле? Я пробовал следующее:
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 [email protected] -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
но он не работает. Я получаю следующий вывод
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
Спасибо заранее!
Ответы
Ответ 1
Сработало.
Прежде всего спасибо @EtanReisner и @rici. Здесь код:
BUILD_PRINT = \e[1;34mBuilding $<\e[0m
COMPILE_cpp = $(CXX) $(CFLAGS) -o [email protected] -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
Все команды вызывают только один echo
, потому что я хочу, чтобы все выходы (командная строка и предупреждения/ошибки) были сгруппированы для каждого файла, созданного при запуске параллельной сборки с помощью make -j
.
$(BUILD_PRINT)
просто печатает путь к файлу, который в настоящее время строится.
$(COMPILE_cpp)
выводит строку компилятора, чтобы я мог видеть команду со всеми флагами/зависимостями/etc...
$(COMPILE_cpp_OUT)
хранит выходные данные компилятора и изменяет соответствующий цвет слов с помощью команды sed
.
Ответ 2
В контексте make следующие строки не ведут себя так, как они были бы в оболочке:
ccred=$(echo -e "\033[0;31m")
ccyellow=$(echo -e "\033[0;33m")
ccend=$(echo -e "\033[0m")
В оболочке они помещают эхо-результат в эти переменные. В make, который пытается запустить команду echo
, которая не существует, и заканчивает создание пустых переменных.
Эти строки должны быть
-
ccred=$(shell echo -e "\033[0;31m")
для запуска команд через оболочку и сохранения вывода, а затем используется как $(ccred)
в теле
-
ccred=\033[0;31m
, чтобы сохранить строку в переменной, а затем использоваться как $$(echo -e '$(ccred)')
в теле
-
ccred=echo -e "\033[0;31m"
, чтобы сохранить команду в переменной, а затем использоваться как $$($(ccred)
в теле
Любой из первых или вторых вариантов, скорее всего, прав. (Используйте := вместо = в первом параметре, чтобы иметь возможность запускать только команду echo один раз, при выполнении времени синтаксического анализа вместо каждого использования ccred
).
make и переменные оболочки совместно используют префикс sigil $. Таким образом, для использования переменных оболочки в контекстах make требуется экранирование $ в контексте оболочки, удвоив его до $$. Как таковой s%$pathpat%$ccred&$ccend%g
должен быть s%$$pathpat%$$ccred&$$ccend%g
и т.д.
Каждая строка тела правила make выполняется как отдельная команда оболочки, поэтому команды не могут взаимодействовать друг с другом. Поэтому для использования конструкций, подобных echo "${PIPESTATUS[0]}"
, поэтому требуется, чтобы они находились в одной командной строке в make. Таким образом, строка компиляции в этом правиле шаблона должна быть $(COMPILE_cpp) 2>&1 | sed ...; echo "${PIPESTATUS[0]}"
.
Однако даже это не будет делать то, что вам нужно, поскольку вам не нужно эхо-статус выхода из компиляции, с которой вам нужно выйти, поэтому вы, вероятно, захотите ; exit "${PIPESTATUS[0]}"
там.