Avoid duplicating GNU Make rules

2019-06-22 03:30发布

问题:

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?

回答1:

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) $$<))


回答2:

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).