About the GNU make dependency files *.d

Responding to K Mulier: Try:

gmake -C $workdir ... 
That sets
CURDIR = ${workdir}
but leaves $PWD (from env) alone. All temp/output files are created in ${workdir}. Also, I set the variable $. = ${PWD} and use that to specify anything relative to the dir in which gmake was run (i.e. the source dir). So, instead of
CPPFLAGS += -I../include

there is

CPPFLAGS += -I$.  -I$./../include

Exit on all errors

@set -e;

Delete existing dep file ($@ = target = %.d)

rm -f $@;

Have the compiler generate the dep file and output to a temporary file postfixed with the shell pid ($< = first prerequisite = %.c, $$$$ -> $$ -> pid)

$(CC) -M $(CPPFLAGS) $< > $@.$$$$;

Capture the target matching $*.o ($* = match stem = %), replace it with the target followed by the dependency file itself, output to dep file

sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \

Delete temp dep

rm -f $@.$$$$

Let's plug in foo, CC = gcc, and CPPFLAGS = '' to see what happens after make has finished expanding stuff:

foo.d: foo.c
    @set -e; rm -f foo.d; \
     gcc -M foo.c > foo.d.$$; \
     sed 's,\(foo\)\.o[ :]*,\1.o foo.d : ,g' < foo.d.$$ > foo.d; \
     rm -f foo.d.$$

The shell itself will expand $$ to the pid, and the final rule in the dep file will look something like

foo.o foo.d : foo.c foo.h someheader.h

Note that this is a pretty outdated way of generating dependencies, if you're using GCC or clang you can generate them as part of compilation itself with CPPFLAGS += -MMD -MP.

Say you have a program called foo:

objs := foo.o bar.o
deps := $(objs:.o=.d)

vpath %.c $(dir $(MAKEFILE_LIST))

CPPFLAGS += -MMD -MP

foo: $(objs)

.PHONY: clean
clean: ; $(RM) foo $(objs) $(deps)

-include $(deps)

That's all you need, the built-in rules will do the rest. Obviously things will be a little more complicated if you want the object files in a different folder or if you want to build outside the source tree.

The vpath directive allows you to run make in a different directory and have the files created there, e.g. make -f path/to/source/Makefile.