next up previous contents
Next: Separate compile steps Up: Makefiles - The Basic Previous: Using several files   Contents

Separate compiles

A Makefile is a set of rules for building programs. The rules are interpreted by make. The basic idea is very simple. When ``programA depends on programB'' we write a rule that looks like:
programA: programB
then we follow it with a set of shell commands that will ``bring programA up to date''. Each rule and its associated group of commands is called a ``stanza''. The command line in the stanza MUST start with a TAB character. This is the most common mistake when writing Makefiles.

Lets put together a simple Makefile for this project. Make will execute the first stanza in a Makefile by default. By convention this has the name ``all''. So our Makefile looks like:

all: mainprog

mainprog: mainprog.o fun1.o fun2.o
	cc -o mainprog fun1.o fun2.o mainprog.o

mainprog.o: mainprog.c
	cc -c mainprog.c

fun1.o: fun1.c
	cc -c fun1.c

fun2.o: fun2.c
	cc -c fun2.c
The above logic reads:
to bring all up to date        => bring mainprog up to date
to bring mainprog up to date   => bring mainprog.o fun1.o fun2.o up to date
to bring mainprog.o up to date => compile mainprog.c
to bring fun1.o up to date     => compile fun1.c
to bring fun2.o up to date     => compile fun2.c
to bring mainprog up to date   => link fun1.o fun2.o mainprog.o
So we start out with this set of files:
bash-2.05b# ls -l
total 36
-rw-r--r--    1 root     root           61 Mar  9 06:07 fun1.c
-rw-r--r--    1 root     root           13 Mar  9 06:07 fun1.h
-rw-r--r--    1 root     root           61 Mar  9 06:08 fun2.c
-rw-r--r--    1 root     root           13 Mar  9 06:08 fun2.h
-rwxr-xr-x    1 root     root        11897 Mar  9 18:28 mainprog
-rw-r--r--    1 root     root          219 Mar  9 18:30 mainprog.c
-rw-r--r--    1 root     root          208 Mar  9 18:30 Makefile
and we type make. We can see the compile steps take place in the order given above.
bash-2.05b# make
cc -c mainprog.c
cc -c fun1.c
cc -c fun2.c
cc -o mainprog fun1.o fun2.o mainprog.o
and we can see all of the files that got created.
bash-2.05b# ls -l
total 48
-rw-r--r--    1 root     root           61 Mar  9 06:07 fun1.c
-rw-r--r--    1 root     root           13 Mar  9 06:07 fun1.h
-rw-r--r--    1 root     root          788 Mar  9 18:34 fun1.o
-rw-r--r--    1 root     root           61 Mar  9 06:08 fun2.c
-rw-r--r--    1 root     root           13 Mar  9 06:08 fun2.h
-rw-r--r--    1 root     root          788 Mar  9 18:34 fun2.o
-rwxr-xr-x    1 root     root        11905 Mar  9 18:34 mainprog
-rw-r--r--    1 root     root          219 Mar  9 18:30 mainprog.c
-rw-r--r--    1 root     root          988 Mar  9 18:34 mainprog.o
-rw-r--r--    1 root     root          208 Mar  9 18:30 Makefile
and we can see that mainprog works.
bash-2.05b# ./mainprog
I am the main program
I depend on fun1 and fun2
change 1 applied
fun1 called
fun2 called
bash-2.05b#
Suppose we change fun2.c to output ``fun2 invoked''. It will look like:
#include <stdio.h>

void fun2()
{ printf("fun2 invoked\n");
}
Changing the file means that the fun2.c file is newer than fun2.o. make will follow instructions and bring fun2.o up to date by compiling fun2.c. However, make now knows that mainprog depends on fun2.o so it will relink mainprog. Notice that it does not need to compile fun1.c or mainprog.c as these files have not changed. So we see:
ls -l
total 52
-rw-r--r--    1 root     root           61 Mar  9 06:07 fun1.c
-rw-r--r--    1 root     root           13 Mar  9 06:07 fun1.h
-rw-r--r--    1 root     root          788 Mar  9 18:38 fun1.o
-rw-r--r--    1 root     root           62 Mar  9 18:43 fun2.c
-rw-r--r--    1 root     root           61 Mar  9 06:08 fun2.c~
-rw-r--r--    1 root     root           13 Mar  9 06:08 fun2.h
-rw-r--r--    1 root     root          788 Mar  9 18:38 fun2.o
-rwxr-xr-x    1 root     root        11905 Mar  9 18:38 mainprog
-rw-r--r--    1 root     root          219 Mar  9 18:30 mainprog.c
-rw-r--r--    1 root     root          988 Mar  9 18:38 mainprog.o
-rw-r--r--    1 root     root          208 Mar  9 18:30 Makefile
bash-2.05b# make
cc -c fun2.c
cc -o mainprog fun1.o fun2.o mainprog.o
bash-2.05b# ./mainprog
I am the main program
I depend on fun1 and fun2
change 1 applied
fun1 called
fun2 invoked
bash-2.05b# ls -l
total 52
-rw-r--r--    1 root     root           61 Mar  9 06:07 fun1.c
-rw-r--r--    1 root     root           13 Mar  9 06:07 fun1.h
-rw-r--r--    1 root     root          788 Mar  9 18:38 fun1.o
-rw-r--r--    1 root     root           62 Mar  9 18:43 fun2.c
-rw-r--r--    1 root     root           61 Mar  9 06:08 fun2.c~
-rw-r--r--    1 root     root           13 Mar  9 06:08 fun2.h
-rw-r--r--    1 root     root          788 Mar  9 18:43 fun2.o
-rwxr-xr-x    1 root     root        11905 Mar  9 18:43 mainprog
-rw-r--r--    1 root     root          219 Mar  9 18:30 mainprog.c
-rw-r--r--    1 root     root          988 Mar  9 18:38 mainprog.o
-rw-r--r--    1 root     root          208 Mar  9 18:30 Makefile
If we were to try make again without changing anything we get:
bash-2.05b# make
make: Nothing to be done for `all'.

So the basic idea is that you can write rules that tell make exactly how to construct your program.


next up previous contents
Next: Separate compile steps Up: Makefiles - The Basic Previous: Using several files   Contents
root 2004-03-15