web-dev-qa-db-ja.com

Makefileの警告とエラーのカラー強調表示

正常に機能するMakefileを作成しました。私は調査中のその部分を投稿しています:

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

外部ツール(colorgccやCMakeなど)を使用せずにコンパイラーによって与えられた警告とエラーを強調したいと思います。私はそれをハッキングするための良い方法は「bashスクリプトトリック」を経由することだと思った。 make出力で警告行とエラー行を強調表示するにはどうすればよいですか? 私は以下を試しました:

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

しかし、それは機能していません。次の出力が表示されます

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

前もって感謝します!

17
helmet_23

うまくいきました。

まず、@ EtanReisnerと@riciに感謝します。これがコードです:

_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
_

_make -j_を使用して並列ビルドを起動すると、ビルドされた各ファイルに対してすべての出力(コマンド文字列と警告/エラー)が一貫してグループ化されるため、すべてのコマンドは1つのechoによって呼び出されます。

$(BUILD_PRINT)は、現在ビルドされているファイルのパスを出力するだけです。

$(COMPILE_cpp)は、コンパイラの文字列を出力するので、すべてのフラグ/依存関係/その他を含むコマンドを表示できます...

$(COMPILE_cpp_OUT)は、コンパイラの出力を保存し、sedコマンドを使用して関連するWordの色を変更します。

8
helmet_23

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)として使用します

最初のオプションと2番目のオプションのどちらでも問題ない可能性があります。 (使用する := の代わりに = 最初のオプションでは、ccredが使用されるたびではなく、makeの解析時に、makeがechoコマンドを1回だけ実行するようにします。)

makeとShell変数は接頭辞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]}"_を使用することをお勧めします。

13
Etan Reisner