19

I have written a Makefile to compile an openCV program on OSX (more general in Unix systems).

The code has a header named constants.hpp where some constants are defined.

I would like to make the Makefile recompile the program when this header file changes because the values of the constants in it change the program behavior.

My Makefile is the following

CPP = g++
CPPFLAGS = -std=c++11

all: main.o

main.o: main.cpp
    $(CPP) $^ $(CPPFLAGS) -o $@

Searching around I tried to define after CPPFLAGS the value:

DEPS = constants.hpp 

and then since main.o depends on it adding the dependency as follows:

main.o: main.cpp $(DEPS)
        $(CPP) $^ $(CPPFLAGS) -o $@

but the error I get is clang: error: cannot specify -o when generating multiple output files.

I tried also this answer and tried to use th e M MM flags but I am missing something.

How to make Makefile recompile when a header file is changed?

EDIT: Following the comments to DevSolar I had to modify completely the question and he asked also the source code. Since I found useless to copy all the source code here I simplified it with a simple hello world program.

The following is the main.cpp:

#include<iostream>
#include"constants.hpp"

int main()
{

  std::cout<<"Hello world, the value is: " <<  myValue <<"\n";
  return 0;
}

and the following the constants.hpp:

static const int myValue = 10;
roschach
  • 8,390
  • 14
  • 74
  • 124
  • 1
    "I am missing something" is not a good description of a problem. Perhaps write a [mcve] so we can tell you what exactly you are missing; the error message you post does not seem to line up with the Makefile fragments you provided. Also, [virtually everything I could tell you about Makefiles](https://wiki.osdev.org/Makefile), including on how to get proper header dependencies without adding a seperate build step (`make depend`)... – DevSolar Aug 27 '18 at 08:41
  • I did post the minimal complete and verifiable example and then described the changes I did in the question. – roschach Aug 27 '18 at 09:14
  • 1
    Your example is not minimal. That would require only one source file, one rule, and no mention of OpenCV. It is not complete; I would still have to write up the source and header file myself. It is thus not verifyable, as the problem you are seeing might be caused by something you haven't shown yet. Please *do* read the links provided. – DevSolar Aug 27 '18 at 09:20
  • I think you are exaggerating but I see your point I will modify it. I think though the downvote is unfair – roschach Aug 27 '18 at 09:24
  • I modified it providing a simplified source code and makefile. If you consider it compliant to the requirements you listed please remove the downvote. – roschach Aug 27 '18 at 10:12

3 Answers3

56

Preface

You are using $(CPP) and $(CPPFLAGS)... that's for the preprocessor. What you want to use is $(CXX) and $(CXXFLAGS), for the C++ compiler.

The following assumes GNU make and a GCC-compatible compiler (clang will do).

Step One

Use generic rules, not one per source file -- the latter will very quickly become unwieldly, and is very error-prone.

Either list your source files manually...

SOURCES := parking.cpp utils.cpp InputStateContext.cpp InputState.cpp InputStateA.cpp

...or have all source files listed automatically:

SOURCES := $(wildcard *.cpp)

You also need a list of the object files (one .o per .cpp):

OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))

Now provide a rule for the executable, depending on all the object files, with a command that links all those object files ($^) into that same executable ($@)...

parking: $(OBJECTS)
        $(CXX) $(CXXFLAGS) $^ -o $@

...and a generic rule on how to generate individual object files (%.o) from the corresponding source file (%.cpp):

%.o: %.cpp Makefile
        $(CXX) $(CXXFLAGS) $< -o $@

Making the object file depend on the Makefile as well ensures that changes in the Makefile, e.g. $(CXXFLAGS), trigger a recompilation as well. $< resolves to the first dependency (the source file).

We will extend this rule later.

Step Two

We will have a dependency file for each source file. (Bear with me here.) We can generate a list of those files the same as we did for object files...

DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))

...and include them into the Makefile:

-include $(DEPENDS)

The - there means that make will not complain if those files do not exist -- because they do not, at this point.

Step Three (Core of the answer to your question)

Have the compiler generate those dependency files for us -- because it knows best. For that, we extend our object file build rule:

%.o: %.cpp Makefile
        $(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@

The -MMD flag generates the dependency file (%.d), which will hold (in Makefile syntax) rules making the generated file (%.o in this case) depend on the source file and any non-system headers it includes. That means the object file gets recreated automatically whenever relevant sources are touched. If you want to also depend on system headers (i.e., checking them for updates on each compile), use -MD instead.

The -MP option adds empty dummy rules, which avoid errors should header files be removed from the filesystem.

At the first compile run, there is no dependency information -- but since the object files don't exist either, the compiler must run anyway. For every subsequent run, make will include the auto-generated dependency files, and "do the right thing".


All-In-One (with some more syntactic sugar added):

SOURCES := $(wildcard *.cpp)
OBJECTS := $(patsubst %.cpp,%.o,$(SOURCES))
DEPENDS := $(patsubst %.cpp,%.d,$(SOURCES))

# ADD MORE WARNINGS!
WARNING := -Wall -Wextra

# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean

# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: parking

clean:
        $(RM) $(OBJECTS) $(DEPENDS) parking

# Linking the executable from the object files
parking: $(OBJECTS)
        $(CXX) $(WARNING) $(CXXFLAGS) $^ -o $@

-include $(DEPENDS)

%.o: %.cpp Makefile
        $(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $@
Dylan Landry
  • 1,150
  • 11
  • 27
DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 2
    Thank you for your detailed well-explained answer. Assuming the order you posted the steps is going to be the same in the Makefile, one thing I do not get is why specifying the generic rule on how to turn the individual source file into an object file AFTER the rule for the executable? should not it be defined before so that it is already known when generating the executable? – roschach Aug 27 '18 at 10:32
  • 1
    Usually you do definitions first, rules last. The order in my answer was didactic, not syntactic. Note that `make` handles rules functionally, not procedurally, thus sequence in the Makefile does not matter. The only "special" rule is the first one, as it is the one executed by default. Usually you make this first rule the `all` rule, so "make" and "make all" are synonymous. – DevSolar Aug 27 '18 at 10:37
  • @FrancescoBoi: I added an all-in-one example Makefile, and fixed a "thinko" in there (making `parking` depend on the sources instead of the objects; that was not correct). – DevSolar Aug 27 '18 at 10:56
  • 1
    I had another problem with `Makefile`s and the explanation about dependency files explained everything. Thanks again – roschach Jan 12 '19 at 16:16
  • I tried this makefile, but somehow only one file has been recompiled if a header changes. My fix was to put parenthesis arround the included files: `-include ($(DEPENDS))` – Sewbacca Jan 24 '21 at 12:47
  • What does the word `Makefile` in the second last line do exactly? – spaL Jan 10 '22 at 12:17
  • @tiner92m3: From the body of the answer: "Making the object file depend on the Makefile as well ensures that changes in the Makefile, e.g. `$(CXXFLAGS)`, trigger a recompilation as well. `$<` resolves to the first dependency (the source file)." Basically, if you change the way object files are to be compiled. – DevSolar Jan 10 '22 at 12:53
  • @DevSolar I get it now. Thank you for the explanation! – spaL Jan 10 '22 at 12:59
3

If you only have one source code file entering the compilation which the object file depends on try

main.o: main.cpp $(DEPS)
      $(CPP) -c $< $(CPPFLAGS) -o $@

This will only work as long as you don't use multiple .cpp files entering the compilation.

$^ is an automatic variable which holds all the prerequisites of the current recipe separated by whitespaces whereas $< just holds the first prerequisite. This is why you can't use this solution for multiple .cpp files in the same compilation.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
weber
  • 91
  • 3
0

If you have multiple .cpp and .hpp files and want to recompile whenever one of them changes, the following should work in GNU make:

main: main.cpp foo.cpp constants.hpp bar.hpp
  $(LINK.cpp) $(filter-out %.hpp,$^) $(LDLIBS) -o $@

$(filter-out %.hpp,$^) removes the .hpp file names from the compiler call.

In GNU make, the variable $(LINK.cpp) expands to $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH).