Some helpful hints: http://make.mad-scientist.net/papers/rules-of-makefiles/ define BASHSCRIPT echo "Running a bash script" cat > tmp-generated-heredoc.txt <<EOF contents of the here-doc line two line three EOF ls -lha tmp-generated-heredoc.txt rm tmp-generated-heredoc.txt endef export BASHSCRIPT runscript: bash -c "$$BASHSCRIPT" Compile target that saves the output of the compile command to a file while preserving error status (piping through tee doesn't preserve error status). The compile command (-x flag to bash) and warnings/errors (cat command) are echoed. After build, you can use a command like "find . -name "*.err" -exec ls {} \; -exec cat {} \;" to see all the warnings/errors. The " || exit 1" at the end is needed only if .ONESHELL: is defined. %.o: %.c bash -xc 'gcc -c -o $@ $(CFLAGS) $< > $(@:.o=.err) 2>&1; RV=$$?; cat $(@:.o=.err); exit $$RV' || exit 1 Stew's Makefile template (make sure to put tabs instead of spaces) CC=gcc CXX=g++ SRC:=main.c \ file1.c BUILDDIR:=build EXENAME:=helloworld vpath %.c $(dir $(SRC)) vpath %.cpp $(dir $(SRC)) OBJS:=$(patsubst %.c,$(BUILDDIR)/%.o,$(patsubst %.cpp,$(BUILDDIR)/%.o,$(notdir $(SRC)))) GCOVGCNO:=$(patsubst %.o,$(BUILDDIR)/%.gcno,$(notdir $(OBJS))) GCOVGCDA:=$(patsubst %.o,$(BUILDDIR)/%.gcda,$(notdir $(OBJS))) CFLAGS+=-Wall -Wextra -Wpedantic -Werror \ -Wlogical-op -Waggregate-return -Wfloat-equal -Wcast-align \ -Wparentheses -Wmissing-braces -Wconversion -Wsign-conversion \ -Wwrite-strings -Wunknown-pragmas -Wunused-macros \ -Wnested-externs -Wpointer-arith -Wswitch -Wredundant-decls \ -Wreturn-type -Wshadow -Wstrict-prototypes -Wunused -Wuninitialized \ -Wdeclaration-after-statement -Wmissing-prototypes \ -Wmissing-declarations -Wundef -fstrict-aliasing -Wstrict-aliasing=3 \ -Wformat=2 \ -O0 -ggdb3 \ -std=c99 -D_POSIX_C_SOURCE=200112L LDFLAGS+= .PHONY: all all: $(MAKE) $(EXENAME) -j $(shell nproc) .PHONY: coverage coverage: CFLAGS=--coverage $(MAKE) $(EXENAME) -j $(shell nproc) ./$(EXENAME) lcov -c -d . -o $(BUILDDIR)/$(EXENAME).info genhtml --legend -o $(BUILDDIR)/coveragereport $(BUILDDIR)/$(EXENAME).info $(EXENAME): $(OBJS) $(CXX) -o $@ $(CFLAGS) $^ $(LDFLAGS) $(BUILDDIR)/%.o: %.c $(CC) -c -o $@ $(CFLAGS) $< $(LDFLAGS) $(BUILDDIR)/%.o: %.cpp $(CXX) -c -o $@ $(CFLAGS) $< $(LDFLAGS) $(OBJS): | $(BUILDDIR) $(BUILDDIR): mkdir $(BUILDDIR) .PHONY: clean clean: $(RM) $(EXENAME) $(OBJS) $(GCOVGCNO) $(GCOVGCDA) $(BUILDDIR)/$(EXENAME).info $(RM) -r $(BUILDDIR)/coveragereport |