make


How to do a multi-line bash script, including here-doc, in a Makefile:

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