5

To generate dependency files I can use something like this to generate dependency files:

-include $(patsubst %.cpp,build/%.d,$(SRC))
build/%.o: %.cpp
    $(CC) $(CXXFLAGS) -c -o $@ $<
    $(CC) $(CXXFLAGS) -MM -MT $@ -MF $(patsubst %.o,%.d,%@) $<

This generates everything and puts both the object and dependency files into the build dir where I want them. But this makes two dependency lines for the <file>.o targets, one from the -include rule and with all the header dependencies, and one which is from the pattern rule. Will this get interpreted correctly, i.e. when a header is modified, the object will be recompiled via the command specified for the pattern rule?

Edit: So this approach does in fact work quite well. I guess I'd like somebody to provide an answer which gives me some insight into what it is exactly that make does in these situations. For instance, what if a different command was given for both rules for the same target? My guess would be that it gives an error since it wouldn't be obvious which command to execute.

Steven Lu
  • 41,389
  • 58
  • 210
  • 364
  • This is specific to GNU make. You should mention that. Even though on many systems "make" is GNU make, it's not a standard by any means. – 0xC0000022L Jun 02 '11 at 13:47
  • I'm actually using MinGW-make but it does work. I can't get it to compile and generate dependency data in one command so it's split into two. – Steven Lu Jun 02 '11 at 13:51
  • MinGW uses GNU make. Check it ;) ... also see my answer below. – 0xC0000022L Jun 02 '11 at 13:56

3 Answers3

5

You should add one more pattern rule to express the dependency between the .cpp and .d files and use that rule to create the .d files (second line in the pattern rule of your question) instead of creating the .d files unconditionally. It might make sense to introduce another dependency between all .h and .cpp files and all .d files to force re-creating the .d files if a header or source file changes.

Here's the separate rule for .d files (hope I got it right):

-include $(patsubst %.cpp,build/%.d,$(SRC))
build/%.o: %.cpp
    $(CC) $(CXXFLAGS) -c -o $@ $<

build/%.d: %.cpp
    $(CC) $(CXXFLAGS) -MM -MT $@ -MF $<

Edit: So this approach does in fact work quite well. I guess I'd like somebody to provide an answer which gives me some insight into what it is exactly that make does in these situations.

I'm afraid currently it would only work by chance (or you have not given all relevant pieces from the make file). See, you have not expressed any dependency between .d files and .cpp files. This, however, is needed so that your .d files get updated before inclusion as make file fragment.

For instance, what if a different command was given for both rules for the same target? My guess would be that it gives an error since it wouldn't be obvious which command to execute.

With that syntax it wouldn't make a difference. But there are some special cases where splitting the rules into two (though otherwise identical rules) has merit. I strongly recommend you get the book "Managing Projects with GNU Make" to get a grip on the various ways of working with GNU Make. The only other recommendation in connection with GNU Make is to read to read the paper here.

0xC0000022L
  • 20,597
  • 9
  • 86
  • 152
  • Well, `g++ -MM` creates this format: `target: source.cpp header.h header2.h`. Wouldn't I need to do extensive processing to get the `.cpp`'s to depend on their corresponding headers, etc? I mean I guess I can assume that the `.cpp` is the first item after `target:` and then I can just use `sed` or something to move that colon over. – Steven Lu Jun 02 '11 at 14:01
  • @Steven Lu: no, the relevant part is to express the dependency between `.cpp` and `.d` files, which is a 1 on 1 mapping. And as I wrote the dependency between .h/.cpp and .d files would only be needed in some arcane circumstances. In most cases adding one more pattern rule for `.d` to `.cpp` dependencies and moving the command to create `.d` files into that rule, will be sufficient. – 0xC0000022L Jun 02 '11 at 14:07
  • This is strange. So I created separate dependencies for the `.d` files. Now when I run `make clean` it generates every single `.d` file. Then deletes them all. How come it thinks that the `.d` files are necessary? I'm running clean. – Steven Lu Jun 02 '11 at 14:40
  • @Steven Lu: yes, that's normal (although of course not nice). What happens here is that you always include the .d files in the make file. So GNU Make thinks it needs the .d files *even* for the `clean` target. Of course it doesn't. You can prevent this, by making your `include` statement conditional (check the name of the targets, but beware that a user can give multiple targets). – 0xC0000022L Jun 02 '11 at 14:47
  • So Make actually invokes them because it wants to include them? I never imagined it would "think ahead" quite this much.. thanks! I don't think i would ever have figured this one out on my own. – Steven Lu Jun 02 '11 at 14:54
  • @Steven Lu: *that* is one of the specialties of GNU Make. Which is why I made the remark that your question is specific to GNU Make ;) – 0xC0000022L Jun 02 '11 at 14:57
  • @STATUS_ACCESS_DENIED: There are good reasons not to have a separate rule for the .d files, as described in this article, which seems to be the last word on include dependency tracking with make: http://mad-scientist.net/make/autodep.html#noreexec – slowdog Jun 02 '11 at 15:02
  • @slowdog: Thanks for pointing that out! this all makes much more sense now. I may revert back to generating the dependency files at the same time that I compile. It just feels cleaner even if it isn't necessary all the time. – Steven Lu Jun 02 '11 at 15:07
  • @slowdog: I'm just trying to apply my experience from using a static make fragment for dependencies on the current case. From what I read at the link it merely adds another level of indirection. Which indeed could be useful. And as for "last word", well as many recursive make files as I've seen and with the downsides described in "recursive make considered harmful" I would say there is no broad consent about - well - anything when it comes to managing and building projects :) – 0xC0000022L Jun 02 '11 at 15:08
  • @Steven Lu: and how would GNU Make know to create your dependency files? Well it won't. That is my main point. You suppress errors from failed inclusion, fine. Now imagine the first run. Empty build/ folder. No .d files to include. What happens? Well, make is going to compile your .cpp files and also additionally create the .d files. But the first run always is without dependencies. How that is better is beyond me ;) – 0xC0000022L Jun 02 '11 at 15:11
  • @STATUS_ACCESS_DENIED: Touche, there is no last word. As with RCMCH, the fact that the Right Way is known and written down doesn't stop everyone from continuing to do it wrong ;-) – slowdog Jun 02 '11 at 15:35
  • "the first run always is without dependencies": Yes, and that is perfectly alright, because on that first run they are *not needed*, because we already know that everything must be rebuilt. The .d files are only needed for subsequent incremental builds. It's a bit of a headwrecker for experienced make users when you see it first, but check out the autodep paper and you too will be converted ;-) – slowdog Jun 02 '11 at 15:44
  • I think I'm going to side with @slowdog on this. I do realize that on the first run the dependencies are not there, but on the first run the dependencies are not even needed since *everything* needs to be compiled so it doesn't make a difference. – Steven Lu Jun 02 '11 at 18:05
  • Works like a charm! I was spending now several days an make until I hit this gem here. :) – Devolus Apr 19 '13 at 16:39
4

Yes, you can specify several rules for one file, and they get merged into one. See the GNU Make documentation.

[...] There can only be one recipe to be executed for a file. [...] An extra rule with just prerequisites can be used to give a few extra prerequisites to many files at once.

And I second that there should be separate rule for .d files. It's names in many projects are deps or depend.

Rajish
  • 6,755
  • 4
  • 34
  • 51
  • Like this? `-include $(patsubst %.cpp,build/%.d,$(SRC)) build/%.o: %.cpp $(CC) $(CXXFLAGS) -c -o $@ $< build/%.d: %.cpp $(CC) $(CXXFLAGS) -MM -MT $(patsubst %.d,%.o,%@) -MF $@ $<` – Steven Lu Jun 02 '11 at 14:04
  • +1 because this actually answers the original question (multiple rules about the same target), even though it's less interesting than the tangent about how best to do header dependencies. – slowdog Jun 02 '11 at 15:46
  • And this is also required by POSIX 7: http://stackoverflow.com/a/41233523/895245 `-MMD` is the way to go: http://stackoverflow.com/a/30142139/895245 – Ciro Santilli OurBigBook.com Dec 20 '16 at 01:19
0

POSIX 7 also says that multiple lines for a given target work http://pubs.opengroup.org/onlinepubs/9699919799/

A target that has prerequisites, but does not have any commands, can be used to add to the prerequisite list for that target. Only one target rule for any given target can contain commands.

so long as only one has the commands.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985