The developers of C quickly realized that determining the exact recompilation command sequence each time a recompilation is needed can quickly lead to a headache. And since they were lazy enough, they decided to let this work to the computer itself.
The result was a program called make
. It reads a file called makefile
, which mentions each file in the project and for each file it mentions the files it is created from and the commands that must be used to create the file. When the make
is invoked, it reads the makefile
and then tries to create the file mentioned at the top of the makefile
. Therefore the executable is mentioned as the first file in makefile
. However the make
program can build any other file - all that is needed to let it to do so is to state the wanted file as the argument of make
.
The makefile
for our small hello, world project looks like this:
hello: hello.o banner.o gcc -o hello hello.o banner.o hello.o: hello.c banner.h gcc -c hello.c banner.o: banner.c gcc -c banner.c
The lines that start at the left margin are the files that are made and the files they are made from (after the colon). The lines with the big space at their start contain the commands. One thing that is not easily visible here is that the big space in the lines with the commands must be created by a tab character (eight spaces are not enough).
When make
is invoked the first time, it recompiles all modules of the program and links them together into one executable. The commands invoked by make
are written on the console, so we can easily see what is done now:
$ make gcc -c hello.c gcc -c banner.c gcc -o hello hello.o banner.o $ hello ******************** ** Hello, world ! ** ******************** $ _
Later Jim changed the module banner.c
to use three stars at the ends of the banner instead of the two. When he invoked the make
utility to update the executable, it correctly realized that the hello.c
is not modified, so it didn't waste time recompiling it:
$ make gcc -c banner.c gcc -o hello hello.o banner.o $ hello ********************** *** Hello, world ! *** ********************** $ _
make
So far everything is wonderfull but problems don't let Jim wait for themselves for too long. The first problem showed up when Jim tried to compile the program under MS-DOS. He quickly discovered that the original makefile
does not work under MS-DOS, because it uses incorrect commands and filenames. A makefile
with commands and filenames correct for MS-DOS is shown below:
hello.exe: hello.obj banner.obj link *.obj,hello.exe hello.obj: hello.c banner.h cc hello.c banner.obj: banner.c cc banner.c
A worse problem appeared when Jim later created a module that contains a function which returns 1 at morning time and 0 at afternoon time. Now he want his "Hello world" program to say "Good morning, world" at morning time and "Good afternoon, world" at afternoon time. So he changes hello.c
to the following text:
#include "banner.h" #include "morning.h" int main(void) { char *Text; NewLine(); if (IsMorningTime()) { Text="Good morning, world !"; } else { Text="Good afternoon, world !"; } GenerateBanner(Text); NewLine(); return(0); }
The morning.h
is the header file of the new morning
module containing the function mentined above. The function is named IsMorningTime
and is used to select the correct message to be sent to the GenerateBanner
. He is wondering about the results so he tries to recompile:
$ make gcc -c hello.c gcc -o hello hello.o banner.o hello.o(.text+0x21): In function 'main': : undefined reference to 'IsMorningTime' collect2: ld returned 1 exit status make: *** [hello] Error 1
Ehm. Jim added the new module called morning
, which contains that IsMorningTime
function. Why the system suddenly complains about it? The reason is clear after looking at the second line of the output of the make
command. It is the failing command and it says that we want to link two modules together into an executable. But that is wrong. Jim needs the new morning
module to be linked into the result as well. So this probably is the reason of the following error message.
But how to make the thing to link the morning
module too? We need to update the makefile
to let make
know what to do with the new module in the project:
hello: hello.o banner.o morning.o gcc -o hello hello.o banner.o morning.o hello.o: hello.c banner.h gcc -c hello.c banner.o: banner.c gcc -c banner.c morning.o: morning.c gcc -c morning.c
And there we are. We (and Jim) are coming to a big hole in the current software development tool design that was never been completely closed. But that is the next part of our course.