1

In my project I have some header files which contain methods (e.g. for template classes). All these header files are included in a single file header.h, which is then included in every cpp file. This way, I have to change the code just in one place. There are also some .h files without a corresponding .cpp file.
Then I have this makefile:

# Makefile

.PHONY: run clean rebuild

CC     = g++
CFLAGS = -Wall -Ofast -std=c++0x -pthread
RM     = rm -f
EXEC   = main

SRC    = $(wildcard *.cpp)
OBJ    = $(SRC:.cpp=.o)

$(EXEC): $(OBJ)
    $(CC) $(CFLAGS) -o $@ $(OBJ)

%.o: %.cpp
    $(CC) $(CFLAGS) -c $^

run: $(EXEC)
    ./$(EXEC)

clean:
    $(RM) $(EXEC) *.o *.gch *~

rebuild: clean $(EXEC)

Everything works fine, except for one small but annoying detail: if I modify a cpp file, then I can do make and everything is updated correctly, but if I modify a header file then I have to remove everything and recompile from scratch (and this is the reason why I have that ugly rebuild target), otherwise the edit will have no effect.

Is there a way to make things better without restructuring the entire code?

EDIT

I tried with this makefile

.PHONY: run clean rebuild

CC     = g++
CFLAGS = -Wall -Ofast -std=c++0x -pthread
RM     = rm -f
EXEC   = main

SRC    = $(wildcard *.cpp)
OBJ    = $(SRC:.cpp=.o)

$(EXEC): $(OBJ)
    $(CC) $(CFLAGS) -o $@ $(OBJ)

%.o: %.cpp headers.h
    $(CC) $(CFLAGS) -c $<

run: $(EXEC)
    ./$(EXEC)

clean:
    $(RM) $(EXEC) *.o *.gch *.d *~

rebuild: clean $(EXEC)

but the result is not what I want: if I modify a single header file and the do make, it tells me that the target is up to date, while I would like it to be recompiled.

Community
  • 1
  • 1
minomic
  • 645
  • 1
  • 9
  • 22
  • Possible duplicate of [generate dependencies for a makefile for a project in C/C++](http://stackoverflow.com/questions/313778/generate-dependencies-for-a-makefile-for-a-project-in-c-c) – Michael Albers Feb 27 '16 at 22:18

2 Answers2

11

Suppose you have foo.cpp, which contains the line:

#include "bar.h"

Your generic rule:

%.o: %.cpp
    $(CC) $(CFLAGS) -c $^

will not rebuild foo.o when bar.h has been modified (and foo.o is called for). It would work if you had an additional rule for foo.o:

%.o: %.cpp
    $(CC) $(CFLAGS) -c $<  # note the change of automatic variable

foo.o: bar.h

Writing such rules by hand would be a pain, but g++ will do it for you:

%.o: %.cpp
    $(CC) $(CFLAGS) -c -MMD $<

This command will produce the file foo.d (as a side effect of building foo.o) which contains the line:

foo.o: bar.h

What good does it do you, having that line in a separate file? You can pull it into the makefile with a line (at the end of the makefile) like this:

-include *.d

(If this approach seems amazingly simple, that's because a lot of smart people put a lot of thought into it.)

Beta
  • 96,650
  • 16
  • 149
  • 150
1

Not a Makefile expert, have a look at this. There are multiple solutions using -MM, -MD and -MF gcc flag. The highest voted answer suggests the following:

depend: .depend

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

include .depend

As far as I understand that should generate the correct dependencies for you and it seems to be the correct way to go. However, I have never used it, I would have tried adding the header files in the dependencies (appending a new target for %.o):

%.o: %.cpp %.h header.h
    $(CC) $(CFLAGS) -c $<

Note that I have changed $^ to $< in order to get the first dependency only (which is the cpp) and I appended the header.h to force recompile when this changes. The last might not be required, depending on what you do in there, and it will result in inefficient compiles since changing it will recompile all of your .o files

Community
  • 1
  • 1
urban
  • 5,392
  • 3
  • 19
  • 45
  • Thanks for the idea but it does not seem to work: please see the edit in the OP – minomic Feb 28 '16 at 14:23
  • @minomic: Adding `%.h` in the rule should make it work... for simple cases but Beta's answer will work in cases where the implementation of the .h lies in multiple .cpp files and is simple and clean – urban Feb 29 '16 at 07:48