I've been writing a Makefile that performs some dependency generation and I've found myself having to duplicate rules because the (legacy) codebase contains a mixture of .cpp
and .cc
files. It seems a bit unsightly. Is there anyway to specify that the prerequisites of a target can be either .cpp
or .cc
files?
So rather than having:
%.d : %.cpp
$(CPP) -MM $(CPPFLAGS) $<
%.d : %.cc
$(CPP) -MM $(CPPFLAGS) $<
Create something without the duplication like:
%.d : %.(cpp | cc)
$(CPP) -MM $(CPPFLAGS) $<
Or is this enforced redundancy just an unfortunate element of GNU Make's design?
First option, use a variable to define the rule body once, and reuse it as needed:
DEPGEN=$(CPP) -MM $(CPPFLAGS) $<
%.d: %.cpp ; $(DEPGEN)
%.d: %.cc ; $(DEPGEN)
Second option, use $(eval)
to dynamically generate the rules:
$(foreach src,cpp cc,$(eval %.d: %.$(src) ; $$(CPP) -MM $$(CPPFLAGS) $$<))
This should work:
%.d :: %.cpp
$(CPP) -MM $(CPPFLAGS) $<
%.d :: %.cc
$(CPP) -MM $(CPPFLAGS) $<
Another idea:
%.d : %.c
$(CPP) -MM $(CPPFLAGS) $<
%.c : %.cpp
ln $< $@ # or cp -p
Another idea is to make GNU make generate the two pattern rules.
There are essentally two ways of doing this:
- write them to makefiles (
%-cc.mk
or similar) that you include within your actual makefile with GNU make's include
statement
- generate and evaluate them inline with GNU make's
$(eval)
and $(call)
functions
Like most everything else in the C/Unix development toolchain, these techniques are essentially a form of preprocessing, making them easy to understand at the price of being really hard to use (lots of double or triple escaping, really hard to keep track of what is expanded when; debugging can be a royal pain, at least in my experience).
So reserve them for more complicated use cases (of which Stack Overflow lists a few).