add_em_up()
. If we change the code in math.c,
we need to recompile the object math.o and the executable
myprog in order for the bug to be fixed in our program. We
do not have to recompile mainfile.c to make
mainfile.o again, because mainfile.o only
contains references to the functions in
math.o, not the functions themselves. We only need to
relink the two objects into an executable after fixing
math.o in order to propagate the bug fix to
myprog.
Recall (from lesson 1) that myprog must be built from mainfile.o and math.o, that mainfile.o is built from mainfile.c, and that math.o is built from math.c. We say that myprog "depends" on mainfile.o and math.o, that mainfile.o "depends" on mainfile.c, and that math.o "depends" on math.c.
We can show this set of relationships in graph form:
---> mainfile.o ---> mainfile.c / myprog --- \ ---> math.o ---> math.cIn this graph, the arrows (Okay, so it isn't artwork. Tough.) show the dependencies between the files. Changes must be propagated against the direction of the arrows. Thus, we see that a change in mainfile.c will cause mainfile.o to be "out-of-date", which will in turn cause myprog to be out-of-date. We can also see that this change will not affect math.o or math.c. Similarly, a change in math.c will cause math.o and myprog to be out-of-date, but not affect mainfile.o or mainfile.c.
This shows that splitting the program into two files not only allows us to easily reuse the math object in other projects, but it saves us from a complete recompile of the entire project if only one function is changed.
Let's look at the part of the makefile for myprog above:
myprog: mainfile.o math.o
cc -o myprog mainfile.o math.o
This is called a rule. For the moment, we won't worry about
the rest of the makefile. The first part is the word myprog
followed by a colon. This defines the target. The target is
the file we want built in some manner (for our purposes, by compiling other
files). The rest of the rule describes the target's dependencies and the
commands for building the target from these dependencies.
After the colon, we see mainfile.o and math.o These are the files on which myprog depends. When make is told to build myprog it will check to see if these files are up to date (more on that later). If they are, and myprog is newer than these files, make will assume that myprog doesn't need to be rebuilt. Otherwise, it will make sure that each of these files is up-to-date by finding the rules which define their dependencies, etc.
Once all the dependencies have been brought up to date, make will execute
the command on the second line of the rule to update myprog
The second line must begin with a tab character (no spaces!), and contains a
command that could be typed at the shell prompt to make the target from the
dependencies. In this rule, the command is "cc -o myprog mainfile.o
math.o
". This is the command we saw above which links the object into
an executable file.
Suppose mainfile.o doesn't exist when we tell make to build myprog, then the target for mainfile.o is found, its dependencies are checked and rebuilt if necessary, and the commands to build mainfile.o are executed. To build mainfile.o we need to compile mainfile.c into an object:
mainfile.o: mainfile.c
cc -c -o mainfile.o mainfile.c
We see that this just encodes the dependency of mainfile.o
on mainfile.c, and that you would use the command
"cc -c -o mainfile.o mainfile.c
" to build
mainfile.o from mainfile.c.
Similarly, for math.o, we would have the rule:
math.o: math.c
cc -c -o math.o math.c
Putting these rules all together, we have the makefile:
myprog: mainfile.o math.o
cc -o myprog mainfile.o math.o
mainfile.o: mainfile.c
cc -c -o mainfile.o mainfile.c
math.o: math.c
cc -c -o math.o math.c
Let's look at the graph we made earlier showing the dependencies of the files:
---> mainfile.o ---> mainfile.c / myprog --- \ ---> math.o ---> math.cIf we type "
make myprog
" at the command prompt,
make will walk the graph we showed above to find all the
dependencies that have be changed, then walk back (against the arrows) updating
targets until it rebuilds myprog.