While working on a C++ project, I noticed that I was making changes to one of the header files linked in my main code, but the make utility was not registering it. I had to force it to compile differently given the changes using "make - B".
I want to know why this is the case; is it because of how my makefile is written, how my files depend on each other, both, or neither?
Here is my makefile:
CXXFLAGS = -Wall -Werror -std=c++11 -pedantic -Wvla -g
//CXXFLAGS = -std=c++11
all: main.o game.o zombie.o
g++ $(FLAGS) game.o main.o zombie.o -o main $(CXXFLAGS)
game: game.cpp
g++ $(FLAGS) -c game.cpp $(CXXFLAGS)
zombie: zombie.cpp
g++ $(FLAGS) -c zombie.cpp $(CXXFLAGS)
main: main.cpp
g++ $(FLAGS) -c main.cpp pairing_heap.h $(CXXFLAGS)
I made a change to pairing_heap.h
which is #included in my main file.
Why did make not notice that it should compile again? Because I feel like this is a conceptual misunderstanding, I felt that it was not necessary to include the changes I made or the output difference when I did "make - B". They were simple things like cout's and cerr's included in the new pairing_heap.h that were not being picked up until forced.
Let me know if I need to provide any more information.
Thank you.
Make doesn't really know anything about any particular programming language or tool, so it doesn't understand that C/C++ files depend on headers as well as source files. It just has rules of the form
target: dependencies
actions
All it knows from this is that the file target
depends on the files listed in dependencies
, and if any of those files are newer, the commands in actions
should be run to update target
. That's really it -- everything that make does comes from this simple idea of target files, dependencies, and actions.
Now there is more to it -- make has a bunch of built-in rules for common things you often want to do, as well as ways to specify 'pattern' rules -- rules where the target contains a wildcard, so can be used for many different targets that depend on other files with related names.
Now in your case, you have the rule:
all: main.o game.o zombie.o
g++ $(FLAGS) game.o main.o zombie.o -o main $(CXXFLAGS)
which says to remake the file all
, if its older than the files main.o
, game.o
or zombie.o
it should run the command. That's the first rule in the file, so it is what gets built by default when you type make
.
Now, you probably don't have a file called all
(if you did make
probably wouldn't do anything), but that's generally fine, as if it doesn't exist, its obviously not up to date, so the command needs to run.
When a command needs to run, it also checks any of the dependencies to see if they in turn have dependencies that are older (so need to be rebuilt). Since these files all end in .o
, they match a built-in rule that knows how to build them from a file with the same name, except ending with .cpp
, so its runs those actions if (and only if) the .cpp
file is newer.
Now, you say, "what about my other rules -- what do they do?" Well it turns out they don't do anything. They are rules to build files named game
, zombie
, and main
, and since you never ask to build those files and nothing else depends on them, they do nothing. You might as well delete them.
You also ask "How do I make it rebuild if the header file changes?" Well, if you add a rule with no actions (just target and dependencies) it will just add those dependencies to another rule (built-in in this case) that does have an action. So if you add a line like:
main.o: pairing_heap.h
(with no action), make
will add this dependency to the built-in rule that know how to build main.o
from main.cpp
and will run that rule (recompiling main.cpp
) if either main.cpp
or pairing_hep.h
is newer than main.o
-- which is exactly what you want.