0

I'm trying to figure out how to implement this Makefile code for generating dependencies.

depend: .depend

.depend: $(SRCS)
        rm -f ./.depend
        $(CC) $(CFLAGS) -MM $^ >  ./.depend;

include .depend

However, I have to modify it so that .depend will be regenerated each time make is run. I Have tried to accomplish this by making a phony target that calls rm -f ./.depend, but, not matter how I arrange things, it always runs after .depend and before include. On the other hand, if I could just get the .depend recipe to run no matter what, that would work even better.

Community
  • 1
  • 1
Matt Munson
  • 2,903
  • 5
  • 33
  • 52
  • If you're going to get the dependencies every time, you may as well just compile every time, I think. The compiler has to process the source to get the dependencies, so that a major part of the compilation is done each time anyway (up to and including the pre-processor, at least). – Jonathan Leffler Apr 07 '13 at 01:09
  • @Jonathan the compiler does not have to process the source, it just gets the list of header files that each object needs. And I can say empirically that there is a difference, because it compiles much faster this way. – Matt Munson Apr 07 '13 at 01:16
  • To determine the headers that are needed, it must read the source and pay attention to the preprocessing enough to know which headers are included under the current options and defines and so on. It doesn't have to keep the preprocessed source, or do anything else, so it is certainly simpler than full compilation, but it does have to do all the work of opening the files, which is itself fairly slow. If it works for you, fine. I've not used that technique for dependencies — I assume that dependencies are stable over long periods, and have seldom or never had problems (I can't think when I did). – Jonathan Leffler Apr 07 '13 at 01:28
  • @Jonathan Ok, I am sure you must be right that if there were enough source files and dependencies, then there would be a significant slowdown (if I understand). In any case, it seems like what I'm trying to accomplish with the Makefile should be trivial. – Matt Munson Apr 07 '13 at 01:38
  • Why rebuild `.depend` if the sources haven't changed? – Beta Apr 07 '13 at 04:23
  • @Beta If I do it this way, then I don't have to update a list of header files whenever I remove or add one. However, I did figure out that I can make `.depend` always run. The problem seems to be with include – Matt Munson Apr 07 '13 at 10:28
  • You don't have to update a list of header files whenever you remove or add one. **That's the whole point of dependency generation.** – Beta Apr 07 '13 at 11:54
  • @Beta Good point. I don't know how I was so confused about that. I still have a problem though, in that I don't understand how make knows how to build the objects, given that the dependencies file doesn't provide a command for doing so. EDIT: I just realised, what about the dependencies for the header files. If I put an include in a header, that wont update the dependencies – Matt Munson Apr 07 '13 at 16:43
  • The dependency file tells Make *when* to build a target; there must be another rule somewhere to explain *how* to build it, either in the makefile or implicit in Make. As for `#include` statements in header files, gcc is smart enough to follow them; try it. – Beta Apr 07 '13 at 17:13
  • @Beta The weird thing is that, even though I don't say how to build the object files, Make seems to know how, because it does so regardless. Except, it doesn't use my compiler flags. Once again, good point about the headers. – Matt Munson Apr 07 '13 at 17:54
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/27731/discussion-between-matt-munson-and-beta) – Matt Munson Apr 07 '13 at 17:55

2 Answers2

4

This method of handling dependencies is very sub-optimal. The best way to create dependency information is as a side-effect of compilation. It's even faster than what you're doing now since the compiler already has to compute all this information.

When you're compiling the code you already know that this instance of the build needs to rebuild the target. The side-effect of the build, creating dependency information, is for the next instance of the build. GCC provides the -MMD -MP options that make this work well. You should definitely not, in this configuration, provide a separate rule to build the included files (that will break everything). Instead, do something like this:

SRCS = foo.c bar.c baz.c ...

%.o : %.c
        $(CC) $(CPPFLAGS) $(CFLAGS) -MMD -MP -o $@ -c $<

-include $(SRCS:.c=.d)

Use -include so that if the dependency file hasn't been created yet you won't get any errors. That's it, that's all you have to do.

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • I don't understand. This includes a bunch of targets with the dependencies I need for the corresponding object files, but the object files are not dependent on `%.d`. So what do I do with those targets? – Matt Munson Apr 07 '13 at 16:31
  • 1
    Is that `include` better written as `-include`? Per GNU `make` 3.82 manual: _If you want make to simply ignore a makefile which does not exist or cannot be remade, with no error message, use the `-include` directive instead of `include`, like this: `-include filenames...`. This acts like `include` in every way except that there is no error (not even a warning) if any of the filenames (or any prerequisites of any of the filenames) do not exist or cannot be remade._ The examples for `.d` files use `include`, though, but I'm not clear on why. – Jonathan Leffler Apr 07 '13 at 16:40
  • Matt, I didn't understand your question; which targets do you mean? The .d files are generated by GCC, and they will contain make rules that define the prerequisite information for each of the object files, things like `foo.o: foo.c foo.h bar.h` etc. When make runs it will include those files and hence define the dependency information. Jonathan, you're right you need `-include` I'll edit the answer. – MadScientist Apr 07 '13 at 20:13
  • I see what you mean. I was just confused, and my question was misinformed. Thanks – Matt Munson Apr 07 '13 at 22:11
1

While I agree with the above comments that there is no benefit in regenerating your dependencies everytime, I also think it is not your job to implement all this in the first place. As a reliable build tool, makepp takes care of this for you. And it doesn't limit itself to header file dependencies but it takes everything into account, like a changed command lines, so it is more correct.

There is much more to makepp. Besides doing almost all that GNU make can, there are lots more useful things, and you can even extend your makefiles with some Perl programming.

Daniel
  • 521
  • 1
  • 4
  • 13