To include or -include auto-generated dependencies

2019-04-15 17:44发布

I like to use the g++ -MM feature to auto-build my dependencies. The way I do this is as follows:

include $(ALLOBJ:%.o=%.d)

%.d: %.cxx
    @echo making dependencies for $<
    @g++ -MM $(CXXFLAGS) $< -o $@
    @sed -i 's,$*\.o,& $@ ,g' $@

Basically I can give this rule ALLOBJ, and it will:

  1. convert every .o name to a .d name, and include it,
  2. when it can't find a .d, it will create it from the .cxx file
    • the final line of the %.d: %.cxx rule will add the name of the .d file to the file itself, so that the dependency will be updated automatically.

The issue arises when I remove a header: the .d file still expects to find it, and make will get upset when it's not there. One solution is to replace include with -include, and to build the dependencies within the compile rule. Unfortunately this requires a dependency generation line for each compile rule, and will also ignore all other include errors (which seems risky). Is there some other simple way to auto-build dependencies which avoids this issue?

标签: makefile g++
2条回答
我想做一个坏孩纸
2楼-- · 2019-04-15 17:52

Reading the manual a bit more, and thanks to @jackKelly and @Beta's responses above, I found the following solution:

include $(ALLOBJ:%.o=%.d)

%.d: %.cxx
    @echo making dependencies for $<
    @g++ -MM -MP -MT $*.d -MT $*.o $(CXXFLAGS) $< -o $@

To summarize the flags:

  • -MM: build dependencies (rather than compiling)
  • -MP: build 'dummy' targets for all headers. This prevents make from complaining when headers are deleted and thus can't be found.
  • -MT: specify the targets for the rule. This allows us to tell make the .d file depends on the headers without resorting to the ugly sed rule.

I don't believe my solution is any more correct than @Beta's solution. I tend to use multiple compile rules for C++ files in the same makefile, so having a single dependency rule for all of them is slightly cleaner (in my case) than generating the dependencies in each compile rule.

查看更多
Ridiculous、
3楼-- · 2019-04-15 18:05

To restate my answer to the other question, I do it this way:

%.o: %.cpp
    @echo making $@ and dependencies for $< at the same time
    @$(CC) -MD -c $(CXXFLAGS) -o $@ $<
    @cp $*.d $*.P
    @sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
         -e '/^$$/ d' -e 's/$$/ :/' < $*.P >> $*.d
    @rm $*.P

-include $(ALLOBJ:%.o=%.d)

EDIT:

It... It produces the dependency file, but more cleanly and without the sed command:

%.o: %.cpp
    @echo making $@ and dependencies for $< at the same time
    @$(CC) -c $(CXXFLAGS) -o $@ $<
    @$(CC) -MM -MP $(CXXFLAGS) $< -o $*.d

-include *.d

So now I have to modify the %.o rule in my own makefiles. From now on there'll be a little bit of @JackKelly in everything I compile, mocking me. Oh, this is a black day.

查看更多
登录 后发表回答