4

I am new to using make and have been learning the basics through this tutorial. Here is the final example makefile example from the tutorial:

IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)

ODIR=obj
LDIR =../lib

LIBS=-lm

_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))

_OBJ = hellomake.o hellofunc.o 
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))


$(ODIR)/%.o: %.c $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS)

hellomake: $(OBJ)
    gcc -o $@ $^ $(CFLAGS) $(LIBS)

.PHONY: clean

clean:
    rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ 

This should work fine assuming all .c files are only including hellomake.h, but it wouldn't work if each .c file was including different headers. Is it possible to write a makefile that knows what each .c file is including, so I don't have to go in and do it manually like:

foo.o: foo.c something.h
    ...

bar.o: bar.c somethingelse.h
    ...

because that seems like it would be a big waste of time.

Hugo Burd
  • 301
  • 1
  • 4
  • 12

4 Answers4

14

Suppose foo.c has a line:

#include "something.h"

You'd like a line in the makefile:

foo.o: foo.c something.h

The gcc compiler can construct that line for you. The command

gcc -MMD -c -o foo.o foo.c

will build foo.o and foo.d which contains the line. (Try it.)

So just modify your makefile to produce these *.d files and include them, and you're done:

$(ODIR)/%.o: %.c $(DEPS)
    $(CC) -MMD -c -o $@ $< $(CFLAGS)

-include $(ODIR)/*.d

(Further refinements are possible, like specifying where the *.d files should go.)

Beta
  • 96,650
  • 16
  • 149
  • 150
  • Is the `$(DEPS)` supposed to be there on the first line of your example? – Hugo Burd Mar 31 '13 at 04:12
  • @user2228139: [shrug] I left it in, but I guess it's not necessary. – Beta Mar 31 '13 at 04:33
  • How exactly do I run a command after the rule in the included .d files? After the `-include...` line I tried putting a tab and then a command like usual but it didn't work. – Hugo Burd Mar 31 '13 at 05:23
  • @user2228139: You don't need any commands after that line. But now I notice I left out the leading tab in the pattern rule... Just add the `-MMD` and the `-include...` to the example in your post, and give it a try. – Beta Mar 31 '13 at 06:03
  • There were actually some other problems that I had to fix in mine. Seems to be working fine now though, I think. – Hugo Burd Mar 31 '13 at 06:40
  • Please forgive the stupidity of this question, but in your example above, how does $(DEPS) get defined? – Andrew Falanga Apr 25 '13 at 17:50
  • 1
    @AndrewFalanga: Not a stupid question at all. The OP used `DEPS` to construct the list of prerequisites in the rule, but this solution constructs the list without using `DEPS`. So in this solution `DEPS` is not needed, doesn't get defined, expands to an empty list and does nothing (and I shouldn't have left it in, but I was trying to modify the rule as little as possible). – Beta Apr 26 '13 at 04:06
0

Traditional makes are rather limited and force you to do all that basic stuff yourself. If you rightly expect a build tool to find dependencies and know what to link, try makepp. You may not need a makefile at all, or just a minimal one like

CFLAGS = -O3
myprog:                # just a default target to know what to build

The linking part would require a little help on your side, in that it is based on source-header pairs. If myprog.cpp includes a.h and b.hpp it'll look if it can build a.o and/or b.o, and if so, will link them and recursively check what their sources include.

You will only need to learn more make syntax, if you have more complex requirements. But if you do, there is no limit. 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
0

Yes, the "MMD" flag will help you to generate ".d" file (dependency) files. If you include at end of your Makefile( -include *.d ) and then if you make any change in .h file, the respective .o file, will rebuild.

Take this as reference: https://github.com/saanvijay/makefile-skeleton

Vijaya Prakash
  • 111
  • 1
  • 5
0

There's a minor limitation to @Beta's answer which can be fixed pretty easily.

Say you have a file main.c which includes header.h. You build this, and your main.d file looks like this:

main.o: main.c header.h

Then you delete header.h and its corresponding include in main.c. The program is valid and should compile fine, but make fails due to the above rule, which has a dependency on a now-nonexistent file.

To fix this, you need main.o to depend on main.d, and a rule to create main.d.

main.d: main.c
    $(CC) -MM -o main.d main.c

include main.d

This splits the generation of the .d file into a separate step, and make is smart enough to know that since it includes main.d, it should be rebuilt before it is included. This would fix the above issue. More info in the docs.

One issue with this approach is that make will rebuild the .d file when it's not needed, e.g. when running make clean. In these cases, you can just disable the include like in this answer. I'm interested to know if there is a smarter way to do this.

The complete Makefile would look something like this:

main.d: main.c
    $(CC) -MM -o main.d main.c

main.o: main.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -o main.o main.c

main: main.o:
    $(CC) main.o -o main $(LDLIBS)

.PHONY: clean
clean:
    rm main.o main.d

ifneq ($(MAKECMDGOALS),clean)
include main.d
endif
Hugo Burd
  • 301
  • 1
  • 4
  • 12